> ## Documentation Index
> Fetch the complete documentation index at: https://docs.anyformat.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP server

> Connect an AI agent host to anyformat over the Model Context Protocol: endpoint, auth, client setup, and the tools available today.

anyformat runs a remote [Model Context Protocol](https://modelcontextprotocol.io) server. Any MCP host, such as Claude Code, Claude Desktop or Cursor, connects to it and calls anyformat as tools. The tools are the same v3 endpoints you call by hand, under the same API key, rate limits and error envelope.

## Endpoint

|           |                                                                                            |
| --------- | ------------------------------------------------------------------------------------------ |
| URL       | `https://api.anyformat.ai/mcp`                                                             |
| Transport | Streamable HTTP, stateless. Every request is independent; there are no sessions to resume. |
| Auth      | `Authorization: Bearer <your af_... key>`                                                  |

`/mcp` and `/mcp/` are the same endpoint. There is no stdio package; a host that only speaks stdio connects through `mcp-remote` (below).

## Auth

The server accepts the same `af_...` API key as the REST API, as a bearer token. A key that works on `/v3` works on `/mcp`. Mint one at [app.anyformat.ai/api-key](https://app.anyformat.ai/api-key).

A missing or unknown key returns `401` with the API's [error envelope](/api-reference-v3/introduction#errors) (`MISSING_API_KEY` or `INVALID_API_KEY`). Repeated invalid keys from one address are throttled and return `429` with `Retry-After`, as on the REST API.

There is no OAuth flow today.

## Connect

<Tabs>
  <Tab title="Claude Code">
    Add the server with the `claude mcp add` command. `--scope user` makes it available in every project; `--scope project` writes it to the project's `.mcp.json`.

    ```bash theme={null}
    claude mcp add --transport http anyformat https://api.anyformat.ai/mcp \
      --header "Authorization: Bearer $ANYFORMAT_API_KEY" --scope user
    ```

    Or write `.mcp.json` in the project root. Claude Code expands `${VAR}` from the environment.

    ```json theme={null}
    {
      "mcpServers": {
        "anyformat": {
          "type": "http",
          "url": "https://api.anyformat.ai/mcp",
          "headers": { "Authorization": "Bearer ${ANYFORMAT_API_KEY}" }
        }
      }
    }
    ```

    Check with `claude mcp list`, then ask Claude to list your workflows.
  </Tab>

  <Tab title="Cursor">
    Add the server to `~/.cursor/mcp.json` (all projects) or `.cursor/mcp.json` (one project). Cursor expands `${env:VAR}`.

    ```json theme={null}
    {
      "mcpServers": {
        "anyformat": {
          "url": "https://api.anyformat.ai/mcp",
          "headers": { "Authorization": "Bearer ${env:ANYFORMAT_API_KEY}" }
        }
      }
    }
    ```
  </Tab>

  <Tab title="Claude Desktop and stdio clients">
    A host that only launches local stdio servers connects through [`mcp-remote`](https://github.com/geelen/mcp-remote), which bridges stdio to the HTTP endpoint. Put the header value in an environment variable so the space in `Bearer ...` survives argument parsing.

    ```json theme={null}
    {
      "mcpServers": {
        "anyformat": {
          "command": "npx",
          "args": [
            "mcp-remote",
            "https://api.anyformat.ai/mcp",
            "--header",
            "Authorization:${AUTH_HEADER}"
          ],
          "env": { "AUTH_HEADER": "Bearer af_..." }
        }
      }
    }
    ```

    For Claude Desktop the file is `claude_desktop_config.json`, under Settings, Developer.
  </Tab>

  <Tab title="Any client">
    Send MCP JSON-RPC over HTTP `POST` to the endpoint with the bearer header. This `initialize` call shows the handshake:

    ```bash theme={null}
    curl -X POST https://api.anyformat.ai/mcp \
      -H "Authorization: Bearer $ANYFORMAT_API_KEY" \
      -H "Content-Type: application/json" \
      -H "Accept: application/json, text/event-stream" \
      -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"0"}}}'
    ```
  </Tab>
</Tabs>

## Tools

The server exposes these tools today. Each one calls the matching v3 endpoint under your key, so the endpoint page is the reference for its inputs, outputs and errors.

| Tool                             | What it does                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      | Endpoint                                                            |
| -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
| `list_workflows`                 | Lists your organization's workflows, newest first. Takes `query: { limit, cursor }`; `limit` is 1 to 100, default 20. Keyset-paginated: pass the response's `next_cursor` back as `cursor` until it is null.                                                                                                                                                                                                                                                                                                      | [List workflows](/api-reference-v3/workflows/list)                  |
| `get_workflow`                   | Returns a workflow with its complete typed graph inline: the latest version by default, or the one named by an optional `version` (a `version_id` from `list_workflow_versions`). Takes `workflow_id`. The `{ name, description, nodes, edges }` sub-shape is what `update_workflow` accepts.                                                                                                                                                                                                                     | [Get workflow](/api-reference-v3/workflows/get)                     |
| `list_workflow_versions`         | Lists a workflow's versions, newest first; item 0 of the first page is the version runs use. Takes `workflow_id` and `query: { limit, cursor }`. Keyset-paginated like `list_workflows`. Versions are read-only, for comparison and audit: read one with `get_workflow` and its `version`.                                                                                                                                                                                                                        | [List workflow versions](/api-reference-v3/workflows/versions)      |
| `create_workflow`                | Creates a workflow from an explicit typed graph. Takes `body: { name, description, nodes, edges }`; omit `persistent_id` on every field. An invalid topology is rejected with `TOPOLOGY_INVALID` and a `detail.violations[]` list naming the rules broken.                                                                                                                                                                                                                                                        | [Create workflow](/api-reference-v3/workflows/create)               |
| `update_workflow`                | Replaces a workflow's typed graph atomically. Takes `workflow_id` and `body`. Echo each existing field's `persistent_id` unchanged, including across renames; omit it only for new fields.                                                                                                                                                                                                                                                                                                                        | [Update workflow](/api-reference-v3/workflows/update)               |
| `delete_workflow`                | Deletes a workflow and all its document packets and runs. Takes `workflow_id`. Irreversible. Returns `{ "deleted": "<workflow_id>" }`.                                                                                                                                                                                                                                                                                                                                                                            | [Delete workflow](/api-reference-v3/workflows/delete)               |
| `upload_documents`               | Imports every URL into one document packet, without running it. Takes `workflow_id` and `body: { urls }`; each URL must be HTTPS. Each file is named by its response's `Content-Disposition`, else by the URL's path. The packet is registered only after every fetch succeeded.                                                                                                                                                                                                                                  | [Upload from URL](/api-reference-v3/workflows/upload-from-url)      |
| `run_document_packet`            | Runs, or re-runs, a packet on the latest version of its workflow. Takes `document_packet_id` and an optional `idempotency_key`; every call without a key starts a new billed run.                                                                                                                                                                                                                                                                                                                                 | [Run a document packet](/api-reference-v3/document-packets/run)     |
| `parse_document`                 | Parses one document fetched from an HTTPS URL with the fast lite parse. Takes `body: { url }`; the file is named by the response's `Content-Disposition`, else by the URL's path. Returns a run reference; the markdown is at `results.parse.markdown` once the run is `processed`.                                                                                                                                                                                                                               | [Parse from URL](/api-reference-v3/parse/parse-from-url)            |
| `get_run`                        | Returns one run with its results inline; `results` is null until `status` is `processed`. Takes `run_id` and an optional `wait_seconds` (0 to 60): the tool polls every 2 seconds until the run is `processed`, `error` or `cancelled`, or the budget runs out.                                                                                                                                                                                                                                                   | [Get run](/api-reference-v3/runs/get)                               |
| `list_workflow_runs`             | Lists a workflow's runs, newest first. Takes `workflow_id` and `query: { limit, cursor, document_packet_created_after, document_packet_created_before }`. Keyset-paginated like `list_workflows`.                                                                                                                                                                                                                                                                                                                 | [List runs](/api-reference-v3/runs/list)                            |
| `list_workflow_document_packets` | Lists a workflow's document packets, newest first. Takes `workflow_id` and `query: { limit, cursor }`. Keyset-paginated like `list_workflows`.                                                                                                                                                                                                                                                                                                                                                                    | [List document packets](/api-reference-v3/document-packets/list)    |
| `get_document_packet`            | Returns one packet: status, timestamps, its files and `latest_run_id`, which is null until the packet has been run. Takes `document_packet_id`.                                                                                                                                                                                                                                                                                                                                                                   | [Get document packet](/api-reference-v3/document-packets/get)       |
| `delete_document_packet`         | Deletes a packet and all its files. Takes `document_packet_id`. Irreversible. Returns `{ "deleted": "<document_packet_id>" }`.                                                                                                                                                                                                                                                                                                                                                                                    | [Delete document packet](/api-reference-v3/document-packets/delete) |
| `ask_knowledge`                  | Asks a question about the content of a workflow's documents and returns an answer with citations, each resolved to a page and a region of the source PDF. Takes `workflow_id` and `body: { question, thread_id }`; a `thread_id` you mint (prefix `kb-`) keeps follow-ups in context. The workflow needs a [Knowledge](/guides/nodes/knowledge) node (`KNOWLEDGE_NOT_ENABLED` otherwise); `KNOWLEDGE_NOT_READY` means the index is still building, so retry. Every question is billed and can take a few minutes. | [Ask the knowledge base](/api-reference-v3/knowledge/ask)           |

The graph a tool takes or returns is the one on the [Node schemas](/api-reference-v3/node-schemas) page. A host reads the full input schema from the server, so an agent can compose a valid graph without you pasting the schema into the conversation.

The document flow an agent follows is `upload_documents`, then `run_document_packet`, then `get_run` with `wait_seconds` set, so one call waits for the result instead of the agent polling. `parse_document` is the one-call shortcut when the agent only needs the markdown of a single document.

<Note>
  `delete_workflow` and `delete_document_packet` are irreversible. Their descriptions ask the agent to call `request_approval` with a one-line summary and to wait for your approval before deleting. That approval is a card the host shows you; a host that does not render it still sees the `destructiveHint` and can ask you its own way.
</Note>

### Tool annotations

Every tool declares the standard MCP annotations, so a host can decide when to ask you before calling it.

| Tool                             | `readOnlyHint` | `destructiveHint` | `idempotentHint` |
| -------------------------------- | -------------- | ----------------- | ---------------- |
| `list_workflows`                 | true           |                   | true             |
| `get_workflow`                   | true           |                   | true             |
| `list_workflow_versions`         | true           |                   | true             |
| `create_workflow`                | false          |                   | false            |
| `update_workflow`                | false          |                   | false            |
| `delete_workflow`                | false          | true              | true             |
| `upload_documents`               | false          |                   | false            |
| `run_document_packet`            | false          |                   | false            |
| `parse_document`                 | false          |                   | false            |
| `get_run`                        | true           |                   | true             |
| `list_workflow_runs`             | true           |                   | true             |
| `list_workflow_document_packets` | true           |                   | true             |
| `get_document_packet`            | true           |                   | true             |
| `delete_document_packet`         | false          | true              | true             |
| `ask_knowledge`                  | false          |                   | false            |

All tools set `openWorldHint: false`: they only reach anyformat.

## Authorization and limits

Authorization follows the API key. Whatever the key can do on `/v3`, it can do over `/mcp`, on the key's organization only. Each tool needs one of the key's scopes: the list and get tools need `read`, the tools that create, run, update or delete need `write`. A tool the key cannot call is left out of the server's tool list, and a direct call to it is answered as an unknown tool. Every tool call passes through the gateway's normal rate limiting, so the [rate limit tiers](/api-reference-v3/introduction#rate-limits) apply per tool call as they do per request.

## Errors

A failed tool call returns an MCP tool error whose message is the API's error envelope as JSON: `{ error, detail, error_code, retryable, request_id, status }`. Read `error_code` to branch, `status` for the equivalent HTTP status code, and quote `request_id` in a support request. A `TOPOLOGY_INVALID` error carries `detail.violations[]`, one entry per broken rule, with the node ids involved.

## Related

* [Coding assistant](/guides/coding-assistant): the `@anyformat/skill` package: the design know-how, also served by this server as `skill://anyformat/SKILL.md`.
* [Python SDK](/api-reference-v3/sdks/python) and [TypeScript SDK](/api-reference-v3/sdks/typescript): the same calls from code.
