Rendered from docs/interfaces/headwater-mcp.md in the Headwater corpus. Every document on this half of the site is typed by the taxonomy the descriptor names: corpus.json.

headwater mcp

Synopsis

headwater mcp [--now <date>] [--write] [--root <path>]

The server reads JSON-RPC messages from standard input and writes one response per request to standard output.

Description

headwater mcp starts the agent-facing surface of the same library as the command line. It walks the corpus once, fixes the date once and then answers MCP requests from those values.

The default server registers seven read tools: route, explain, related, resolve_identifier, governing_docs_for_path, check and kinds. The check tool takes one format from text, json, sarif or markdown. The kinds tool takes one format from text or json, and it has no default. It answers the bytes that headwater taxonomy kinds writes over the lock that the server started with, and one renderer writes both. Its structuredContent is the document that headwater taxonomy kinds --json writes. Four of the other five read tools take the target or task named by their command-line counterparts. governing_docs_for_path has no command-line counterpart (#845). This server is the only route to it. The explain, related and governing_docs_for_path tools read a path as headwater explain reads it, relative to the root that the server started over (#1227, #1249). So ./x, a/../x and an absolute path under the root get the answer that x gets. For a path outside the repository, each of the three tools answers with the sentence that the verb writes. That sentence is "<path> is outside this repository, or is not a path it can read". A path through a symlink that leads out of the root is outside the repository. When governing_docs_for_path refuses a path, its structuredContent is {"pointers": []}. A census row can be one that the walk could not read. For such a row, the explain tool answers with the refusal of headwater explain. The related tool answers with the same sentence, with related as the verb, so it ends "so related prints nothing". Each answer is a normal content block and not a tool error. governing_docs_for_path takes a code path and not a document. It does not open a named pipe, a socket or a device under the root. When no document governs such an entry, the answer is "no document governs ", and structuredContent is {"pointers": []} (#1366).

route and governing_docs_for_path put their answer in result.structuredContent, and that member is the machine contract of both tools (#1248). A client reads the pointers from structuredContent.pointers. Each element holds path, kind and unwarranted, and it holds id, name, purpose and summary where the document declares them. A route element also holds evidence, which states what reached it and names any suspect edge. The server adds no newline to a string under structuredContent, whatever its length. A newline that the author wrote, in a summary or in the task, is data, and the server carries it through as it is.

For route, the member is the document that headwater route --json writes for the same task, less its text member. That text is the report folded at 80 columns for a terminal, so the MCP answer does not carry it. The server takes the member after it removes the paths that git ignores, so ungoverned never names an ignored path. The other members are version, task, terms, separating, distinctive, anchors, matched, withheld, ungoverned and, for a silent route, silence. json::VERSION gives the version of their shape. For governing_docs_for_path, the member is {"pointers": [...]}.

The text block is for display only. The server never folds it, so a pointer takes one line unless its own summary or name holds a newline that the author wrote. The first line repeats the task, and a newline in the task shows there as well. So the text block is not a parse target. A path can hold (, a summary can hold any word, and a line can end where the author put a newline. A client shows the text block as it is, and takes the pointers only from structuredContent.pointers. The server announces protocol 2024-11-05, which does not define structuredContent, so a client that reads only that protocol ignores the member.

--write also registers new and fix. new takes a kind, title and optional array of relation strings. fix takes one output format. The fix tool passes no change, so it writes no verified_revision stamp onto a suspect edge. To record a stamp, run headwater change and then headwater check --fix --change from a terminal, as the headwater check contract states. No tool commits, pushes or merges, and the default server registers no tool that writes.

A write tool returns the account and artifact as separate content blocks. A call that moves a byte spends the server. Later tool calls receive a JSON-RPC -32000 error because their answers would describe a stale corpus. A refused write or a write that lands no byte does not spend the server.

The transport uses one JSON object per line. Notifications produce no response. Unknown methods and invalid tool arguments produce JSON-RPC errors. Tool descriptions state read-only and destructive hints, but registration is the boundary that controls which tools exist.

Preconditions

The repository must carry a readable .headwater/taxonomy.lock, consumer declaration and corpus. The server loads these before it accepts a message.

The host must provide a date, or --now must provide one in YYYY-MM-DD form. The server uses that date for its whole session.

The process must have readable standard input and writable standard output. The server does not need a network endpoint or a model.

Options

Option What it does
--now <date> Fix the date for every check and write in this server session.
--write Register the working-tree new and fix tools. It does not register commit, push or merge tools.
--root <path> Select the repository to load and serve.
--no-color Force plain text on both streams: bold and dim weight plus glyphs, no escape sequence. The default already senses whether each stream is a terminal, and renders color only there. Every response this server writes is JSON on stdio, which carries no color at all.
--no-banner Suppress the masthead: the line naming this binary and its version, that the root help screen alone prints. It is accepted here and does nothing, since only the root screen prints one.

--wide is refused because the server prints protocol responses rather than help. Global --help, --version and --no-banner are answered before the server runs.

Exit status

0 means that the server started and returned when standard input closed. Tool findings and JSON-RPC errors do not change this process status.

1 means that the command line, date, taxonomy, consumer declaration or corpus could not load. A protocol error is carried in the response with its JSON-RPC code.

1, and never 101, when standard output or standard error cannot be written, and one sentence on standard error names a failed standard output.

Environment

No environment variable reaches this verb. The date, write consent and repository come from the command line, and all other inputs come from the loaded tree and protocol messages.

Files

Path How this verb treats it
.headwater/taxonomy.lock Read at startup.
.headwater/taxonomy.yml Read at startup through the consumer loader.
The corpus Read once at startup for every registered tool.
.headwater/imports/ Read at startup where .headwater/taxonomy.yml declares an import, for the anchors that an imported snapshot supplies. An imports entry that does not read stops the verb with exit 1, and so does an at path outside the repository root.
the path each harvests.<name>.at names Read at startup where .headwater/taxonomy.yml declares a pinned corpus export, for the anchors that export supplies. A harvests entry that does not read stops the verb with exit 1, and so does an at path outside the repository root. A pin with no digest binds no anchor. An absent file binds no anchor, and neither does a file that fails the pinned digest or is not an export.
Documents and .headwater/capture-cost.jsonl Written by new when --write is enabled.
Documents Written by fix only when a derived patch lands.

The default server writes no file. A write-enabled server ends its usable session after the first call that moves a byte.

See also

headwater route and headwater explain document the terminal reads served by this protocol.

Spec 5 defines the query, working-tree write and landed-write classes.

Spec 6 defines the MCP transport boundary.