<!-- Generated by crates/swarmops-cli/src/reference/mcp_page.rs from the code: do not edit. Change the code, then run SWARMOPS_REGEN_REFERENCE=1 with the regen_reference test. -->

# MCP tools

`swarmops mcp` serves the store's operations as an MCP server on stdin and stdout: JSON-RPC 2.0, one message per line. Each tool is one operation, named as the envelope's `op` is, and its result holds the envelope the CLI prints for the same request. These pages are generated from the server's own tool table, so they say what `tools/list` says. [MCP integration](../../develop/mcp.md) shows how to register the server and use it.

## Tools

In `tools/list`'s order.

| Tool | Title | CLI command | Changes the store | Needs an identity |
| --- | --- | --- | --- | --- |
| [`repo_info`](repo-info.md) | Describe the store | [`swarmops info`](../commands/info.md) | no | no |
| [`resolve_rev`](resolve-rev.md) | Resolve a revision | [`swarmops resolve`](../commands/resolve.md) | no | no |
| [`read_file`](read-file.md) | Read a file | [`swarmops cat`](../commands/cat.md) | no | no |
| [`read_tree`](read-tree.md) | List a directory | [`swarmops ls`](../commands/ls.md) | no | no |
| [`show`](show.md) | Show a changeset | [`swarmops show`](../commands/show.md) | no | no |
| [`log`](log.md) | List history | [`swarmops log`](../commands/log.md) | no | no |
| [`path_history`](path-history.md) | List a path's history | [`swarmops history`](../commands/history.md) | no | no |
| [`diff`](diff.md) | Diff two revisions | [`swarmops diff`](../commands/diff.md) | no | no |
| [`op_log`](op-log.md) | List operations | [`swarmops op log`](../commands/op-log.md) | no | no |
| [`ref_list`](ref-list.md) | List refs | [`swarmops ref list`](../commands/ref-list.md) | no | no |
| [`ref_set`](ref-set.md) | Move a ref | [`swarmops ref set`](../commands/ref-set.md) | moves refs | yes |
| [`ref_delete`](ref-delete.md) | Delete a ref | [`swarmops ref delete`](../commands/ref-delete.md) | moves refs | yes |
| [`undo`](undo.md) | Undo an operation | [`swarmops op undo`](../commands/op-undo.md) | moves refs | yes |
| [`commit`](commit.md) | Commit a changeset | [`swarmops commit`](../commands/commit.md) | adds to it | yes |
| [`land`](land.md) | Land a change | [`swarmops land`](../commands/land.md) | adds a changeset and moves the target | yes |
| [`blob_put`](blob-put.md) | Store a blob | [`swarmops blob put`](../commands/blob-put.md) | adds to it | yes |
| [`blob_has`](blob-has.md) | Find stored blobs | [`swarmops blob has`](../commands/blob-has.md) | no | no |
| [`verify`](verify.md) | Verify the store | [`swarmops verify`](../commands/verify.md) | no | no |

These commands have no tool: [`swarmops init`](../commands/init.md), [`swarmops whoami`](../commands/whoami.md), [`swarmops schema`](../commands/schema.md), [`swarmops git import`](../commands/git-import.md), [`swarmops git export`](../commands/git-export.md), [`swarmops mcp`](../commands/mcp.md), [`swarmops derive`](../commands/derive.md). An operator or a script runs them as commands; `derive` runs beside the store as maintenance, deriving values ahead of readers.

## Protocol versions

| Version | How a client opens it |
| --- | --- |
| 2026-07-28 | No handshake: each request names it in `params._meta` under `io.modelcontextprotocol/protocolVersion`, with the client's capabilities under `io.modelcontextprotocol/clientCapabilities`. |
| 2025-11-25 | `initialize`; also the version a client gets when it asks for one the handshake does not serve. |
| 2025-06-18 | `initialize`. |

The handshake revisions get the same tools and results. Revisions older than 2025-06-18 are not served. In 2026-07-28, a result has `resultType: "complete"` and the server's identity in `_meta`, and the results of `server/discover` and `tools/list` say a client may keep them for `ttlMs` 3600000 (an hour) with `cacheScope: "public"`: they change only with the binary. [MCP integration: Protocol versions](../../develop/mcp.md#protocol-versions) shows a session of each.

## Server instructions

`initialize` and `server/discover` return this text as `instructions`, for the client's model: 2005 characters on one line.

```text
SwarmOps is source control for coding-agent swarms: many agents commit to one store at once. Each tool is one store operation, and its result is the SwarmOps envelope {ok, op, api, result | error, meta}, as structuredContent and again as JSON text. A failed operation sets isError and gives error {code, message, retryable, exit, details, hint}: retryable says whether the operation can succeed when it is run again, as it is or after re-reading what the hint names, and a hint is often a swarmops command, whose operation is the tool of the same name (ref list is ref_list, cat read_file, ls read_tree, info repo_info). commit records a changeset; with advance it also moves that ref to it in the same transaction, if the ref still names parent: check result.advanced. ref_set and ref_delete change a ref by compare-and-swap, so their expected_old, like commit's parent with advance, is the full 64-hex changeset id the ref held when you read it (from ref_list, show, log or a commit's result). A ref name or a relative revision is read when the call runs instead of pinning the id you read: the ref's own name always matches, so the compare-and-swap protects nothing, and main~1 on ref main never matches; an id prefix stops resolving once another changeset shares it; the server refuses all three. To publish a changeset, land it: land merges it three-way onto main and moves main in one step, and on E_CONFLICT details.report says what to resolve. A read may show a commit that a failed sync then takes back; a mutation that names it fails under the lock instead of building on it. op_log lists the store's transactions, newest first; undo restores the refs one moved while they still hold what it set. Clients limit long tool results: ask for little, as each tool's description says. A {"file": path} content is read by this server, not by your client: give an absolute path (a relative one, or the server's own stdin or stdout, is refused). Every change is recorded for the agent the server runs as.
```

