Model Context Protocol

once mcp runs a Model Context Protocol server over standard input and output. A coding agent can inspect the typed build graph, query project memory, and optionally run graph capabilities through the same JavaScript Object Notation (JSON) shapes emitted by once query and the command-line execution commands.

This page covers transport, handshake, error model, an example session, and Claude Desktop configuration. The Tools page documents each tool's input schema and return shape.

Transport#

The server exchanges newline-delimited JSON over standard input and output. Each request is one line in and each response is one line out, following JSON Remote Procedure Call (JSON-RPC) 2.0. Notifications, which have no id, get no reply.

Spawn the server with the workspace as its working directory, or pass an explicit --workspace <DIR>:

bash
once -C ~/code/MyApp mcp once mcp --workspace ~/code/MyApp

Protocol Handshake#

Once prefers protocol version 2025-11-25 and negotiates supported client versions back through 2024-11-05. The expected sequence:

  1. Client → initialize request with its protocol version, capabilities, and client info.
  2. Server → initialize result with the negotiated protocol version, the tools capability, server info, the configured workspace root, and cross-tool workflow instructions.
  3. Client → notifications/initialized (no reply).
  4. Client → tools/list to discover tools, then tools/call for each invocation.
json
{ "jsonrpc": "2.0", "id": 0, "method": "initialize", "params": { "protocolVersion": "2025-11-25", "capabilities": {}, "clientInfo": { "name": "claude-desktop", "version": "1.0" } } }

Server reply:

json
{ "jsonrpc": "2.0", "id": 0, "result": { "protocolVersion": "2025-11-25", "capabilities": { "tools": {} }, "serverInfo": { "name": "once-mcp", "version": "0.0.0" }, "instructions": "Once is a self-describing build graph…" } }

Error model#

SurfaceWhere it lands
Parse errorJSON-RPC error, code -32700, id null
Unknown methodJSON-RPC error, code -32601
Malformed tools/call paramsJSON-RPC error, code -32602
Unknown toolTool result with isError: true
Missing argumentTool result with isError: true
No matching target or schemaTool result with isError: true

Tool-level failures stay inside the JSON-RPC result envelope so the agent surfaces the message instead of treating the channel as broken.

Verification Reports#

With execution enabled, once_build_target and once_exec_script accept the optional boolean verify_reproducible, defaulting to false. When true, they return a once.verification.v1 report instead of their normal execution record. The corresponding commands are once build --verify-reproducible <target> and once exec --verify-reproducible --script -- <runtime> <script>.

once_query_verification accepts an id containing the verification UUID and returns the retained report without running commands. It is available without --allow-run, matching once query verification <ID> --format json. A failed check is inspectable as a report with success: false; failure to find or read the report is a tool-level error. Successfully reading a report does not mean the check passed.

FieldMeaning
schemaonce.verification.v1.
id, subjectVerification UUID and the command or target checked.
successBoth trials succeeded, and either declared artifacts match or, when no artifacts are declared, captured logs match. This is the check's pass/fail decision.
execution_succeededBoth trials returned successful results without execution or artifact-retention errors. Identical failures cannot pass.
artifacts_matchArtifact equality, or null when execution failed, no artifacts were declared, or the detail limit prevents distinguishing artifact drift from log drift.
logs_matchEquality of captured standard output, standard error, and retained declared action logs, or null when complete comparison is unavailable. Log drift is advisory when declared artifacts match.
reproducibleStricter comparison: successful execution with no artifact, exit-code, or captured-log differences. It can be false while success is true for log-only drift. It is not a proof claim.
trials, resultsTrial count and each trial's action digest, result, and error.
differencesResult-level differences tagged by kind: exit_code, stdout, stderr, or output. Output records identify the declared path and both digests, with null for an absent value.
artifact_differencesBounded file-level details with a path, difference kind, a log flag for declared action logs, and, when available, the first differing byte offset and text excerpts from both trials.
differences_truncatedWhether the file-level inventory or difference listing reached its limit. Full retained artifacts remain available for inspection.
trial_directoriesWorkspace-relative paths to retained trial results, decoded declared artifacts, captured logs, and trial-local Once caches.
scope, limitationsWhat was repeated and which sources of variation or external state were not isolated.
inspect_commandCommand for reading the same retained report again.

Both trials start from the same whole-workspace snapshot at the same private path, using separate, initially empty local Once caches. Script dependencies and fingerprints run in each trial. Declared trial outputs do not replace outputs in the original workspace. Reports and artifacts remain local under .once/verifications/<ID>/; they are not automatically published as project evidence. Retained files and excerpts may contain sensitive data.

The comparison covers the selected command or target's declared result, not artifacts and logs produced only by prerequisites.

This is a repeated-trial observation, not proof of reproducibility. Host toolchains, host tool caches, absolute paths, network services, and external side effects are not isolated. Clocks, randomness, and scheduling are not perturbed or controlled. Authorize repeated execution before starting a check. See script verification and build verification for the workflow and snapshot limitations. The tool catalog provides the exact tool schemas.

Example session#

A complete client/server exchange:

plaintext
→ { "jsonrpc": "2.0", "id": 0, "method": "initialize", "params": { … } } ← { "jsonrpc": "2.0", "id": 0, "result": { … "capabilities": { "tools": {} } … } } → { "jsonrpc": "2.0", "method": "notifications/initialized" } → { "jsonrpc": "2.0", "id": 1, "method": "tools/list" } ← { "jsonrpc": "2.0", "id": 1, "result": { "tools": [ … ] } } → { "jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": { "name": "once_query_workspace", "arguments": {} } } ← { "jsonrpc": "2.0", "id": 2, "result": { "content": [ { "type": "text", "text": "{ … workspace state … }" } ], "structuredContent": { "result": { … workspace state … } } } }

Every advertised tool includes behavioral annotations, a strict root input schema, and an output schema. Text content remains available for older clients; newer clients can consume structuredContent directly.

When editing and execution are enabled, once_materialize_example can create a complete starter without returning every file through the model context. It is idempotent for identical files and rejects the complete operation before writing when any destination conflicts.

Some hosts probe optional resource, resource-template, or prompt catalogs even when a server does not advertise them. Once returns valid empty catalogs for those probes and responds to the standard liveness request. Workflow guidance comes from the initialization instructions and live tool catalog.

Wiring into Claude Desktop#

Add an entry to your claude_desktop_config.json under mcpServers:

json
{ "mcpServers": { "once": { "command": "once", "args": ["--workspace", "/absolute/path/to/your/project", "mcp"] } } }

Restart Claude Desktop. The read-only tools appear under the once server in the connectors list and Claude can call them directly when planning against the graph and project memory.