Give agents the store#
swarmops mcp serves the store's operations to an agent as an MCP server on stdin and stdout.
This page registers it with Claude Code, lists what agents can call, and keeps a copy of every
answer for monitoring. Commands and outputs here follow the
conventions of the operations guide.
Before you start#
- A store (Stores), and an identity for each agent process (Identities).
- Claude Code (
claude) on the same host, running as the user who owns the store (permissions).
Register the server for one agent#
Register it with Claude Code for one agent, with its identity:
claude mcp add swarmops -e SWARMOPS_AGENT=agent/worker-1 -- swarmops mcp --repo ~/.local/state/swarmops/repos/acme
claude mcp listAdded stdio MCP server swarmops with command: swarmops mcp --repo … to local config
…
swarmops: swarmops mcp --repo … - ✔ Connected✔ Connected is the check. That registration is Claude Code's local scope: private to you, in
the directory you ran it in.
Register the server for a project#
For a project that several agent sessions open, one .mcp.json at its root registers the server
for every one of them, and each session gives its own identity in its own SWARMOPS_AGENT, which
Claude Code expands into the server's environment:
{
"mcpServers": {
"swarmops": {
"command": "swarmops",
"args": ["mcp", "--repo", "/home/me/.local/state/swarmops/repos/acme"],
"env": {"SWARMOPS_AGENT": "${SWARMOPS_AGENT:-}"}
}
}
}Claude Code asks once, in each project, to approve the servers a .mcp.json names; until then
claude mcp list shows the server as ⏸ Pending approval. The README's MCP
section says why the entry runs swarmops rather than so, and why the empty default (:-)
matters. Give the store's path absolute, as above.
The tools agents get#
The server lists 18 tools, one per operation, each taking the operation's request as its arguments and returning the envelope the CLI prints for it:
| Reads | Writes |
|---|---|
repo_info, resolve_rev, read_file, read_tree, show, log, path_history, diff, op_log, ref_list, blob_has, verify | commit, land, blob_put, ref_set, ref_delete, undo |
init, whoami, schema, git import, git export and derive are commands only: you run
them, not the agents.
- The store and the identity are the server's:
--repo(elseSWARMOPS_REPO) and--as(elseSWARMOPS_AGENT). No call can name others, and without an identity every write fails withE_IDENTITY_REQUIRED. - Content given as
{"file": <absolute path>}, incommit,blob_putorland'sresolutions, makes the server read that path itself, with the permissions of the user it runs as: an agent can store any file that user can read, also one that a sandbox of the agent's own file access keeps from it (SECURITY.md). - Claude Code starts one server for a session, and the session's subagents share it and its identity. An agent that needs an identity of its own runs as its own Claude Code process.
- The server opens the store for each call, so it sees what other agents commit meanwhile. It exits on any of the store's four documented aborts (storage spec §2; the README's MCP section lists them), such as a failed journal write whose cut-back fails too: the client sees the server exit, and has to start it again.
- The server tells the model how to use it, in its MCP
instructionsand its tools' descriptions: a full 64-hex changeset id wherever a compare-and-swap needs one,landto publish (onE_CONFLICT,details.reportsays what to resolve), anidempotency_keyto make a retry safe, and small pages (max_bytesof 32768 or less, alimitof 100 or less), since clients limit long tool results. Put the same in the project'sCLAUDE.mdif you want it in every prompt. - Agents work without a checkout: they read files through
read_fileandread_tree, and write whole files throughcommit. There are no workspaces yet (M5), so an agent that must build or test its change needs the files on disk some other way, such as a git worktree of the git side (Build and test a change).
Keep a copy of every envelope#
Every tool result is an envelope, and the server keeps none of them: swarmops mcp writes its
answers to the client and to nothing else, and op log lists the writes that succeeded, not the
calls that failed or how long they took. What monitoring reads is therefore
in the client's transcript of the session (Claude Code keeps one for each, as JSON lines under
~/.claude/projects/), or in a file that you have the server's answers copied to. This wrapper does
the second, one file per agent, named by its identity.
-
Write the wrapper:
cat > ~/.local/bin/swarmops-mcp-log <<'EOF' #!/bin/bash # `swarmops` with a copy of every answer the server writes, in one file per agent. dir=~/.local/state/swarmops/envelopes install -d -m 0700 "$dir" agent=${SWARMOPS_AGENT:-no-identity} exec swarmops "$@" > >(tee -a "$dir/${agent//\//_}.jsonl") EOF chmod +x ~/.local/bin/swarmops-mcp-log -
Register it. It takes the arguments of
swarmopsas they are, so a registration differs from the ones above in its command only:{ "mcpServers": { "swarmops": { "command": "/home/me/.local/bin/swarmops-mcp-log", "args": ["mcp", "--repo", "/home/me/.local/state/swarmops/repos/acme"], "env": {"SWARMOPS_AGENT": "${SWARMOPS_AGENT:-}"} } } }claude mcp addtakes it in the same place:claude mcp add swarmops -e SWARMOPS_AGENT=agent/worker-1 -- ~/.local/bin/swarmops-mcp-log mcp --repo ~/.local/state/swarmops/repos/acme claude mcp listAdded stdio MCP server swarmops with command: …/swarmops-mcp-log mcp --repo … to local config … swarmops: …/swarmops-mcp-log mcp --repo … - ✔ Connected
The wrapper execs the server, so the client talks to the server itself and sees how it ends as it
would without the wrapper, the SIGABRT of one of the store's aborts included. tee appends each
answer to the agent's file as the server writes it: agent/worker-1 writes
agent_worker-1.jsonl. A line is one JSON-RPC response. A tool call's holds the call's
envelope twice, as an object in structuredContent and as the text of the one content block, with
isError true when the envelope's ok is false; the answers to initialize and tools/list are
lines too, and hold no envelope. A failed land, cut down:
{"jsonrpc":"2.0","id":6,"result":{"content":[{"type":"text","text":"{\"ok\":false,\"op\":\"land\",\"api\":1,\"error\":{\"code\":\"E_CONFLICT\",…}"}],"structuredContent":{"ok":false,"op":"land","api":1,"error":{"code":"E_CONFLICT",…},…},"isError":true}}The files hold what the agents read and write, and a read_file line holds its page twice. They
grow for as long as the agents work and nothing prunes them: the wrapper makes their directory
0700, and old files are yours to move away between sessions.
Next: the daily loop, and what to read in these files.
Troubleshooting
This page goes from what you see to why it happens and what to run. It covers the installer, the MCP server, where a store may live, a busy store, a damaged…
Backup and restore
Copy a store that agents are writing, check the copy, and put it back after damage. Commands and outputs here follow the conventions of the operations guide.