Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/nornir

.nornir/mcp-tools.md

nornir MCP tools — authoritative reference

nornir-mcp is an MCP (Model Context Protocol) server over stdio that exposes nornir's whole API surface as tools. It is the same surface as the nornir CLI, presented for LLM agents (Claude Code/Desktop, Copilot CLI, …).

Total tools: 70. Every #[tool] in src/bin/nornir-mcp.rs is listed below, grouped by area, with its input args (name : type — ? = optional/defaulted) and output shape. This file is generated-by-hand from the source and kept in lock-step with the functional coverage test (tests/support/mcp_harness.rs, run via --test mcp_matrix): every tool here has a coverage row, and the test goes RED if a tool is added without one.

Modes (read first)

Every warehouse-touching tool has two code paths:

Some tools are server-only (no embedded path): workspace_register, sync_now, index_status. Offline they return a clear "needs NORNIR_SERVER" error.

Output shape notation: most tools return a single text content block holding pretty-printed JSON (the ok_json helper); a few return a plain-text table or an SVG string. "→ JSON {…}" / "→ JSON […]" below describes that payload.


repos / workspace (7)

Tool Purpose Input args Output
repos_list List repos declared in nornir.toml (or the active workspace's members in server mode). — → JSON ["holger", …]
workspaces_list List the workspaces this MCP can target + the active one (server mode). — → JSON {active, workspaces:[…]} (embedded: {active, note})
workspace_use Switch the active workspace for subsequent calls (server mode), no restart. Empty name clears the override. name : string → JSON {active}
workspace_register Server-only. Register a workspace so nornir tracks its git members + rebuilds the warehouse on change. name : string, descriptor : string, mode? : string (default monitored), poll? : string → JSON {registered, mode, members:[…]}
sync_now Server-only. Force an immediate git fetch + warehouse republish for a workspace (skip the poll loop). workspace? : string (empty = active) → JSON {workspace, fetched, changed, snapshot, errors}
index_status Server-only. Workspace freshness: current snapshot + each git member's last SHA, last-synced time, sync state. workspace? : string → JSON {workspace, current_snapshot, updated_at, members:[…]}
crate_published Is a crate published on crates.io? Queries the sparse index directly (no cargo/API key). name : string → JSON {name, published, max_version, versions_count, yanked_latest}

(workspaces_list, workspace_use, repos_list are the agent's orientation entry points; workspace_register/sync_now/index_status are the write/ freshness side, server-only.)

dependency Mímir (cross-repo graph) (10)

Tool Purpose Input args Output
deps_of Repos <repo> depends on. transitive=false: direct edges with the via crates; transitive=true: full forward closure. repo : string, transitive? : bool → JSON edges/closure
dependents_of Repos that depend ON <repo> — the BLAST RADIUS. Direct (via) or full reverse closure. repo : string, transitive? : bool → JSON edges/closure
affected_by_change Given changed repos, the invalidation set (changed + transitive dependents) in build order. repos : string[] → JSON build-ordered list
build_order Full workspace build order (deps before dependents). Errors on a cycle. — → JSON ordered repo list
dep_path Shortest dependency path from→to, annotated with via crates. Null if unreachable. from : string, to : string → JSON path
external_dep_users Workspace repos that consume external crate <crate> (e.g. "who uses serde?"). crate : string → JSON [repos]
dep_graph_svg Render the cross-repo graph as a static SVG flowchart (edges labelled with crates; no JS, no build step). — → SVG text
changed_since_last_release Diff each repo's HEAD vs last-released SHA, expand moved repos through the graph into the build-ordered re-run set. — → JSON change set
repo_overview One-shot orientation: <repo>'s deps + dependents (with via), build-order position, and a knowledge digest (symbol/call counts + sample names). repo : string → JSON overview
regression_trace Deterministic regression time-bisect: last GREEN release, first RED, suspect commit range, full timeline. repo : string, workspace? : string → JSON trace

guard (tamper evidence) (3)

Tool Purpose Input args Output
guard_status Report writable state of every [guard].forbidden path. — → text table (exists/writable/changed/path)
guard_apply chmod -w every forbidden path, record a tamper-evidence manifest (sha256 + mode), export guard-policy.json. — → text table
guard_verify Verify every forbidden path against the recorded manifest (per-path drift). Read-only. — → JSON {intact, recorded_at, paths:[…]}

Note: the unlock (chmod +w) tool guard_release is intentionally NOT exposed to agents (see the agent_tool_surface_excludes_unlock_* unit test).

bench / release gates (8)

Tool Purpose Input args Output
bench_history Read bench_history.jsonl for <repo> (one BenchRun per line). repo : string → JSON [BenchRun, …]
test_history <repo>'s recorded test-run history — one RunSummary per run, newest-first (the SAME per-run data nornir test history <repo> prints). Embedded (own warehouse) or via the server (Viz.TestResults) when NORNIR_SERVER is set. repo : string, limit? : usize → JSON [{run_id,repo,ts_micros,passed,failed,ignored,stalled,skipped,listed,total,green}, …]
release_gate_path_patches Gate: no [patch.crates-io] path patches in <repo>'s Cargo.toml. repo : string → "ok: …" / error
release_gate_nexus_floor Gate: holger_ops_sec ≥ nexus_ops_sec for the latest BenchRun. repo : string → "ok: …" / error
release_gate_no_regression Gate: latest BenchRun vs same-machine history; fail if a metric drops > max_regression_pct. repo : string → "ok: …" / error
release_gate_docs_fresh Gate: README.md generated sections in sync with the latest BenchRun. repo : string → "ok: …" / error
release_gate_all Run every gate enabled in [repo.<name>.gates] (incl. the heavy tests matrix gate when [gates].tests = true). repo : string → JSON {repo, passed:[…], failed:[{name,error}]}
release_doctor Advisory release doctor report across the whole constellation — dirty trees (real local git status), external-dependency version skew (target vs each repo with bump hints), path-override safety, promotability, blast radius. Read-only; the "see it + get hints first" tier before the gates. Embedded/local only (reads the local checkouts). forbid? : [string] (e.g. ["arrow=56"]), json? : bool → JSON / text doctor report

docs (7)

Tool Purpose Input args Output
docs_init Scaffold .nornir/ for <repo> (migrate existing README/CHANGELOG into it). repo : string → JSON {repo, nornir_dir/sources, …}
docs_render Render every managed doc from .nornir/ (full rewrite, chmod-aware). repo : string → JSON {repo, reports:[…]}
docs_check Dry-run: every artifact matches its .nornir/ source. repo : string → "ok: …" / drift error
docs_history List historized exports from the Iceberg doc_exports table (newest first). repo : string, doc? : string, version? : string, format? : string, limit? : usize → JSON {repo, rows:[{doc,version,format,path,exported_at,size_bytes}]}
docs_book Render the WHOLE doc set into one typst book → <repo>/docs/book.<ext>, historize in doc_exports. Needs docs-export feature. repo : string, format? : string (pdf|html|md) → JSON {repo, format, sources, bytes, out, sha256, git_sha, export_id}
docs_export Export the assembled README → <repo>/docs/README.<ext>, historize. Needs docs-export feature. repo : string, format? : string → JSON {repo, format, bytes, out, sha256, git_sha, export_id}
docs_install_hooks Install a tracked pre-commit hook for <repo> (.githooks/pre-commit + core.hooksPath) that re-renders managed markdown (markdown-only, never blocks) on every commit. Local-only; idempotent. repo : string → JSON install report

index / search (1)

Tool Purpose Input args Output
search Full-text BM25 search over indexed corpora (Tantivy). Run nornir index build first. query : string, corpus? : string (docs|code|bench_history|changelog|config), repo? : string, limit? : usize → JSON [{id,corpus,repo,path,score,snippet,title}]

introspect — DWARF over a live binary (5)

Tool Purpose Input args Output
symbol_lookup Extract every function symbol from a built binary, filter by name substring. binary : string, pattern : string, limit? : usize → JSON [{name,name_demangled,name_mangled,file,line,size_bytes,krate}]
defined_in Symbols defined in source files whose path ends with file. binary : string, file : string, limit? : usize → JSON [Symbol]
callers_of Inline-callgraph: functions that call name. (Inlined edges only.) binary : string, name : string → JSON [names]
callees_of Inline-callgraph: functions called by name. binary : string, name : string → JSON [names]
path_between Shortest inline-call chain from→to (BFS). Null if none. binary : string, from : string, to : string → JSON path / null

knowledge — persisted syn graph, no binary (5)

Reads the latest nornir knowledge scan --persist snapshot from Iceberg.

Tool Purpose Input args Output
knowledge_symbol_lookup Symbols in <repo> whose item name contains arg. repo : string, arg : string, limit? : usize → JSON [{crate_name,module_path,item_kind,item_name,visibility,file,line,doc_lines,signature}]
knowledge_defined_in Symbols defined in files whose path ends with arg. repo : string, arg : string, limit? : usize → JSON [Symbol]
knowledge_callers Call edges invoking name (bare or path-qualified last segment). repo : string, name : string, limit? : usize → JSON [{crate_name,caller_path,callee_ident,call_kind,file,line}]
knowledge_callees Call edges emitted from a caller whose path ends with name. repo : string, name : string, limit? : usize → JSON [Call]
knowledge_call_path Shortest call chain from→to (BFS, last-segment match). Array or null. repo : string, from : string, to : string → JSON path / null

DWARF — persisted warehouse facts, no binary (5)

Reads the historized dwarf_* tables (nornir introspect symbols --persist), with optional time-travel by git sha.

Tool Purpose Input args Output
dwarf_symbol_lookup Persisted function symbols for <repo> (or _workspace) whose demangled name contains arg. repo : string, arg : string, sha? : string, limit? : usize → JSON [Symbol]
dwarf_defined_in Persisted symbols defined in a file ending with arg. repo : string, arg : string, sha? : string, limit? : usize → JSON [Symbol]
dwarf_callers Persisted inline callers of arg. repo : string, arg : string, sha? : string → JSON [names]
dwarf_callees Persisted inline callees of arg. repo : string, arg : string, sha? : string → JSON [names]
dwarf_call_path Persisted shortest inline-call chain from→to. Null if none. repo : string, from : string, to : string, sha? : string → JSON path / null

funnel — ideas → plans → nodes (planning DAG) (7)

A persistent DAG that survives agent context loss. Call funnel_show + funnel_next after any restart to find what to work on.

Tool Purpose Input args Output
funnel_submit_idea Submit a new idea into the intake funnel. text : string, source? : string → idea id (i-NNN)
funnel_create_plan Create + auto-activate a plan refining an idea. idea_id : string, summary : string → plan id (p-NNN)
funnel_add_node Add a node to a plan (verb kind, optional needs deps). plan_id : string, kind : string, title? : string, prompt? : string, targets? : string[], needs? : string[] → node id (n-NNN)
funnel_link Add a dependency edge: to becomes ready only once from is done. plan_id : string, from : string, to : string → "ok …"
funnel_next Ready PlanNodes (deps satisfied) across active plans, in topo order. — → JSON [PlanNode]
funnel_status Flip a node's status (ready|active|blocked|done|abandoned). plan_id : string, node_id : string, status : string, why? : string → "ok …"
funnel_show Dump the whole funnel (ideas, plans, nodes, edges). — → text summary

vector — semantic code search (1)

Tool Purpose Input args Output
vector_search Semantic (jina-v2-base-code) vector search over a repo's materialized embeddings; time-travel by sha. Repo must be vectorized via nornir vector index <repo>. Needs embed-tract/embed-ort feature (or a server that has one). query : string, repo : string, sha? : string, limit? : usize → JSON {repo, hits:[{score,file,start_line,end_line}]}

completeness gate — autonom n-005 (2)

Tool Purpose Input args Output
test_coverage The autonom completeness gate (n-005): discover the testable surface (viz tabs × {thin,fat}, CLI subcommands, MCP tools, and unreached functions = symbol_facts − test-reachable(call_edges)), difference it against the covered set + .nornir/autonom-allow.toml, and report the gap. Reads the latest persisted gate run; computes one live if none. repo? : string (default = workspace name) → JSON {total, covered, allowlisted, gap, green, missing:[…]}
release_gate_coverage Release gate wrapping n-005 for <repo>'s workspace — fails (HARD zero) when the surface has any uncovered+un-allowlisted node OR any stale allowlist entry. Embedded/local only. repo : string → {ok} / error with the gap+stale list

architecture wiring — EPIC ARCH (3)

Reads the latest historized architecture_wiring graph (generate first with nornir arch generate <repo>).

Tool Purpose Input args Output
arch_svg The historized component/gRPC/core/table wiring graph for <repo> as a static skade circuit-board SVG (no JS, no build step) — the code-derived version of .nornir/architecture-wiring.md §2. repo : string → SVG text (or a hint if none historized)
arch_graph The same wiring graph as JSON — nodes are Component (viz pane) / gRPC verb / core fn / warehouse table; edges are the call/access facts. repo : string → JSON {nodes:[{id,label,kind}], edges:[{from,to,kind}]}
arch_trace The focused sub-board of everything reachable downstream from <entrypoint> (a UI pane like TestTab, a gRPC verb like Viz.Timeline, or a crate::module bucket; case-insensitive substring match). repo : string, entrypoint : string → JSON focused sub-graph

airgap — Skíðblaðnir (4)

Drives the sibling skidbladnir crate (../Skidbladnir, path dep). Zero network (the airgap law). CLI parity with nornir airgap ….

Tool Purpose Input args Output
airgap_pack Pack a staging tree into an airgap bundle (*.tar.zst) + write the sidecar version file. staging : string, out : string, version? : string (default today YYYYMMDD) → text ✓ packed N entries → out (root sha256 …)
airgap_verify Verify a received bundle against its sidecar manifest — recompute the manifest root hash AND every entry's content SHA-256 by extraction; refuse a tampered bundle. bundle : string, sha256? : string (out-of-band whole-file hash) → text verify report (manifest_root_ok/bundle_hash_ok/bad_entries)
airgap_unfold_plan The unfold provisioning PLAN for a target: kvm → qemu argv, terraform → nornir_component HCL, redfish → ComputerSystem.Reset body. Plan is real; provisioning is a feature-gated seam. backend : string (kvm|terraform|redfish), target : string, disk? : string (kvm) → text plan
airgap_events Read back the airgap_events bring-up DAG from the warehouse JSONL sink (one row per product×op×phase, with depends_on edges). — → JSON [AirgapEvent, …] (or a hint when none written)

viz — live Urðr Threads UI (2)

Talks to a running nornir viz over its control channel ($NORNIR_VIZ_CMD) — LAW #6 "see what the user sees as data".

Tool Purpose Input args Output
viz.state What is the viz showing RIGHT NOW? The full UI-state mirror: selected workspace + picker options, active tab + full tab list, and per-tab the rendered rows/nodes/cells. — → JSON UI-state mirror
viz.click Drive the viz: switch the active TAB / WORKSPACE / app-wide PALETTE, set a named form field, or click a named action; writes a one-shot command the running viz applies on its next frame. tab? : string, workspace? : string, palette? : string, set_field? : string, click_id? : string, wait_ms? : u64 (default 1200) → JSON state after apply

Count by area

Area Tools
repos / workspace 7
dependency Mímir 10
guard 3
bench / release gates 8
completeness gate (n-005) 2
docs 7
index / search 1
introspect (DWARF, live binary) 5
knowledge (syn graph) 5
DWARF (persisted) 5
funnel 7
vector 1
architecture wiring (EPIC ARCH) 3
airgap (Skíðblaðnir) 4
viz (live Urðr Threads UI) 2
Total 70

How this is verified

tests/support/mcp_harness.rs (the shared body of --test mcp_matrix and --test mcp_tools) enumerates the registered tool set from the live server's tools/list and exercises every tool with real arguments against a seeded warehouse, asserting structured output. The per-tool verdicts land in tests/mcp_tool_coverage.json. Current surface: 70 tools — the 3 server-only tools (workspace_register, sync_now, index_status) skip in the embedded harness; the rest are exercised and asserted.