Skip to content
nauro

Reference

MCP reference

Nauro exposes its decision and context store to agents over the Model Context Protocol. One shared tool registry (nauro_core.mcp_tools.ALL_TOOLS) holds 11 tools, 8 read and 3 write, consumed by two transports: a local stdio server and a hosted HTTP endpoint. Tool descriptions, titles, JSON input schemas, and behavioral annotations are centralized in mcp_tools.py so both transports stay in sync.

Transports: local stdio vs hosted endpoint

The local stdio server is run with nauro serve --stdio. Claude Code and other MCP clients spawn this process and talk over stdin and stdout. The --stdio flag is a hidden no-op kept for backward compatibility, since stdio is the only supported local transport (the former local FastAPI HTTP transport was retired).

There is no --project flag on the local server. It resolves the project from the cwd's .nauro/config.json.

On startup the stdio server pulls latest from the remote (best-effort) before accepting tool calls, then runs mcp.run(transport="stdio"). Pull failures are logged and the server starts with local state.

The server is a FastMCP("nauro", instructions=MCP_INSTRUCTIONS, log_level="WARNING") instance. Read tools that have a renderer in nauro_core.renderers.RENDERERS return a CallToolResult with a single TextContent block carrying the renderer output. Write tools, get_raw_file, and diff_since_last_session keep a single-block shape.

The hosted endpoint is https://mcp.nauro.ai/mcp. Add it as an MCP connector in your tool's settings to reach a cloud-synced project from surfaces without a local copy (for example claude.ai web) or from another machine.

The hosted path requires nauro auth login, then a one-time nauro link --cloud to promote the local project, then nauro sync. The hosted server implementation lives in a private repository but consumes the same ALL_TOOLS registry and operations kernel.

The local FastMCP server and the remote HTTP server read tool metadata from the same nauro_core.mcp_tools registry. The local server derives input schemas from Python type hints and consumes title, description, and annotations; the remote (JSON-RPC) server consumes the whole ToolSpec entry directly.

sh
# Local stdio server (spawned by the MCP client; runnable directly)
$ nauro serve --stdio

Source: packages/nauro/src/nauro/cli/commands/serve.py; packages/nauro/src/nauro/mcp/stdio_server.py; packages/nauro/README.md; README.md.

Read/write annotation model

Every tool is closed-world (openWorldHint: False). It operates only on the local or remote Nauro store.

Writes are non-destructive (destructiveHint: False). The source comment states writes are additive and nothing is ever deleted.

Read tools carry _READ_ANNOTATIONS = {readOnlyHint: True, openWorldHint: False} plus idempotentHint: True. Write tools carry _WRITE_ANNOTATIONS = {readOnlyHint: False, destructiveHint: False, openWorldHint: False} plus idempotentHint: False.

python
_READ_ANNOTATIONS  = {"readOnlyHint": True,  "openWorldHint": False}
_WRITE_ANNOTATIONS = {"readOnlyHint": False, "destructiveHint": False, "openWorldHint": False}

Source: packages/nauro-core/src/nauro_core/mcp_tools.py.

Connector config (mcp.json)

nauro adopt (or nauro setup claude-code) writes the entry into the repo's project-scope .mcp.json under mcpServers["nauro"]. The entry shape is {"command": "nauro", "args": ["serve", "--stdio"]}, with the command resolved via shutil.which("nauro"), falling back to the literal "nauro".

Cursor uses the same shape in <repo>/.cursor/mcp.json. Codex uses ~/.codex/config.toml.

The local stdio connector below applies to both Claude Code (.mcp.json) and Cursor (.cursor/mcp.json).

json
{
  "mcpServers": {
    "nauro": {
      "command": "nauro",
      "args": ["serve", "--stdio"]
    }
  }
}

The hosted remote connector is registered under a name distinct from the local nauro stdio server. The Codex example below is from the README.

sh
$ codex mcp add nauro-cloud --url https://mcp.nauro.ai/mcp
toml
# pin the OAuth callback port in ~/.codex/config.toml (Codex 0.131.0+)
mcp_oauth_callback_port = 8765

