# MCP tools

> The MCP server your users' agents connect to, how agents are authorised, and every tool they can call.

Your users' agents (Claude, Codex, or any client that speaks the Model Context Protocol) reach their documents through one MCP server per platform, run by Proof. Agents talk to Proof directly: your server approves each agent once, and never relays its edits or holds its tokens. For the approval step, see [Connect agents](/guides/connect-agents/).

## Your platform's server

```text
https://mcp.proof.exalto.ai/acme
```

The last part is your platform's slug, from the [console](https://developer.proof.exalto.ai/console). In test mode the address is `https://mcp.proof.exalto.ai/acme/test`, and connects agents to your test data. Show the address wherever your users connect agents; [`GET /v1/platform`](/reference/api/platform/) gives it for the key's mode as `mcp_url`. An agent's tokens work only on the platform that issued them, so someone who uses two Proof platforms connects their agent to each, and the agent keeps the two apart by server name (`acme`'s `read_document`, say, beside another platform's).

The server names itself to agents by your slug and platform name, with your icon if you set `icon_url` on the [platform](/reference/api/platform/). It speaks Streamable HTTP, statelessly, with JSON responses. It supports MCP protocol versions `2025-11-25`, `2025-06-18`, `2025-03-26` and `2024-11-05`, and answers a client asking for another with the newest. A request may batch up to 20 messages.

## How an agent is authorised

An agent needs nothing but the address. The rest follows the MCP authorization spec, with OAuth 2.1:

1. The agent calls the server without a token and gets `401` with a `WWW-Authenticate` header pointing at the protected resource metadata, `https://mcp.proof.exalto.ai/.well-known/oauth-protected-resource/acme`.
2. That names the authorization server, whose issuer is the same address as the MCP server. Its metadata is at `https://mcp.proof.exalto.ai/.well-known/oauth-authorization-server/acme`.
3. The agent identifies itself in one of two ways. Most use a client ID metadata document: its `client_id` is the https address of a JSON document describing it, which Proof fetches (from public addresses only). Others register with dynamic client registration and get a `client_id` back. Either way, the name the agent gives is the name people see, and the domain it comes from is shown beside it.
4. The agent opens the person's browser at the authorize endpoint, with PKCE (`S256`; plain is refused). Its redirect URI must be one it registered, or for one on a loopback address, the same on any port.
5. Proof has no sign-in of its own, so it sends the browser to your consent page with an [agent request](/reference/api/agent-requests/). You sign the person in, ask them, and approve or deny from your server.
6. Proof sends the browser back to the agent with an authorization code, and the agent exchanges it for tokens.

Access tokens last an hour, and work only at the address that issued them. Refresh tokens change each time they are used, and lapse after 90 days without use; one used twice ends all the agent's tokens, as someone else may hold a copy. Revoking the agent, through [`DELETE /v1/agents/:agent_id`](/reference/api/agents/) or by deleting its person, ends both at once.

## What an agent may do

An agent acts for one person, and can never do more than they can:

- With `access: "all"`, it reaches every document its person can open, editing at most.
- With `access: "chosen"`, it reaches only the documents its person, or your server, gave it a role in: `editor`, `suggester` or `viewer`.

What it may do in a document is the lower of that and its person's role there now, checked on every call. If Ada becomes a viewer of a document, Ada's agent can only read it from that moment. An agent never owns a document, though it can start one for its person with `create_document`.

A document the agent may not open answers as if it didn't exist: "You have no access to document doc_8Hq2Lm4R."

### Credit

Everything an agent writes, suggests or comments is credited to it, under the name its client registered and its person's current name: **Claude Code (Ada Lovelace's agent)**. Its words count as AI on the seal until a person shapes them. See [Provenance](/concepts/provenance/).

Writing tools take an optional `instruction`: what the person asked for, in their words where the agent has them. It is shown beside the text the agent wrote, labelled as reported by the agent.

### Suggest by default

The server's instructions tell agents to propose their changes, with `suggest: true`, unless their person asked them to edit the document directly. Each suggestion shows in the editor for people to accept or reject, and its optional `comment` starts the suggestion's discussion. Where the agent may only suggest, every edit is a suggestion whatever it passes.

## Tools

Every tool that works on one document takes its `document_id`. Every tool that writes to a document also takes these optional arguments:

| Argument | Type | What it does |
| --- | --- | --- |
| `instruction` | string | What the person asked for, shown beside the text written. |
| `suggest` | boolean | Propose the change instead of making it. |
| `comment` | string | With `suggest`, a note for whoever reviews the suggestion. |

Blocks are addressed by the ids `read_document` gives them, such as `1234:5`. Content goes in and comes out as GitHub-flavoured Markdown.

### Finding documents

| Tool | Arguments | What it does |
| --- | --- | --- |
| `list_documents` | `cursor` | The documents the agent may open, newest first, 100 at a time, with what it may do in each: its person's documents with `access: "all"`, or those it was given. Pass the `next_cursor` it returns for more. |
| `search_documents` | `query` | Blocks matching words across those documents, best first, at most 20, each with its `document_id`, block id and the text around the match. `"quotes"` match a phrase, `or` goes between alternatives, and `-word` excludes. |

### Managing documents

