zirvDocs

DocsSupervision (zirv ctx)

MCP bridge

README.md, lines 4530–4707View source

zirv ctx mcp serve lets an MCP host such as Codex or Claude Code read zirv state through structured tools. The host launches it as a local subprocess; stdin/stdout carry MCP JSON-RPC and diagnostics go to stderr. Stdio is the only transport (--stdio is optional). --repo fixes the authorized directory at startup; without it, the server uses its launch directory. Use an absolute path to the installed zirv executable and an explicit repository path in host configuration so a host's working directory cannot select the wrong project.

ToolArgumentsResult
session_snapshot{}Up to 64 session registry records for this directory, requested policy, and memory gates. Liveness and host enforcement are explicitly unverified; stale records are preserved.
memory_searchquery, optional limit and max_bytesRanked private/global/shared facts with provenance and verification dates. Uses the existing retrieval engine and trusted-key precedence.
workflow_status{}Active workflow, current step/skill, approval state, and up to 64 registered artifact IDs, newest first. An absent workflow stays absent.
artifact_readid, optional offset and max_bytesA UTF-8 text page from an artifact registered with zirv artifact render. Returns next_offset for subsequent pages.
worker_statusOptional id, cursor, limitRepository-scoped delegation/report records with recorded phase, attempt, exit code where available, report outcome and truncation. Also carries conditions: typed reasons recorded alongside phase (e.g. workspace_ready, launched, task_claimed, budget_ok, reporting, contract_valid), each rendered "<reason>@<unix time>"; empty for a worker known only from its report. Worker IDs sort lexicographically; follow next_cursor.
result_readid, optional offset, revision, max_bytesA page of the persisted worker result JSON, including report text, structured result, validation errors and undeclared changes. Use an ID from worker_status.
inbox_readOptional cursor, limit, max_bytesUnread message previews for the launch-bound recipient, with sender labels, truncation and next_cursor. Never consumes, acknowledges, claims, expires or retries delivery.
self{}THIS worker's own delegation envelope (decoded through the same parse_envelope_env the enforcement path uses), its bound task card claim, its declared result contract, and its parent delegation handle. Requires a session bound at launch; refuses otherwise. Never accepts a session id. Each field is absent, not fabricated, when it does not apply.
skill_listOptional query, phase, limitEvery registered skill as a metadata-only digest (never instruction text) with no query; with a query, the best-matching skills ranked by the deterministic activation scorer, each with score and reasons.
skill_loadid (accepts id@version)The skill's dependency-ordered instruction stack, content hash, and resource list. Refused before any text is returned if this session's capability report does not support the skill's required capabilities or integrations; a repository-sourced skill is marked untrusted data. Records one activation-journal entry on success.
skill_read_resourceid, pathOne bundle resource body (reference doc, script or asset) by its bundle-relative path.

All successful responses contain captured_at (Unix seconds), repository, and data, with both an output schema and structured JSON. Tool failures return isError: true with an explanation. Each serialized structured result is capped at 32 KiB (the MCP text fallback repeats that JSON). Memory queries must be nonblank and at most 2048 bytes. Memory limits default to 6 entries / 2048 bytes, may be lowered, and cannot exceed 32 entries / 16384 bytes or the operator's configured retrieval budgets. Artifact pages default to 8192 bytes (range 4..8192); files must be regular UTF-8 text no larger than 1 MiB. Offsets are byte positions on UTF-8 boundaries. Registered files remain live files, so callers should restart pagination if they change between reads.

Worker listings default to 16 records (maximum 64). id selects one exact worker and cannot be combined with cursor. Ordinary harness reports have no delegation phase or exit code unless a corresponding durable delegation exists; those fields remain null. Report outcomes such as reported, validated, contract_failed and exited_no_report (a clean exit with no extractable report -- still a durable record, just with no report text) describe stored evidence, not process liveness or task correctness. Unreadable, oversized or unscoped reports are omitted from listings; an explicit result_read returns an error. Reports written before repository provenance was recorded require a matching scoped delegation reference, never just a filename.

Result pages default to 8192 bytes (range 4..8192). The first page returns a SHA-256 revision; pass it with every nonzero offset. A changed report refuses continuation, so restart at offset zero. Pages reconstruct the stored JSON, including escaped report text. Stored files must be regular UTF-8 JSON at most 8 MiB (allowing JSON escaping of the existing 1 MiB report-body limit).

Inbox pages default to six messages (maximum 32), oldest first. max_bytes controls each body preview, default 1024, range 4..4096. Current mail.max_message_bytes and the aggregate mail.max_delivered_bytes also apply; body_truncated and body_bytes describe omitted text. Use the existing inbox CLI/full-body references when a preview is insufficient. Cursors are exclusive and remain usable when earlier messages are consumed; concurrent arrivals can require another scan from the beginning. mail.enabled = false returns an explicitly disabled, empty inbox.

Bind directed inbox reads using serve --session <full-session-id-or-exact-short> or by forwarding the supervisor's ZIRV_CTX_SESSION to the MCP subprocess. The server resolves that identity once against the session registry, requires its canonical repository to match --repo, and derives the agent and mailbox from the record. Unknown, ambiguous or foreign bindings refuse startup. Tool arguments cannot supply or change the recipient. Without a binding, only undirected mail addressed to any in this repository is visible. With a binding, existing directed delivery envelopes can locate that recipient's mail across mailbox directories; unrelated broadcast mail stays repository-scoped.