Source: packages/nauro/src/nauro/cli/commands/setup.py; README.md.

Tool reference (11 tools)

Each entry below gives the tool name, READ or WRITE kind, a one-line purpose, input parameters (type, required or optional plus default), and return shape. Schemas are from mcp_tools.py (input_schema); return shapes from the kernel *Result Pydantic models.

Every tool except list_projects accepts an optional project_id (string), used by the remote surface to disambiguate when a user has multiple projects; local installs auto-resolve from cwd. list_projects takes an empty object schema.

The local stdio surface also accepts an undocumented internal cwd (string) parameter for store resolution.

Tool Kind Purpose
get_contextreadReturn project context at the requested detail level.
get_raw_filereadReturn the raw markdown of any store file.
list_decisionsreadBrowse the full decision history.
get_decisionreadReturn a specific decision by number.
diff_since_last_sessionreadShow what changed since the last snapshot.
search_decisionsreadSearch decisions by BM25 relevance.
check_decisionreadCheck overlap with existing decisions without writing.
propose_decisionwriteRecord an architectural decision.
flag_questionwriteFlag or resolve an open question.
update_statewriteUpdate current state with a progress delta.
list_projectsread, remote-onlyReturn the projects this user can access.

get_context (READ)

Returns project context at the requested detail level (L0 concise, L1 working set, L2 full dump).

Inputs:

  • level (string enum L0|L1|L2, optional, default L0). Detail level. The kernel also accepts int 0|1|2.
  • project_id (string, optional).

Returns GetContextResult: content (markdown payload string) on success, or error (kind="rejected", invalid level) otherwise. L0 appends a *Last synced: ...* trailer when present; L2 appends a ## Snapshot Diff (...) block; empty or no-decision stores get a NO_CONTEXT_YET body. The envelope adds store and project identity.

get_raw_file (READ)

Returns the raw markdown of any file in the project store (a low-level escape hatch).

Inputs:

  • path (string, required). Path relative to store root, e.g. project.md, decisions/001-initial-architecture.md.
  • project_id (string, optional).

Returns GetRawFileResult: content (file text) on success, or error (kind="error") on a miss. The adapter rejects path traversal with Invalid path: <path>, and on a miss adds an available_files list (capped at 20, excludes snapshots/).

list_decisions (READ)

Browse the full decision history (beyond the last 10 in get_context, or with the include-superseded filter).

Inputs:

  • limit (integer, optional, default 20). Max decisions returned.
  • include_superseded (boolean, optional, default false).
  • project_id (string, optional).

Returns ListDecisionsResult: decisions, a list of DecisionSummary rows (number, title, date?, status, type?, confidence), sorted by number descending and truncated to limit.

get_decision (READ)

Returns a specific decision by its number, as a header triage projection or the full body.

Inputs:

  • number (integer, required). Decision number, e.g. 23.
  • mode (string enum header|full, optional, default full). header is frontmatter plus title plus short lede; full is the complete decision markdown.
  • project_id (string, optional).

Returns GetDecisionResult: content (decision markdown body) on success, or error (kind="error") on a miss.

diff_since_last_session (READ)

Shows what changed in the project context since the last snapshot, or since N days ago.

Inputs:

  • days (integer, optional). Look back N days; finds the nearest snapshot to N days ago and diffs against the latest. Omit to diff the two most recent snapshots (session-scoped).
  • project_id (string, optional).

Returns DiffSinceLastSessionResult: diff (human-readable diff body) and optional cutoff_date_used (echoes the baseline timestamp for time-based lookups). Sentinel diff strings cover "not enough snapshots (need at least 2)" and "one snapshot covers the requested range" rather than erroring.

search_decisions (READ)

Searches all decisions by BM25 relevance over titles and rationale.

Inputs:

  • query (string, required, non-empty). Search text.
  • limit (integer, optional, default 10). Max results.
  • include_superseded (boolean, optional, default false).
  • project_id (string, optional).

