# MCP server

Use Formstep from Claude, ChatGPT, Cursor and other MCP clients. Connect with OAuth or an API token so AI agents can build forms, send requests and read the answers.

MCP is an open standard that lets AI tools call outside services. Formstep hosts an MCP server that any client with remote MCP support can connect to, such as Claude, ChatGPT and Cursor. To connect one step by step, see [Connect an AI agent](https://formstep.io/docs/guides/ai-agents/connect/).

## Connection

```text
URL:  https://api.formstep.io/api/mcp   (POST, streamable HTTP)
Auth: Bearer <token>
```

Two kinds of bearer token work:

- An [API token](https://formstep.io/docs/developers/api-tokens/) (`fs_...`), for your own scripts and headless agents.

- An OAuth access token (`fso_...`), issued by the [OAuth flow](#oauth). Most clients get one for you when you sign in.

Both reach exactly one workspace. A tool call that names another workspace, or a form in one, fails with `FORBIDDEN`. OAuth tokens also carry scopes: `mcp:read` reaches the tools that only read, and `mcp:write` reaches every tool. `tools/list` shows only the tools a token may call, and any other call answers `403` with `insufficient_scope`. API tokens have no scopes and reach every tool.

Tool calls share the limit of 120 a minute per token with the [REST API](https://formstep.io/docs/developers/rest-api/). Only `tools/call` counts; `initialize`, `tools/list`, `prompts/*` and `resources/*` are free. Over the limit, the call still returns HTTP 200, with a failed tool result carrying `RATE_LIMITED` and `retryAfterMs`. Poll on a timer, never in a loop.

## Tools

The server describes its own tools on `tools/list`, each with a full schema, and clients that load schemas on demand fetch one when a task needs it. The tools cover forms and the editor, themes, settings, share links, translations, folders, webhooks, analytics, submissions and requests. Longer guides, such as every question type or how logic rules work, are served as `skill://` resources and through the `load_skill` tool, so an agent reads them when it needs them.

## Requests

An agent sends a request the same way code does: `fields_list`, then `request_create`, with the same parameters as the REST API. [Create requests from code](https://formstep.io/docs/developers/requests-api/#agents) covers the parameters and what is different over MCP, and [Inline forms](https://formstep.io/docs/developers/inline-forms/) covers building the form in the same call.

### Callbacks or polling

With a `callbackUrl`, Formstep POSTs once when the request ends, signed with the workspace's request signing secret; see [Request callbacks](https://formstep.io/docs/developers/callbacks/). That secret is shown only on the **OAuth and API Keys** page, and never returned over MCP or the API. An agent that runs on its own, with nobody to set up a receiver, therefore cannot verify a callback. It should leave out `callbackUrl` and poll `request_get` every few minutes until `status` leaves `pending`, then read `answers` and `outcome`. `expiresAt` bounds how long that is worth doing.

## Tools that ask first

Every tool carries the MCP hints `readOnlyHint`, `destructiveHint` and `openWorldHint`. These are marked destructive, because undoing them takes another call or is not possible: `form_delete`, `form_unpublish`, `workspaceFolder_delete`, `editor_deleteElement`, `translationLanguage_delete` and `request_cancel`. So are the tools that send something outside the workspace, such as `request_create`, and the tools that replace a stored value, such as `form_publish`, `formTheme_set` and `editor_updateElement`. Most clients ask before running them, but the prompt is the client's choice, so check its approval settings if you need a hard stop.

## Limitations

A tool call cannot carry a file. Images are set by URL: covers, logos and image blocks take an `http(s)://` or `data:image` URL. A per-request document is the exception: `document_create` returns an upload URL that a client with HTTP access can `PUT` the file to, as in [Documents for one recipient](https://formstep.io/docs/developers/requests-api/#documents). To turn a PDF or a screenshot into a form, use the [built-in AI chat](https://formstep.io/docs/ai/using-ai/#files).

## Connecting with an API token

Most clients sign in with OAuth: add the URL with no header and follow [Connect an AI agent](https://formstep.io/docs/guides/ai-agents/connect/), which also has the setup for Cursor. A client that cannot open a browser, such as a script, a CI job or a headless agent, sends an [API token](https://formstep.io/docs/developers/api-tokens/) as a header instead. Claude Code, from the command line:

```bash
claude mcp add --transport http formstep https://api.formstep.io/api/mcp \
  --header "Authorization: Bearer fs_YOUR_TOKEN"
```

Or in a project's `.mcp.json`. Other clients take the same URL and header; see their documentation for where.

```json
{
  "mcpServers": {
    "formstep": {
      "type": "http",
      "url": "https://api.formstep.io/api/mcp",
      "headers": {
        "Authorization": "Bearer fs_YOUR_TOKEN"
      }
    }
  }
}
```

## Using OAuth instead of API tokens

An app that connects on behalf of a user should use OAuth instead of asking for a pasted token. Formstep is an OAuth 2.1 authorization server with mandatory PKCE (S256) and opaque tokens: no JWTs and no implicit grant. Claude, Claude Code and other clients discover it all from the MCP endpoint, so the URL with no header is enough: the 401 points at `/.well-known/oauth-protected-resource`, and the client takes it from there.

The flow, for a client you write yourself:

1. `GET /.well-known/oauth-protected-resource`, then `GET /.well-known/oauth-authorization-server` for the endpoint URLs, scopes and supported auth methods.

2. `POST /oauth/register` with your `redirect_uris` (dynamic client registration, no credentials needed). You get a `client_id`, plus a `client_secret` if you asked for anything other than `token_endpoint_auth_method: "none"`. Redirect URIs must be HTTPS, or HTTP on `localhost`. Registration is capped at 20 an hour per IP.

3. Send the user to `/oauth/authorize` with `response_type=code`, your `client_id`, the registered `redirect_uri`, `scope=mcp:read mcp:write offline_access`, `state`, and a `code_challenge` with `code_challenge_method=S256`. They sign in, pick one workspace, and authorize.

4. Exchange the code at `POST /oauth/token` with `grant_type=authorization_code` and your `code_verifier`, within 60 seconds. A code works once.

5. Call the MCP endpoint with `Authorization: Bearer fso_...`. Access tokens last 1 hour. Refresh tokens last 30 days and rotate on every use; reusing a spent refresh token revokes the whole chain, so always store the newest one.

`POST /oauth/revoke` (RFC 7009) revokes an access or refresh token.

### Connected apps

Every OAuth connection is listed under **Connected apps** on the **OAuth and API Keys** page, with when it was connected and last used. Connections are personal: only the user who authorized one sees it, and workspace admins cannot see or revoke another member's. Disconnecting revokes every token the app holds for that workspace at once. A user who leaves or is removed from the workspace loses all their connections to it.

[Connect an AI agent](https://formstep.io/docs/guides/ai-agents/connect/) — Set up Formstep in any MCP client.

[Create requests from code](https://formstep.io/docs/developers/requests-api/) — The request parameters an agent sends.

For what an agent can do with it, see [the MCP server overview](https://formstep.io/integrations/mcp/).
