Skip to content

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.

MCP setup itself (per-platform commands and config snippets) lives in Integration Tutorials. This page assumes the server is already wired up and focuses on what your agent should actually do with it.

## First-run setup

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` — the local SQLite graph Roam queries on every subsequent tool call. Initial indexing typically takes 30 to 120 seconds on a medium repo and is a one-time cost; later runs are incremental.

    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 workflow
    roam health                     # verify the index is healthy (0-100 score)
    roam mcp-setup                  # write the per-client MCP config snippet

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 `.roam/index.db` does not exist, Roam does not hang or auto-build. It returns a structured envelope the agent can read and act on:

    {
      "command": "roam_health",
      "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; the `retry_after_seconds` field is a hint for how long to wait before retrying the original tool call.

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

Nine MCP tools are exempt from the cold-start guard because they either create the index, diagnose the install, or operate on caller-supplied data:

Tool | Purpose
--- | ---
`roam_init` | Build the index. Run this first.
`roam_reindex` | Rebuild the index (incremental by default).
`roam_doctor` | Diagnose the install — Python, extras, grammars, schema version, stale index.
`roam_catalog` | Machine-readable list of every registered MCP tool plus capability flags.
`roam_expand_toolset` | Switch the active preset (core / review / refactor / debug / architecture / full).
`roam_session_metrics` | Per-session counters for the current MCP connection.
`roam_evidence_doctor` | Validate a `ChangeEvidence` packet passed in by the caller.
`roam_fetch_handle` | Fetch all or part of a large MCP payload by handle (byte slice, section pick, jq projection).
`roam_pr_comment_render` | Render a markdown PR comment from a `roam_pr_analyze` envelope.

Everything else is gated by the cold-start guard. Adding a new exemption is a deliberate source-code change pinned by a drift test.

## Typical agent flow

The canonical sequence for an agent given a free-form change request looks like this. Every call is a single MCP tool invocation; no shell-out, no subprocess fan-out.

    # 1. Verify the index exists (or create it).
    roam_doctor()
    roam_init()                                   # if cold-start envelope returned

    # 2. Orient before touching code.
    roam_health()                                 # 0-100 score + top issues
    roam_understand()                             # one-screen codebase briefing

    # 3. Find the relevant symbol or files for the task.
    roam_retrieve(task="where does login validate sessions", budget=4000)
    roam_context(symbol="auth_login")             # files + line ranges to read

    # 4. Gate before editing.
    roam_preflight(symbol="auth_login")           # blast radius + tests + fitness
    roam_impact(symbol="auth_login")              # what breaks if this changes

    # 5. Make the edit (out-of-band, in the editor / via the agent's edit tool).

    # 6. Verify the patch.
    roam_diff()                                   # blast radius of uncommitted changes
    roam_critique(diff_text="")     # clones-not-edited + blast radius

    # 7. Optional: package the proof.
    roam_pr_analyze(diff_text="")   # INTENTIONAL / SAFE / REVIEW / BLOCK

Steps 1 and 2 are once-per-session; steps 3 through 7 repeat per task. The Agent Contract documents the five discipline rules behind this sequence (context before edit, impact before delete, critique before merge, simulate before refactor, math before optimise).

## Tools that take longer than expected

A handful of tools produce envelopes large enough to push past a default MCP call budget. Reach for the handle pattern or a narrower scope when invoking these:

Tool | Why it's heavy | What to do
--- | --- | ---
`roam_capsule_export` | Exports the entire sanitised structural graph; can exceed 1M tokens on large repos. | Write to file via the CLI (`roam capsule --output capsule.json`) and reference the path.
`roam_orchestrate` / `roam_partition` | Multi-agent partitioning emits one entry per cluster; thousands of entries on large repos. | Bound output with `--agents N` (orchestrate) or `--n-agents N` (partition), or call `roam_fleet_plan` which emits a compact `.roam-fleet.json` instead.
`roam_fingerprint` | Per-symbol topology fingerprints across the whole graph. | Pass `--compact` for a single-line summary instead of the full per-symbol export.
`roam_verify_imports` | Cross-language import resolution over every file. | Scope to a single file with `--path`.
Any tool returning more than 20K tokens | The payload may be truncated by the client. | The tool returns a `handle` field; call `roam_fetch_handle(handle, section=...)` to page through the payload.

`roam_explore` is the recommended browse-style entry point because it auto-applies the handle pattern: large envelopes are split, you get a small summary plus a handle, and you fetch detail by section.

## 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.

### `USAGE_ERROR` on `roam_doctor`

Known issue: `roam_doctor` emits a non-zero exit even on advisory failures (missing optional extras), which the MCP wrapper currently surfaces as `USAGE_ERROR`. The underlying diagnostics are still present in the envelope. Read `summary.verdict` and `checks[]` rather than the top-level status.

### Empty result from `roam_dead_code` or `roam_smells`

Empty is a valid signal — the project may genuinely have no unreferenced exports or no flagged smells. Check the JSON envelope: `summary.verdict` will say "0 findings" (good) rather than failing silently. If you expected findings and got none, run the CLI equivalent with `--debug` to confirm detector coverage.

### Tool not found

The default preset is `core` (16 tools plus the `roam_expand_toolset` meta-tool). Tools outside that preset are loaded on demand: `roam_expand_toolset(preset="full")` exposes all 243 tools. You can also set `ROAM_MCP_PRESET=full` in the server env to start with the full set.

### Server returns stale data after a `git pull`

Run `roam reindex` (or set `ROAM_MCP_WATCH=1` in the server env to enable reactive incremental reindexing on file changes). The watcher emits `notifications/resources/updated` so subscribing clients see fresh data without polling.

## 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. Gateway-style defences (prompt-injection scanning, response redaction, tool-call interception) are a complementary layer owned by your MCP host, not by Roam.

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 `McpDecisionReceipt` dataclass records actor, tool id, sha256 of inputs, policy verdict (`allow` / `deny` / `escalate` / `redact` / `not_evaluated` / `would_deny_dry_run`), and a hash of outputs. Raw inputs and outputs are never stored — only their digests.
- HMAC-chained run ledger — every `roam runs start`/`end` writes signed events under `.roam/runs/`; `roam runs verify` detects tampering.
- Proof-carrying PR bundle — `roam pr-bundle emit` binds preflight + impact + critique envelopes into a single `ChangeEvidence` packet 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     # 13-tool AI-governance subset
    roam mcp-setup vscode --write                 # write the file in place
    roam --json mcp-setup vscode                  # structured envelope for scripting

Hand-rolled snippets drift the moment a preset changes. The generator reads the live tool registry, so the JSON it emits always matches what the server actually exposes. Treat anything copy-pasted from a blog post as illustrative; trust `mcp-setup` as the source of truth.

## 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 | A human is exploring interactively, or a CI pipeline / git hook / script is invoking Roam. CLI output supports `--json`, `--sarif`, and `VERDICT:`-first text; subprocess invocation is the right shape for non-agent automation.

Both surfaces share the same underlying engine — every MCP tool is a wrapper around a CLI command. Choose by the caller, not the capability.

## See it run

The 5-minute canonical demo — install → health → preflight → critique → signed `ChangeEvidence` packet, end to end. The agent flow above in one sitting.

## See also

- Full surface reference: Command Reference — every command, every flag, every JSON envelope.
- Agent contract: Agent Contract — the five discipline rules behind the canonical flow.
- MCP server card: mcp-server-card.json — machine-readable capability manifest (243 MCP tools, 7 presets, 10 resources, 5 prompts).
- Want a worked example on your own repo? Run a paid PR Replay — we replay your last 5 PRs through Roam, return a signed evidence packet plus a written analyst report, and your spend converts to Review credit if you continue with the hosted product.