### Example: initialize

```json
{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "initialize",
  "params": {
    "capabilities": {},
    "clientInfo": {
      "name": "swarmops-tests",
      "version": "0"
    },
    "protocolVersion": "2025-11-25"
  }
}
```

```json
{
  "id": 1,
  "jsonrpc": "2.0",
  "result": {
    "capabilities": {
      "tools": {}
    },
    "instructions": "SwarmOps is source control for coding-agent swarms: many agents commit to one store at once. Each tool is one store operation, and its result is the SwarmOps envelope {ok, op, api, result | error, meta}, as structuredContent and again as JSON text. A failed operation sets isError and gives error {code, message, retryable, exit, details, hint}: retryable says whether the operation can succeed when it is run again, as it is or after re-reading what the hint names, and a hint is often a swarmops command, whose operation is the tool of the same name (ref list is ref_list, cat read_file, ls read_tree, info repo_info). commit records a changeset; with advance it also moves that ref to it in the same transaction, if the ref still names parent: check result.advanced. ref_set and ref_delete change a ref by compare-and-swap, so their expected_old, like commit's parent with advance, is the full 64-hex changeset id the ref held when you read it (from ref_list, show, log or a commit's result). A ref name or a relative revision is read when the call runs instead of pinning the id you read: the ref's own name always matches, so the compare-and-swap protects nothing, and main~1 on ref main never matches; an id prefix stops resolving once another changeset shares it; the server refuses all three. To publish a changeset, land it: land merges it three-way onto main and moves main in one step, and on E_CONFLICT details.report says what to resolve. A read may show a commit that a failed sync then takes back; a mutation that names it fails under the lock instead of building on it. op_log lists the store's transactions, newest first; undo restores the refs one moved while they still hold what it set. Clients limit long tool results: ask for little, as each tool's description says. A {\"file\": path} content is read by this server, not by your client: give an absolute path (a relative one, or the server's own stdin or stdout, is refused). Every change is recorded for the agent the server runs as.",
    "protocolVersion": "2025-11-25",
    "serverInfo": {
      "name": "swarmops",
      "title": "SwarmOps",
      "version": "[version]"
    }
  }
}
```

Recorded by the MCP tests. A name in square brackets, such as `[tmp]` or `[c1]`, stands for what differs from run to run: the test's temporary directory, an id, a time, the version.

## The store and the identity

Both are the server's, never a call's; no tool argument names either.

- The store is `--repo`, else `SWARMOPS_REPO`, opened anew for each call, so that a call sees what other processes committed. A store that is not there is each call's `E_NOT_A_REPO`, and the server serves on.
- The identity is `--as`, else `SWARMOPS_AGENT`, with `SWARMOPS_RUN_ID`, as for the CLI. Every change is recorded for it.
- These tools need it, and without one fail with `E_IDENTITY_REQUIRED`: `ref_set`, `ref_delete`, `undo`, `commit`, `land`, `blob_put`.
- These need none: `repo_info`, `resolve_rev`, `read_file`, `read_tree`, `show`, `log`, `path_history`, `diff`, `op_log`, `ref_list`, `blob_has`, `verify`.
- The output flags (`--json`, `--human`, `--pretty`) do not apply.

## Result size limits

A result holds its envelope twice, so the descriptions of the tools that read much ask the model for small reads and pages. In `tools/list`, `read_file` carries `_meta: {"anthropic/maxResultSizeChars": 200000}`: Claude Code keeps a result of up to that many characters in the conversation instead of saving it to a file. The other tools carry no `_meta`. [MCP integration: Result size limits](../../develop/mcp.md#result-size-limits) gives the sizes each tool asks for.

A message line longer than 64 MiB is an Invalid Request (`-32600`) without an `id`, read no further than one byte past the limit.

## Protocol errors

A message the server cannot serve gets a JSON-RPC error. An operation that fails is not one: its tool result has `isError: true` and the envelope's `error`, with an [error code](../errors.md).

| Code | Name |
| --- | --- |
| `-32700` | Parse error |
| `-32600` | Invalid Request |
| `-32601` | Method not found |
| `-32602` | Invalid params |
| `-32603` | Internal error |
| `-32022` | Unsupported protocol version |

[MCP integration: Protocol errors](../../develop/mcp.md#protocol-errors) shows when each is sent.

## See also

- [MCP integration](../../develop/mcp.md)
- [`swarmops mcp`](../commands/mcp.md)
- [CLI reference](../cli.md)
- [Error codes](../errors.md)
