Reference
Using Roam via MCP
How to call Roam from Claude Code, Cursor, Codex, Gemini CLI, Amp, VS Code, and any other Model Context Protocol client. Covers first-run setup, the cold-start envelope your agent will see on a fresh repo, the tools that work without an index, the canonical agent flow, slow-tool patterns, and the failure modes that have tripped up real users.
First-run setup
Client setup and protocol support are different. Run roam mcp --compat-profile all
to inspect the installed SDK's supported revisions. The tested stack supports the handshake
through 2025-11-25; the newer July 2026 lifecycle is not yet a supported integration.
See the protocol compatibility guide.
Install dependencies before launching stdio; keep installation output out of the protocol stream.
Install the MCP extra (Python 3.10+ required) and run
roam init in your project root before
the first MCP call. roam init builds
.roam/index.db by default — the local SQLite graph
used by indexed queries. Indexing time depends on the repository,
its history, and your machine. Refresh it with roam index
as code changes; later runs can reuse unchanged files.
pip install "roam-code[mcp]" # Python 3.10+; pulls fastmcp + tree-sitter
cd /path/to/repo
roam init # creates .roam/index.db + fitness rules; CI is opt-in
roam --json doctor # inspect environment and index readiness
roam mcp-setup claude-code # preview one supported client config
Review the generated configuration, then add --write
when you intend to install it. Restart the server in your client and
check its connected tool list. Use an absolute executable path if
the editor cannot find the same Roam installation as your terminal.
Why this is a manual step: indexing can take long enough to exceed an MCP call timeout, and forcing an automatic build on first use hides that cost from the agent. We surface the cost explicitly so the agent (or the human driving it) can budget for it. See the next section for what your agent receives when it skips this step.
The cold-start envelope
When an MCP tool that needs an index is called on a project where the configured index is not built, the call's cold-start guard does not build it. It returns a structured envelope the agent can read and act on:
{
"command": "roam_health",
"isError": true,
"status": "index_not_built",
"summary": {
"verdict": "Index not built. Run `roam init` in a terminal first, then retry MCP tools.",
"level": "blocker",
"partial_success": false
},
"next_command": "roam init",
"expected_duration_seconds": 60,
"retry_after_seconds": 60,
"agent_contract": {
"facts": [
"0 of 8 evidence questions answered without indexed symbols",
"1 prerequisite command unmet -- run roam init"
],
"next_commands": [
"roam init",
"# then retry the MCP tool that returned this envelope"
]
},
"_meta": {
"guard": "w296_cold_start",
"tool": "roam_health"
}
}
Wire your agent prompt to recognise status ==
"index_not_built" and either run roam init
itself (if the agent has shell access) or ask the human to.
The next_command field is copy-paste executable;
timing fields are estimates, not a completion signal. Wait for
indexing to finish successfully before retrying. This is an error
result even though partial_success is false: inspect
isError and status before the summary.
Server startup and an explicitly enabled watcher have separate
index-refresh behavior.
To bypass the guard for tests or scripts, set
ROAM_MCP_DISABLE_COLD_START_GUARD=1 in the server
environment. Production agent setups should leave it on.
Tools that don't need an index
An index exemption does not make a tool available in your preset.
For bootstrap and diagnostics, use roam init and
roam --json doctor in a terminal at the project root.
These metadata and delivery tools are available in the default
core preset without an index:
| Tool | Purpose |
|---|---|
roam_expand_toolset | Inspect preset contents (core / review / refactor / debug / architecture / compliance / compile-curated / full). Changing the active toolset requires a server restart. |
roam_fetch_handle | Fetch all or part of a large MCP payload by handle (byte slice, section pick, jq projection). |
Inspect roam mcp --list-tools-json for the installed
inventory and argument schemas. This describes that local process,
not the server already connected to your editor.
Typical agent flow
Start with a repository question, then inspect the relevant code.
These illustrative calls use tools and argument names in the
default core preset. Replace auth_login
with a symbol returned from your project; these are MCP calls,
not shell commands. The server must be rooted in that project.
roam_understand(root=".")
roam_search_symbol(query="auth_login", root=".")
roam_uses(symbol="auth_login", root=".")
roam_prepare_change(symbol="auth_login", root=".")
Read the returned locations and limitations before editing. Indexed references are not every possible runtime caller; suggested tests still need execution. After changes, refresh the index and run the project's tests and review checks. The Agent Contract explains how to choose those checks. Some MCP tools combine multiple CLI operations; a single tool call is not a promise of one underlying process.
Tools that take longer than expected
Separate computation time from response size. A handle makes a large result easier to retrieve; it does not make the analysis faster. Narrow scope only with arguments the connected tool's schema supports.
When a response contains is_handle: true, use its
handle to retrieve the stored result. For byte-slice
delivery, start at offset zero and follow next_offset
while has_more is true. A slice is not a complete JSON
document. Use the same project root as the original call.
roam_fetch_handle(handle="<returned handle>", root=".", offset=0, limit=20000)
Alternatively request a supported top-level section or
jq projection, not both. A projection answers only that
narrower question. Retrieve the required evidence before accepting a
verdict; a handle preview is not the full result.
CLI flags and MCP parameters are separate interfaces; check each tool's schema for supported arguments and defaults. Read evidence limits for deletion verdicts, test mapping, heuristic scores, and partial analyses.
Check whether missing detail is recoverable delivery or incomplete computation. Fetching a stored partial analysis does not complete it. If storage failed, inspect the operation's outcome before retrying: an operation with side effects may already have run. If that outcome remains unknown, report it and do not repeat the write merely because its response could not be stored.
Troubleshooting
Tool hangs or times out
Check that .roam/index.db exists in the working
directory the MCP server was launched from. If it does not,
the cold-start guard should have returned an
index_not_built envelope rather than hanging — if
you see a real hang, run roam doctor to confirm
the install, then roam init to build the index.
Cloud-sync filesystems (OneDrive, Dropbox, iCloud) sometimes
lock the SQLite file; see Troubleshooting #2.
A readable summary inside an error result
Check isError, status, and any
error_code before using the summary. Keep useful
diagnostics, but do not treat readable JSON or a reassuring verdict
as completed analysis when the surrounding result reports failure.
Resolve the named prerequisite or invocation problem first.
Empty result from roam_dead_code or roam_smells
A completed scan can find zero candidates within its stated scope.
Check what was scanned, index freshness, resolution, and any warnings,
failed checks, caps, or partial_success disclosure.
An empty list without evidence that the required scan completed is
unknown, not clearance. Keep valid positive findings
from a partial result as leads; investigate the missing scope separately.
Tool not found
First check the connected installation and preset; a stale connection
can differ from the configuration you just generated. The default is
core. Use roam_expand_toolset() to inspect
available presets, then inspect the relevant preset by name. Select
one that contains the needed tool; full is an option,
not a required repair for every missing-tool error. A preset change
requires a server restart.
Set the variable in the editor's MCP server configuration. For a manual
PowerShell launch, run $env:ROAM_MCP_PRESET = "full", then
roam mcp. Confirm the connection in the client's tool list;
local diagnostics inspect their own process, not the editor's connection.
Server returns stale data after a git pull
Run roam index and wait for the refresh to finish.
For optional reindexing on file changes, install watchdog
in the same Python environment as the MCP server; the
roam-code[mcp] extra does not include it. Set
ROAM_MCP_WATCH=1 in the server environment, restart,
and confirm file watcher started in its startup log.
If it does not start, keep refreshing with roam index.
The watcher can emit notifications/resources/updated
to supported clients. A notification is not proof that your next
result covers the intended revision; inspect index freshness after
the update.
MCP security stance: inside-server vs gateway
Roam's MCP server is the inside-server half of the agent's trust boundary. It runs locally as the same user as the editor, reads your code, and emits structured evidence on every sensitive call. It does not sit as a network gateway between agent and model; it does not proxy or rewrite model traffic; and it does not introspect prompts or responses on the wire. Roam applies producer-side secret-pattern redaction and exposes supported structural injection markers. Those bounded checks do not detect every secret or malicious instruction. A host or gateway can add semantic inspection, traffic policy, and tool-call controls.
What Roam does contribute to security is local, structural, and tamper-evident:
- Cold-start envelope (W296) — an agent on a
fresh repo gets
status: "index_not_built"instead of a hung tool call; the agent's next step is in the envelope, not in a stack trace. - Per-call decision receipt — the
McpDecisionReceiptdataclass records actor, tool id, sha256 of inputs, policy verdict (allow/deny/escalate/redact/not_evaluated/would_deny_dry_run), and a hash of outputs. Those receipt fields hold digests, not raw payloads. This is not a global storage promise: response handles and explicitly written reports can contain analysis data. A recorded actor label is not authenticated identity. - HMAC-chained run ledger — every
roam runs start/endwrites signed events under.roam/runs/;roam runs verifydetects tampering. - Proof-carrying PR bundle —
roam pr-bundle emitbinds preflight + impact + critique envelopes into a singleChangeEvidencepacket a reviewer (or CI) can validate before merge.
Read the inside-server vs gateway discussion for the longer framing of which class of defence Roam owns and which class belongs to the host.
Generate config: don't hand-edit
Every per-client config snippet on Integration Tutorials comes from one command:
roam mcp-setup claude-code # or: cursor, codex-cli, gemini-cli, vscode, windsurf
roam mcp-setup cursor --preset compliance # 14-tool AI-governance subset
roam mcp-setup vscode --write # write the file in place
roam --json mcp-setup vscode # structured envelope for scripting
The generator uses maintained client configuration templates and can add the selected preset to the server environment. It does not inspect your connected client or discover its active tools. Review the preview, preserve unrelated settings, then restart the connection after a change. Check the client's tool inventory against the intended installation and preset.
When to use MCP vs the CLI directly
| Surface | Use it when |
|---|---|
| MCP | An AI coding agent (Claude Code, Cursor, Codex, Gemini CLI, Amp, custom) is driving the workflow. The agent gets structured envelopes, schema-versioned output, and shared session memory across calls. |
| CLI | An agent has shell access, a person is exploring, or a CI pipeline or script is running checks. Use --json for machine-consumed results; selected commands also support SARIF. Inspect process exit and the command's result state. |
Both surfaces use Roam's analysis engine. MCP also has metadata, session, delivery, and compound tools; names, arguments, and defaults are not always identical to the CLI. Choose the supported interface for the task, not an assumed one-to-one mapping.
See it run
The worked change-review demo — local queries, patch review, a saved bundle, and run-ledger verification. Inspect missing checks along the way; setup time varies by project.
See also
- Command reference: Examples and command index — worked examples, global output options and the complete command index. For a command's own flags, run
roam <command> --help. - Agent contract: Agent Contract — the five discipline rules behind the canonical flow.
- MCP server card: mcp-server-card.json — machine-readable capability manifest (246 MCP tools, 8 presets, 10 resources, 5 prompts).
- Try your own history: the free local sample uses
HEAD~5..HEAD, not five identified PRs. For report options, see PR Replay.