Wire nornir's MCP into Claude Code (idiot-proof)
nornir-mcp is an MCP server over stdio that exposes nornir's whole surface (56 tools — see mcp-tools.md) to any MCP client. Two ways to run it:
- Remote / relay (recommended for agents on another machine): set
NORNIR_SERVERand every tool relays to a runningnornir-serverover gRPC (bearer auth). No sources and no warehouse on the agent's machine — but note the relay client still opens one small local single-writer store (thefunnel_*idea-intake/planning redb), so only one relay client can run per store path. To run several agents at once, see mcp-second-agent-for-idiots.md and the design in mcp-relay-client.md. - Embedded (everything local): leave
NORNIR_SERVERunset; the same binary opens a local warehouse and answers directly.
Copy-paste the path that matches your setup.
1. Install (on the machine running Claude Code)
cargo install nornir # ships nornir-mcp by default (≥ 0.4.21), + nornir, nornir-server, nornir-ui
nornir-mcp lands in ~/.cargo/bin — make sure that's on PATH:
which nornir-mcp # → /home/you/.cargo/bin/nornir-mcp
On < 0.4.21 the MCP binary was gated behind a feature, so
cargo install nornirshipped it only with--features mcp(orcli); without itclaude mcp add … -- nornir-mcpreferenced a missing binary and the client just said "Failed to connect." Upgrade (cargo install nornir --force) so a plain install includes it.
Debugging a "Failed to connect"
Claude Code's stdio transport hides the real error — it only shows ✘ Failed to connect. Run the binary directly to see why:
NORNIR_SERVER=http://oden:7878 NORNIR_SERVER_TOKEN=<token> nornir-mcp # prints the real startup error to stderr
nornir-mcp --help # works without any config
Note: NORNIR_SERVER is a gRPC endpoint — don't curl it (you'll get a confusing HTTP/0.9 / reset that looks like the server is down; it isn't).
2a. Register it — REMOTE (relay to a nornir-server)
One MCP serves EVERY workspace. Just two env vars — point it at the server. Do not pin a workspace: workspaces_list shows all workspaces with their repos, and workspace_use <name> switches focus at runtime.
claude mcp add (CLI):
claude mcp add nornir \
--env NORNIR_SERVER=http://oden:7878 \
--env NORNIR_SERVER_TOKEN=<the shared token> \
-- nornir-mcp
…or .mcp.json in the project root:
{
"mcpServers": {
"nornir": {
"command": "nornir-mcp",
"env": {
"NORNIR_SERVER": "http://oden:7878",
"NORNIR_SERVER_TOKEN": "<the shared token>"
}
}
}
}
NORNIR_SERVER— the host (Tailscale MagicDNShttp://oden:7878, orhttp://100.115.167.95:7878). Required for relay mode.NORNIR_SERVER_TOKEN— the shared bearer. On the host:sudo grep NORNIR_SERVER_TOKEN /etc/nornir/nornir.env. Required.NORNIR_WORKSPACE— optional default focus only. Omit it and the MCP exposes every workspace; set it if you want one workspace selected at start. It is no longer a hard lock.
Working across all workspaces (the agent flow)
workspaces_list→ every workspace with its repos — the full workspace×repo surface in one call (e.g.knut: [knut, knut-pipelines, …],znippy: [znippy, zoomies, …]). No switching needed just to see it.workspace_use <name>→ focus a workspace; subsequentrepos_list/repo_overview/deps_of/search/ … target it. No restart.- Repeat 2 to hop workspaces — one MCP covers
knut,korp,znippy,skade,holger,njord, … without relaunching.
2b. Register it — EMBEDDED (local warehouse, no server)
No NORNIR_SERVER. Point it at a local nornir.toml so it can find the workspace + warehouse:
{
"mcpServers": {
"nornir": {
"command": "nornir-mcp",
"env": {
"NORNIR_CONFIG": "/abs/path/to/workspace_X/release/nornir.toml"
}
}
}
}
NORNIR_CONFIG— path to yournornir.toml(else nornir discovers one from the cwd). Embedded mode reads the home-derived warehouse at~/.nornir/workspaces/<name>/builds— populate it first with the usualnornir index build/nornir knowledge scan --persist/nornir introspect symbols --persiststeps.
3. Verify it works (do this once)
After registering, restart Claude Code so it picks up the MCP, then:
claude mcp list # nornir should appear, "connected"
Inside Claude Code, the tools show up as mcp__nornir__*. Sanity-check with two calls:
- List the surface — ask: "call the nornir MCP tool
repos_list". You should get back a JSON array of repo names (proves the server/warehouse is reachable and scoped to your workspace). - Call one real tool — ask: "use nornir
repo_overviewforholger" (or any repo from step 1). A non-empty JSON orientation block = working.
If repos_list is empty or errors:
- relay mode: check
NORNIR_SERVERreachability and the token; - embedded mode: check
NORNIR_CONFIGpoints at a realnornir.tomland the warehouse has been built.
4. Example tool calls
Just ask Claude Code in plain language; it picks the mcp__nornir__* tool:
- "use the nornir MCP:
knowledge_symbol_lookupin njord for 'handler'" - "what calls
extern_rapport_pdf? (knowledge_callers)" - "search the njord docs corpus for the booking flow" (
search) - "orient me in njord —
repo_overview" - "blast radius of changing codec-utils —
dependents_of, transitive" - "what must I re-validate? —
changed_since_last_release" - "submit an idea to the funnel, then
funnel_next"
Highlights of the 56 tools: repo_overview/deps_of/build_order (dependency Mímir), knowledge_{symbol_lookup,defined_in,callers,callees,call_path} (the syn graph), dwarf_* (binary symbols), search (BM25), release_gate_*, bench_history, docs_*, and the funnel_* planning DAG. Full table: mcp-tools.md.
Why this helps a small / on-prem model
In relay mode the server does the heavy lifting once (clone → syn scan → index → embed → Iceberg) on the host. A weak local model then asks precise questions over MCP and gets back exact symbols / call paths / ranked snippets — so it needs far less context window and zero local indexing/embedding compute. All reads hit the server's live warehouse, fed by the monitor poll loop (see running-as-a-server.md).
Verified 2026-06-09: a Claude Code-style client drove nornir-mcp → http://oden:7878, scoped to the njord workspace, and got real data back (knowledge_symbol_lookup, search). The full 56-tool surface is exercised on every build by cargo test --features mcp --test mcp_matrix (see mcp-tool-testing.md).