Returns SearchDecisionsResult: results, a list of SearchHit rows (number, title, date?, status, relevance_snippet?, score), sorted by BM25 score descending and truncated to limit; error (kind="rejected") on an empty or whitespace query.

check_decision (READ)

Checks whether a proposed approach overlaps existing decisions without writing anything; returns related decisions and a deterministic assessment.

Inputs:

  • proposed_approach (string, required). The approach you are considering.
  • context (string, optional). Extra context on why.
  • project_id (string, optional).

Returns CheckDecisionResult: related_decisions, a list of RelatedDecision (id, title, score, status, date, rationale_preview) via Tier 1 plus Tier 2 BM25 retrieval; and assessment (a deterministic summary string).

The tool does not judge conflicts. The agent reads each related decision via get_decision before proposing.

propose_decision (WRITE)

Records an architectural decision; commits on Tier 1 structural validation (single-call), with Tier 2 BM25 similarity advisory (non-blocking).

Inputs:

  • title (string, required).
  • rationale (string, required). Why, including constraints and tradeoffs.
  • operation (string enum add|update|supersede, optional, default add).
  • affected_decision_id (string, optional). Required when operation is update or supersede (e.g. decision-042).
  • rejected (array of {alternative, reason} objects, optional). Alternatives considered.
  • confidence (string enum high|medium|low, optional, default effectively medium for add/supersede).
  • decision_type (string enum architecture|library_choice|pattern|refactor|api_design|infrastructure|data_model, optional).
  • reversibility (string enum easy|moderate|hard, optional).
  • files_affected (array of strings, optional). Repo-relative paths.
  • resolves_questions (array of strings, optional). Open-question ids to mark resolved.
  • project_id (string, optional).