| Tool | Arguments | What it does |
| --- | --- | --- |
| `create_document` | `markdown`, `instruction` | Starts a document owned by the agent's person, with the agent as an editor. Its first line is its title. Returns its `document_id` and link. |
| `rename_document` | `document_id`, `name` | Names the document for everyone; an empty name calls it by its first line again. Needs edit access. |
| `list_trash` | none | The documents in its person's trash that the agent may restore. |
| `trash_document` | `document_id` | Moves a document to its person's trash: for everyone if they own it, from their own list if it was shared with them. Deleted for good after 30 days. |
| `restore_document` | `document_id` | Brings a document back from its person's trash, as it was. |

The three trash tools work only on documents the agent was given edit access to, or with `access: "all"`, and agents are told to use them only when their person asks. So are `rename_document` and `create_document`.

### Reading

| Tool | Arguments | What it does |
| --- | --- | --- |
| `read_document` | `document_id`, `from_block_id` | The document as Markdown, each block with its id, and its pending suggestions with theirs. About 40,000 characters at a time: each part says the `from_block_id` to continue from, and the first part has the outline. |

### Editing

| Tool | Arguments | What it does |
| --- | --- | --- |
| `replace_text` | `document_id`, `find`, `replace`, `block_id`, `all` | Replaces plain text inside blocks, keeping its formatting. Matches within one run of text. `block_id` limits it to one block; `all` replaces every match instead of the first. |
| `insert_markdown` | `document_id`, `after_block_id`, `markdown` | Inserts Markdown after a block, or at the top with `"start"`. |
| `replace_block` | `document_id`, `block_id`, `markdown` | Replaces one block with Markdown, which may be several blocks. |
| `delete_block` | `document_id`, `block_id` | Deletes one block, images included. |
| `append_markdown` | `document_id`, `markdown` | Adds Markdown at the end. |

All five also take `instruction`, `suggest` and `comment`, and answer with the blocks they changed.

### Suggestions

| Tool | Arguments | What it does |
| --- | --- | --- |
| `accept_suggestion` | `document_id`, `suggestion_id` | Makes a pending suggestion part of the document. Needs edit access. |
| `reject_suggestion` | `document_id`, `suggestion_id` | Rejects a pending suggestion. Needs edit access, except to withdraw the agent's own. |

### Comments

| Tool | Arguments | What it does |
| --- | --- | --- |
| `list_comments` | `document_id`, `include_resolved`, `from_thread_id` | The document's threads, oldest first: the block each is on, the text or suggestion it's about, and every message with its author. About 40,000 characters at a time. |
| `add_comment` | `document_id`, `block_id`, `quote`, `suggestion_id`, `comment` | Starts a thread on the first `quote` in a block, or on a suggestion with `suggestion_id`. A suggestion has one thread, so commenting on one that has it adds a reply. |
| `reply_to_comment` | `document_id`, `thread_id`, `comment` | Replies in a thread. Replying to a resolved thread reopens it. |
| `resolve_comment` | `document_id`, `thread_id`, `resolved` | Resolves a thread, or reopens it with `resolved: false`. |
| `edit_comment` | `document_id`, `thread_id`, `message_id`, `comment` | Rewrites one of the agent's own messages. |
| `delete_comment` | `document_id`, `thread_id`, `message_id` | Deletes one of the agent's own messages. Deleting a thread's first message deletes the thread, which it may do only while nobody else has replied. |

Agents may comment wherever they may suggest. To mention someone, which [notifies them through your webhook](/reference/webhooks/#mentioncreated), an agent writes `@[Grace Hopper](user:usr_9Tb3Wc1X)` with an id from `list_people`.

### People

| Tool | Arguments | What it does |
| --- | --- | --- |
| `list_people` | `document_id` | The people the agent may mention here: the document's members, and others who wrote in it or its comments and can still open it. Each comes with their Proof user id, their name, the `detail` you gave them (such as an email address), and how to write their mention. |

### Images

| Tool | Arguments | What it does |
| --- | --- | --- |
| `read_image` | `document_id`, `src` | Returns an image stored with the document, as `read_document` shows its address, for the agent to see. |
| `add_image` | `document_id`, `after_block_id`, `url` or `data`, `alt` | Adds a PNG, JPEG, GIF or WebP image after a block, from an https address or base64 data, stored with the document. `alt` describes it for people who can't see it. |

## Links in answers

Several tools answer with a link to the document, so the agent can hand it to its person. The link follows the **Document URL** pattern you set in the console or as `document_url` with [`PATCH /v1/platform`](/reference/api/platform/), such as `https://acme.com/docs/{document}`. Without one, answers give the document's id alone.

## Limits

| What | Limit |
| --- | --- |
| One part of `read_document` or `list_comments` | About 40,000 characters |
| `list_documents` | 100 documents a call |
| `search_documents` | 20 results |
| One image | 1,900,000 bytes |
| Images in one document | 100 MB, shared with people's uploads |
| Messages in one request | 20 |

Agents share the editor with people, and people come first. Their edits go ahead of agents' in every document, and each agent request gets a short slice of work at a time, so a burst from an agent never holds typing back by more than a moment.

## Your own tools

Proof's server has the tools for documents: their text, suggestions, comments, people and images. Folders, pins, workspaces and anything else your product keeps for itself aren't Proof's. To give agents those, [register tools of your own](/reference/api/platform/#set-your-agent-tools): the server lists them after its own, adds your instructions to its own, and forwards each call to your server. See [Add your own agent tools](/guides/your-own-agent-tools/).