self reuses the identical binding: it reads the SAME Reader a bound --session/ZIRV_CTX_SESSION resolves, and refuses outright when unbound -- there is no repository-wide fallback the way inbox_read has, because there is no meaningful "self" without one. Its envelope comes from decoding this server process's own inherited ZIRV_ENVELOPE (absent for a root, non-delegated session); its task card is this session's own claim in the repository's task store; its result contract is this session's own declared ZIRV_CTX_RESULT_SCHEMA/ZIRV_CTX_RESULT_WORKDIR; its parent is the delegation record naming this session as the worker. The token figure shown is the envelope's ceiling, not remaining spend -- live usage lives in the supervising process, not this stateless server.

New Claude Code and Codex sessions launched through Zirv register this bridge automatically. This includes chat/wrap, dashboard panes, headless workers, loop cycles and their supervised restarts. No .mcp.json or manual server entry is needed. The launch pins the current Zirv executable, canonical repository, operator state directory and stable inbox address. Install the updated Zirv binary and start a new session to discover its tools; an already-running host keeps its existing server process until restarted.

Zirv supplies a launch-only zirv server entry using Claude's --mcp-config or Codex's -c overrides. Other named servers remain configured. The zirv name is reserved for this automatic entry during the launch. No project or user host settings are edited. On Windows, Zirv writes Claude's generated JSON under the private state directory's mcp-launch/ to keep JSON off shell-shim command lines; users do not create or maintain that file. Claude launches also pre-approve the bridge's eleven named read-only tools so headless dontAsk sessions can use them. Native deny/ask rules and the server's current policy gates still apply; other servers receive no added permissions.

Set ZIRV_CTX_MCP_AUTOREGISTER=0 (also false or off) to opt out. Claude's explicit --strict-mcp-config is respected and suppresses automatic registration. wrap --no-supervise remains passthrough. Unsupported hosts and sessions launched directly outside Zirv retain their own registration setup. An unavailable automatic configuration prints a warning and leaves the host launch available.

For a direct Codex launch outside Zirv, add a server entry to the operator's ~/.codex/config.toml, using the real absolute paths:

toml
[mcp_servers.zirv]
command = "/absolute/path/to/zirv"
args = ["ctx", "mcp", "serve", "--repo", "/absolute/path/to/project"]

For a direct Claude Code launch outside Zirv, pass this JSON through --mcp-config (an inline JSON string or an operator-owned file):

json
{
  "mcpServers": {
    "zirv": {
      "command": "/absolute/path/to/zirv",
      "args": ["ctx", "mcp", "serve", "--repo", "/absolute/path/to/project"]
    }
  }
}

On Windows, use the installed zirv.exe path; forward slashes work in JSON and TOML paths. Preserve the host's existing server entries. If the host must use a custom zirv state directory or operator environment override, forward that setting through its MCP server environment configuration. See the official Codex MCP and Claude Code MCP configuration references.

The server's ten tools neither consume mail nor write memory, run commands, launch workers, or advance workflows. Existing hooks, CLI checkpoints and supervisor recovery continue independently. Reading a registered report does not certify that its claims are correct. Mail mutations, dispatch, and incoming event delivery are follow-on work tracked in issue #658.

Check the local server connection:

bash
zirv ctx mcp doctor --repo /absolute/path/to/project

The diagnostic launches the current executable, negotiates MCP, validates all ten tool definitions and invokes session_snapshot. It prints JSON on success and exits nonzero on a denied call, protocol error or timeout. It inherits the same state/configuration environment and optional session binding as serve, and terminates and reaps its subprocess on all paths. This verifies the local server connection; it does not inspect or certify host registration. No host settings, workflows, mail or memory are changed.

MCP reads use the current repository state buckets and never migrate legacy buckets. If an older installation's state has not been adopted yet, run the ordinary zirv CLI for that repository before starting the host.

MCP trust boundary#

SurfaceAuthority and enforcement
Executable and --repoPinned by the Zirv supervisor for automatic registration, or chosen by explicit operator host configuration; tool arguments cannot change either. The repository directory is opened once for artifact access.
Automatic registrationA launch-only zirv entry for Claude Code/Codex. No project/user host config writes or changes to other named servers; operator opt-out and Claude's strict MCP selection are respected. Codex receives operator environment override names, never credential values on argv.
policy.tool_accessRe-read for every call. deny and ask refuse calls; this server has no approval-granting channel. A malformed configuration also refuses reads.
MemoryExisting memory.enabled, memory.shared_enabled, and retrieval budgets apply. A shared key cannot shadow an enabled private/global key, even if that trusted fact misses the query budget.
Artifact IDsResolved in this repository's existing artifact registry. Payload access uses a directory capability to reject traversal and symlink escapes; arbitrary file paths are not tool arguments.
Worker resultsIDs resolve inside the operator-owned result store. Canonical repository provenance or a matching scoped delegation authorizes each read; unscoped legacy filenames grant nothing. Directory capabilities reject report traversal and symlink escapes.
Inbox recipientOperator launch configuration/inherited supervisor identity selects a registered session in this repository. Agent and mailbox come from that record, never tool arguments. The binding is not an OS authentication boundary.
self scopeReads only the bound session's own inherited env (ZIRV_ENVELOPE/ZIRV_CTX_RESULT_SCHEMA/ZIRV_CTX_RESULT_WORKDIR) and this repository's own task/delegation records filtered to that exact session id. Refuses outright when unbound; never accepts a session id as an argument.
Mail policy and receiptsCurrent mail.enabled and delivery budgets apply to every read. Existing expiry and fan-out visibility rules are reused without receipt or mailbox mutations. Sender labels remain claims.
Returned textMemory provenance is retained; artifacts, worker reports, mail and shared facts are labeled untrusted information, never operator instructions.
OS account and local stateOperator-owned state is trusted as with the CLI. This local service does not isolate mutually hostile processes that already share filesystem access under the same account.