Returns ProposeDecisionResult: status (confirmed|rejected), tier (int), operation (add|update|supersede|reject), similar_decisions (advisory RelatedDecision hits), assessment, decision_id (on-disk file stem on confirm), touched_decisions (files rewritten), resolved_questions (ids moved under ## Resolved), and optional error.

On confirm the adapter captures a snapshot, regenerates AGENTS.md, and pushes to cloud.

flag_question (WRITE)

Flags an unresolved question for human review, or resolves existing questions against a decision (writes open-questions.md). Pass exactly one of question or resolved_by.

Inputs:

  • question (string, optional). The question to flag.
  • context (string, optional). Why it matters.
  • targets (array of strings, optional). Question ids; on flag, duplicate candidates that short-circuit if already resolved; on resolve, the entries to stamp (every id must exist).
  • resolved_by (string, optional). Decision id that resolves targets; when set, the call resolves instead of appending.
  • project_id (string, optional).

Returns FlagQuestionResult: status (ok|rejected), num (minted id on the ok-flag path; unset when rejected), and error. On flag, the adapter may add a BM25 similarity hint pointing to an addressing decision (the question is still logged). On success it captures a snapshot and pushes.

The local stdio surface does not surface the structured envelope; it returns a short string ("Question flagged." / "Question(s) resolved." / a hint plus "The question has still been logged." / a rejection reason).

update_state (WRITE)

Updates the project's current state with a progress delta and triggers a snapshot.

Inputs:

  • delta (string, required). What changed, e.g. "Deployed v0.2.0 to staging".
  • project_id (string, optional).

Returns UpdateStateResult: status (ok wrote a new state body; noop means no existing state file to update), optional warning (keyword-overlap caution; the update is still applied), and optional error. On a non-noop the adapter captures a snapshot and pushes.

The local stdio surface returns a short string ("State updated." optionally with the warning appended).

list_projects (READ, remote-only)

Returns the projects this user has access to (the discovery entry point for picking a project_id).

Inputs: none (empty object schema).

Returns the projects accessible to the current user. It is not registered on the local stdio server, because local installs auto-resolve to the single project store, so the discovery tool is unnecessary; only the remote or hosted surface registers it. The return-shape detail is not defined in nauro_core.operations (it is handled by the private hosted server).

Source: packages/nauro-core/src/nauro_core/mcp_tools.py; packages/nauro/src/nauro/mcp/tools.py; packages/nauro-core/src/nauro_core/operations/results.py; packages/nauro/src/nauro/mcp/stdio_server.py.

Example tool calls (MCP JSON-RPC arguments)

The arguments below are passed in MCP tools/call requests, one example per common workflow.

json
// get_context at session start
{ "name": "get_context", "arguments": { "level": "L0" } }

// search the decision log
{ "name": "search_decisions", "arguments": { "query": "authentication", "limit": 10 } }

// check before adopting an approach (read-only, no write)
{ "name": "check_decision",
  "arguments": { "proposed_approach": "Use Redis as the hot-read cache" } }

// record a decision (write)
{ "name": "propose_decision",
  "arguments": {
    "title": "Adopt Redis for hot-read cache",
    "rationale": "In-memory cache for hot read paths; lower p99 than DB round-trips.",
    "rejected": [{ "alternative": "Memcached", "reason": "Less feature-rich" }],
    "files_affected": ["src/cache.py", "src/api.py"],
    "confidence": "medium",
    "decision_type": "infrastructure"
  } }

Source: packages/nauro-core/src/nauro_core/mcp_tools.py (input schemas); README.md (CLI mirror of propose-decision).

Key facts

  • One shared registry nauro_core.mcp_tools.ALL_TOOLS holds 11 tools: 8 read, 3 write. Order: get_context, get_raw_file, list_decisions, get_decision, diff_since_last_session, search_decisions, check_decision, propose_decision, flag_question, update_state, list_projects.
  • Read tools (8): get_context, get_raw_file, list_decisions, get_decision, diff_since_last_session, search_decisions, check_decision, list_projects. Write tools (3): propose_decision, flag_question, update_state.
  • The local stdio server registers 10 (7 read, 3 write); list_projects is remote-only, since local installs auto-resolve the single project store.
  • Local transport: nauro serve --stdio runs nauro.mcp.stdio_server.run_stdio(), a FastMCP("nauro") server over stdin and stdout. --stdio is a hidden no-op kept for back-compat; stdio is the only local transport.
  • Hosted endpoint: https://mcp.nauro.ai/mcp (private repo); requires nauro auth login plus nauro link --cloud plus nauro sync. Enter the URL with no trailing slash.
  • All tools are openWorldHint: False (closed-world); writes are destructiveHint: False (additive, nothing deleted). Reads add readOnlyHint: True plus idempotentHint: True; writes add readOnlyHint: False plus idempotentHint: False.
  • .mcp.json connector entry shape (written by nauro adopt / nauro setup claude-code): mcpServers.nauro = {"command": "nauro", "args": ["serve", "--stdio"]}. Cursor uses .cursor/mcp.json with the same shape; Codex uses ~/.codex/config.toml.
  • Every tool except list_projects accepts optional project_id (string); list_projects takes an empty object schema. propose_decision requires affected_decision_id when operation is update or supersede; flag_question takes exactly one of question or resolved_by.
  • Return shapes are typed Pydantic *Result models in nauro_core.operations.results; each adds store (and the local surface adds project identity) at serialization time.

Open gaps

The exact return shape and fields of list_projects are not defined in the public nauro_core (the discovery tool is implemented only by the private hosted server). Its inputs (none) and purpose are documented above; the response schema is unconfirmable from the public repo.

The internal local-only cwd parameter present on the stdio tool signatures is not part of the published input_schema in mcp_tools.py; it is treated as an implementation detail.

The hosted HTTP server's JSON-RPC framing, auth flow internals, and envelope format live in a private repository and could not be read; only the public registry and operations behavior are documented here as ground truth.

The README states the hosted server is "8 read" overall (counting list_projects); the local-server docstring counts "10, 7 read, 3 write". Both are consistent (list_projects is the eighth read, remote-only); there is no conflict, noted here for clarity.