MCP Interface

For a concise local setup path, see MCP Quickstart.

MCP is Zaxy's primary integration surface. The server exposes memory operations as typed tools so LangGraph, Claude Desktop, custom agents, or any MCP-capable client can use the same memory system without linking directly against Python application code.

Model Call Rhythm

Use Zaxy tools in this order:

  1. At session start, call memory_bootstrap.
  2. Before substantial work, call memory_checkout.
  3. For multi-agent missions, use Coordinate tools to record worker-local findings and promote only accepted state.
  4. After using retrieved context, call memory_feedback.
  5. When checkout returns synthesis answer candidates and one materially shapes the answer, call memory_synthesis_artifact.
  6. When an individual synthesis ledger row is used or excluded, call memory_synthesis_evidence.

memory_append(event_type, actor, payload, thread?) appends a typed event to the Eventloom log for the selected session, extracts graph entities and edges, upserts the selected graph projection, records metrics, and emits a Pathlight span when tracing is enabled. Payload size is bounded and session IDs are validated before they affect filesystem paths.

memory_query(query, temporal_filter?, limit?) returns ranked context chunks. The query router validates the string and limit, optionally embeds the query, runs exact/keyword/vector/traversal search, fuses scores, and returns compact context suitable for an agent prompt. Temporal filters let a client ask what was valid at a specific time. Remote SSE requests are constrained to the session from the configured session header. Results include Eventloom citations when available so clients can display or replay the source event. Results also include score_explanation metadata for ranking diagnostics.

memory_verbatim(query, session_id?, limit?) returns exact source chunks from the Eventloom log without requiring a graph service. It is the source-recall lane for questions that need raw transcript turns, document chunks, identifiers, quoted phrases, or file/source citations. Results include the raw content, BM25 score, eventloom://... citation, source kind, and source metadata such as document path/line range or transcript source/turn index.

memory_feedback(entity_name, entity_type, feedback, ...) records whether a retrieved graph entity was useful. Positive feedback values, used and helpful, append a memory.reinforced event with optional importance, query, source, score, citation, and reason fields. Negative feedback, irrelevant, appends an audit-only memory.feedback event and does not delete or decay existing memory. Fabric-level feedback for assembled packet_memory context also preserves source packet projection metadata. The tool uses the same session scoping rules as append and query. Pass purpose and outcome when a memory item changes a purpose-specific action, such as accepted Coordinate state supporting a handoff; reinforced memory projection preserves compact purpose profile, evidence-policy, expected-action, authority, and mission metadata for future checkout and audit.

memory_synthesis_artifact(checkout, candidate?, outcome?, ...) persists the answer candidates from a Memory Checkout response as a deterministic memory.synthesis.artifact.created event. If a selected candidate is provided, outcome must also be provided; Zaxy records the normalized outcome as memory.synthesis.used, memory.synthesis.rejected, memory.synthesis.corrected, or memory.evidence.excluded. The checkout payload owns the session scope, so this tool intentionally has no separate session_id override. Candidate feedback must match one of diagnostics.synthesis.answer_candidates; Zaxy canonicalizes the persisted candidate from checkout diagnostics before appending the outcome event. Artifacts and candidate outcomes project into graph memory as synthesis artifact, answer-candidate, ledger-row, and source-group relationships.

memory_synthesis_evidence(checkout, row, outcome, candidate?, reason?, actor?) records synthesis evidence row feedback for one diagnostics.synthesis.ledger_rows item. used and helpful outcomes append memory.evidence.reinforced; excluded appends memory.evidence.excluded. The event preserves the row fact id, source group, citation, support source ids, optional selected answer candidate, checkout quality, slot plan, and reason. Use this when a composed answer depends on or explicitly rejects a ledger row instead of only recording the aggregate candidate outcome.

In Coordinate missions, use coordination_record_synthesis_artifact instead of the generic memory tool when the answer candidate is part of a merge brief, approval packet, accepted checkout, or handoff. It writes the generic synthesis artifact and then appends a mission-scoped coordination.proof_packet.created event with accepted finding ids, review refs, promotion refs, worker source refs, optional handoff event refs, diagnostic pending ids, conflict ids, excluded row reasons, and non-authoritative row diagnostics. For decision_scope="handoff", provide handoff_id so the proof packet cites the exact coordination.handoff.created sequence and hash.

memory_skill(action, skill_id, ...) is a typed helper for procedural memory. It appends one of the deterministic skill lifecycle events skill.proposed, skill.validated, skill.revised, skill.deprecated, skill.contradicted, skill.applied, or skill.outcome_recorded, then projects the event through the same extractor and graph path as memory_append. Use it when an agent learns, validates, revises, applies, or records outcomes for a reusable procedure. The helper accepts version, name, summary, procedure, applicability, citations, task, success_score, feedback, evidence, reason, and supersedes_version as relevant to the action. Skill updates are never implicit checkout side effects.

memory_replay(session_id, from_seq?) rebuilds session history from the Eventloom log. This is useful for handoffs, audits, and debugging. In remote SSE mode, the authenticated session scope is enforced so a client cannot replay a different session. For long sessions, the CLI replay tool can inspect bounded Eventloom ranges with zaxy replay .eventloom/work.jsonl --from-seq N --to-seq M.

memory_invalidate(entity_name, entity_type, invalid_at) closes the validity window for a graph fact without deleting history. This lets agents correct memory while preserving provenance.

memory_capabilities(session_id?, current_task?) returns the model-facing memory contract for the active session. It tells the model what Zaxy is, which tools are available, when to refresh context, which capture paths appear healthy, and which call should normally happen next. Models should call this at session start or whenever tool awareness is unclear, then call memory_checkout for the current task. The contract explicitly treats memory as an ambient loop: session-start awareness is not enough, so models should refresh memory before major work, after compaction/resume, and before roadmap or architecture decisions.

memory_bootstrap(session_id?, current_task?) is the shorter startup packet for clients that want one model-facing handoff. It embeds the capabilities manifest, the first recommended checkout call, deterministic capture status, and a trust policy for cited current facts, unsupported context, and feedback recording. Both memory_bootstrap and memory_checkout record lightweight activity markers so hooks and dashboards can tell whether Zaxy is still visible in a long session.

Zaxy also records memory.reminder.suggested when lifecycle hooks detect a session boundary, resume, compaction, long session, long tool run, or roadmap/status question after stale memory activity. Treat that event as a runtime nudge: call memory_bootstrap if tool awareness is unclear, then call memory_checkout for the current task before answering.

memory_checkout(query, session_id?, ref?, replay_from_seq?, limit?, max_recent_events?, purpose?) returns the high-level contract an agent should condition on before a turn. It wraps context assembly with a # Memory Checkout prompt, current facts that exclude superseded context, cited evidence, provenance parsed from eventloom://... citations, retention metadata, warnings, the active working set, and Checkout diagnostics. Diagnostics include source lane counts, total citation count, current-fact citation count, current fact count, excluded superseded context count, warning count, and a memory_feedback recommendation when cited context is returned. purpose may be a preset such as coding, review, release, security, research, or coordinate, or an object with role, task, risk, time horizon, expected action, evidence policy, retention policy, and ontology lens fields. The normalized profile is returned in purpose, diagnostics, prompt guidance, and later synthesis feedback payloads so memory can be conditioned by the intended action instead of query text alone. Non-general purpose profiles condition retrieval before checkout projection by adding deterministic profile emphasis terms, purpose-specific recall floors, and a purpose-selected scoring profile; the applied policy is reported in diagnostics.purpose_retrieval_policy. Purpose suppress rules are then enforced before checkout projection, and any excluded rows are summarized in diagnostics.purpose_policy and retention.purpose_policy so clients can audit why retrieved material did not become current memory. When applicable Skill Memory is retrieved, diagnostics also include a skills block and the prompt includes an Applicable Skills section with cited procedure steps. This lane is read-only: models may follow the guidance, but revisions require a new memory_skill or memory_append event. When retrieved skill versions and outcomes include enough history, diagnostics also include skill_analytics and the prompt includes a Skill Analytics section. That section reports read-only promotion candidates, rollback candidates, contradiction counts, outcome counts, scores, and citations so the model can decide whether to apply, avoid, or explicitly revise a skill. This is the preferred tool when a model needs a bounded, auditable working state rather than a raw list of retrieval hits. The response also includes guidance with model-facing trust and ignore instructions, a recommended follow-up memory_checkout call, and concrete memory_feedback payload templates for cited facts that materially influence the next response. The quality block adds an answerability decision (answer_from_memory, refresh_recommended, or ask_user), a bounded confidence score, reasons, and any required next action. Checkout only returns answer_from_memory when current facts have current Eventloom citations and the checkout has no warnings; missing, superseded-only, uncited, or compacted checkout states ask the model to refresh memory or ask the user instead of answering from stale context. When ref is supplied, checkout resolves a Git-style memory ref such as HEAD or refs/heads/main and filters replay/context to the target event identity. MCP clients discover this tool through the standard tools/list handshake, so an already-running client must reconnect before the new tool appears in the model-visible tool registry.

Example checkout response fragment:

The canonical docs/test fixture for this contract is docs/examples/memory-checkout-contract.json; keep examples aligned with that fixture when changing the tool response.

{
  "current_facts": [
    {
      "content": "Memory Checkout is the model-facing context contract.",
      "citation": "eventloom://zaxy-default/events/1882#abc123def456",
      "source_lane": "graph",
      "entity_name": "memory checkout",
      "entity_type": "decision"
    }
  ],
  "diagnostics": {
    "source_lanes": {"graph": 1},
    "citation_count": 1,
    "current_citation_count": 1,
    "current_fact_count": 1,
    "superseded_contexts_excluded": 0,
    "warning_count": 0,
    "feedback_recommended": true,
    "feedback_tool": "memory_feedback",
    "skills": {
      "count": 1,
      "items": [
        {
          "skill_id": "python-test-first",
          "version": "1",
          "status": "validated",
          "procedure": ["Write failing test", "Run pytest"],
          "citation": "eventloom://zaxy-default/events/1883#def456abc123"
        }
      ]
    }
  },
  "quality": {
    "answerability": "answer_from_memory",
    "confidence": 0.75,
    "reasons": ["Retrieved current facts with Eventloom citations."],
    "required_action": null
  },
  "guidance": {
    "feedback": {
      "tool": "memory_feedback",
      "payloads": [
        {
          "entity_name": "memory checkout",
          "entity_type": "decision",
          "feedback": "used",
          "actor": "assistant",
          "citation": "eventloom://zaxy-default/events/1882#abc123def456"
        }
      ]
    }
  }
}

Model consumption rule: answer from memory only when quality.answerability is answer_from_memory. If it is refresh_recommended, call the quality.required_action tool before relying on the checkout. If it is ask_user, ask for missing context instead of inventing continuity. When cited facts materially influence the response, call memory_feedback with one of the listed payloads so Zaxy can reinforce useful context.

For composed questions, checkout diagnostics also include a slot_plan contract that names required retrieval slots such as source, numeric, and temporal, plus optional exact and semantic slots. When evidence is incomplete, quality.required_action includes missing_slots and suggested_queries so the model can retry checkout before answering. Numeric and aggregation synthesis bundles are projected into diagnostics.synthesis.answer_candidates, including rank, candidate type, answer value, confidence, supporting source IDs, and excluded source IDs. Generated synthesis bundles also expose diagnostics.synthesis.ledger_rows with fact IDs, source groups, citations, values, labels, and include/exclude reasons. After using one of those candidates in a response, record the checkout and candidate outcome through memory_synthesis_artifact; this keeps composed answers auditable without mutating source memory. When a specific ledger row materially supports or is excluded from that answer, record the row-level outcome through memory_synthesis_evidence so future checkout can reinforce or diagnose the exact cited fact.

In Coordinate missions, synthesis bundles are the proof format for merge briefs, approval packets, accepted checkout, and handoff answers. Each ledger row must preserve whether it came from accepted parent state, pending worker-local findings, rejected findings, stale evidence, or conflict diagnostics. Accepted checkout synthesis must default to parent-accepted state; pending worker-local rows may appear only in diagnostics and must be labeled non-authoritative.

Degraded checkout response fragment:

{
  "current_facts": [
    {
      "content": "Memory Checkout is current.",
      "citation": null,
      "source_lane": "graph"
    }
  ],
  "diagnostics": {
    "citation_count": 0,
    "current_citation_count": 0,
    "current_fact_count": 1,
    "warning_count": 1
  },
  "quality": {
    "answerability": "refresh_recommended",
    "confidence": 0.29,
    "reasons": [
      "Retrieved current facts, but they lack Eventloom citations.",
      "Checkout contains warnings that reduce confidence."
    ],
    "required_action": {
      "tool": "memory_checkout",
      "query": "current decisions, blockers, and next actions for: Memory Checkout is current.",
      "reason": "Refresh memory before major follow-up work, after compaction/resume, or when task scope changes."
    }
  }
}

context_assemble(query, session_id?, replay_from_seq?, limit?, max_recent_events?) returns a prompt-ready bundle containing bounded recent replay plus ranked retrieval. The assembled retrieval set includes a reserved verbatim Eventloom source-recall lane by default, and each context item includes metadata with an assembly_lane value such as graph or verbatim. The response also includes assembly_policy and context_counts fields so clients can inspect the active policy and the number of graph, verbatim, and replay items returned. The prompt begins with an # Active Memory Working Set section, and the JSON response includes working_set items for bounded goals, decisions, tasks, artifacts, blockers, and source anchors. context_after_turn(role, content, ...) first appends a transcript.turn event, then assembles context for the next model call. subagent_cleanup(parent_session_id, subagent_session_id, summary, ...) records subagent.cleaned in the subagent session and returns a handoff bundle with summary and integrity status. These lifecycle tools are session-scoped under remote SSE auth just like query and append.

Coordination tools package the parent mission plus worker session workflow: coordination_start, coordination_worker_create, coordination_assign, coordination_report_finding, coordination_merge_brief, coordination_checkout, coordination_performance_ledger, coordination_approval_packet, coordination_apply_approval, coordination_review_finding, coordination_promote, and coordination_handoff. coordination_record_synthesis_artifact binds a mission-scoped Memory Checkout synthesis artifact to a Coordinate proof packet for briefs, approvals, accepted checkout, and handoffs. Handoff-scoped proof packets require handoff_id and return handoff_event_ref with the cited Eventloom sequence and hash. They preserve accepted finding ids, non-authoritative diagnostic rows, conflict ids, and handoff refs as graph-projected coordinator memory, so future checkout can retrieve both the accepted support and the excluded worker-local rows. Selected answer-candidate feedback must also match the checkout candidates, so the proof packet, artifact, and outcome event cannot disagree about support ids. Coordinate keeps worker-local findings isolated until a coordinator review promotes accepted state into the parent mission history. The first merge brief, accepted checkout, inspection handoff records, and performance ledger are replay-backed and do not require graph availability. coordination_checkout returns promoted parent state by default and includes the coordinate purpose profile: accepted parent state is authoritative, worker-local pending rows are suppressed unless diagnostics are requested, and proof packets/handoff refs are retained as coordinator memory. Set include_diagnostics to include pending findings and conflicts as non-authoritative diagnostics. coordination_performance_ledger returns per-worker outcome metrics such as accepted, rejected, duplicate, missing-evidence, and test-backed finding rates. coordination_handoff appends a replayable parent mission event with summary, next steps, and risks; later handoff-scoped proof packets are linked back during mission inspection through their cited handoff_event_ref. coordination_proof_trace resolves a proof by artifact_id, handoff_id, or proof_seq and returns the replayed proof event, synthesis artifact event, handoff event, accepted finding refs, review/promotion refs, answer candidates, ledger rows, and non-authoritative diagnostics. The approval tools export pending/conflicted findings for remote review and apply returned decisions as ordinary review events, with promotion only when a decision explicitly sets promote.

MCP dispatch also performs automatic lifecycle capture by default. After each tool call, Zaxy appends a tool.call.completed event to the resolved session with the tool name, status, argument keys, and a bounded result summary. Raw argument values are not persisted in the lifecycle payload. Capture is best-effort: failures while recording metadata do not fail the original MCP tool call. Set MCP_LIFECYCLE_CAPTURE_ENABLED=false to disable this automatic capture. Server shutdown also records a best-effort session.ended event for the default session when lifecycle capture is enabled, and subagent cleanup records subagent.completed alongside the existing subagent.cleaned event.

Run stdio locally:

zaxy serve

At session start, clients or agents should bootstrap model awareness:

zaxy memory bootstrap --session-id zaxy-default
zaxy memory checkout "current task, project direction, and recent decisions" --session-id zaxy-default

memory_bootstrap returns the compact session-start handoff: the active capability manifest, recommended first checkout call, capture status, and trust policy. During a long session, repeat checkout before important work and after compaction or resume. Capture meaningful completions with context_after_turn or typed memory_append, and reinforce cited context that was actually used with memory_feedback.

Generate first-run MCP client config:

zaxy ide-config claude-desktop --eventloom-path .eventloom
zaxy ide-config claude-code --install --workspace .
zaxy ide-config cursor --eventloom-path .eventloom
zaxy ide-config cursor --install --workspace .
zaxy ide-config vscode --eventloom-path .eventloom
zaxy ide-config vscode --install --workspace .
zaxy ide-config codex --install --domain zaxy
zaxy ide-config codex --install --codex-config-scope project --codex-trusted-project --workspace .
zaxy ide-config hermes --install
zaxy ide-config claude-desktop --eventloom-path .eventloom --domain zaxy

By default, ide-config prints copyable config. The --install flag is limited to verified targets: project-local .mcp.json for Claude Code, .cursor/mcp.json for Cursor, .vscode/mcp.json for VS Code, explicit Codex TOML scopes, and Hermes Agent's global config.yaml. Install mode merges the zaxy server entry into the documented root object, preserves unrelated servers, and refuses to replace an existing zaxy entry unless --force is passed.

Codex is CLI-assisted by default: zaxy ide-config codex --install prints the official codex mcp add zaxy -- zaxy serve command. Codex config is kept workspace-neutral because user-level Codex MCP servers can be reused across repositories: it does not write graph-backend variables such as NEO4J_URI, PROJECTION_BACKEND, or repo identity values such as EVENTLOOM_PATH, EVENTLOOM_THREAD, or ZAXY_DOMAIN. A bare zaxy serve resolves .eventloom, the projection backend, and the domain-prefixed default session from the process workspace at startup. Direct TOML writes are opt-in through --codex-config-scope project|user. Project-scoped writes target .codex/config.toml and require --codex-trusted-project because Codex only loads project config from trusted projects. User-scoped writes target CODEX_HOME/config.toml or ~/.codex/config.toml.

zaxy ide-config codex without --install also prints the Codex CLI command, because Codex does not use the JSON config shapes consumed by Claude, Cursor, or VS Code.

Hermes Agent uses a global YAML config, normally ~/.hermes/config.yaml or HERMES_HOME/config.yaml, with MCP servers under mcp_servers. Zaxy keeps the Hermes server workspace-neutral for the same reason as Codex: the global config may be reused across repositories. zaxy ide-config hermes prints the YAML fragment. zaxy ide-config hermes --install merges it into the Hermes config, or --hermes-config /path/to/config.yaml can target an explicit file. The generated entry exposes the model-facing memory tools without writing graph-backend variables or repo-specific EVENTLOOM_PATH, EVENTLOOM_THREAD, or ZAXY_DOMAIN; zaxy serve derives those from the current workspace at startup.

Embedded runtime ownership: when PROJECTION_BACKEND=embedded, one workspace zaxy serve process owns the repo-local Kuzu graph in read-write mode. Additional stdio zaxy serve processes, including worker/subagent MCP launches, proxy to that owner through .eventloom/runtime/zaxy-embedded-owner.sock instead of opening Kuzu themselves. This preserves full graph-backed checkout without starting in degraded mode.

zaxy init and zaxy doctor clean stale embedded owner records when no live owner lock is held. If the owner lock is held but no healthy proxy socket exists, doctor reports embedded_mcp_runtime with an action to fully exit stale Codex/Zaxy processes before retrying. Verify the local process set with:

ps -ef | awk '/[z]axy serve/ {print}'

Install the zaxy CLI before generating MCP config:

pipx install zaxy-memory
# or: pip install zaxy-memory

MCP clients cannot launch a server command that does not exist yet. Generated stdio config uses the resolved executable path by default, preferring the installed zaxy console script and falling back to the current process path. This is more reliable for GUI clients than assuming they inherit your shell PATH.

Generate observer hook adapters:

zaxy hooks claude-code --eventloom-path .eventloom --domain zaxy
zaxy hooks codex --eventloom-path .eventloom --domain zaxy

For Codex, the default local preset also writes .codex/zaxy-capture.json and prints a zaxy capture start --workspace . command. That managed watcher reads Codex's local session JSONL and appends normalized Eventloom observations. It does not proxy provider traffic or require an OpenAI API key. For supervised checks, add --watch-iterations <n> to run a bounded number of capture passes to the underlying zaxy codex-capture --watch command. Add --graph to zaxy capture start when the selected projection backend should receive newly captured observations during the same pass.

Hook adapters do not proxy tool execution. Agents and tools continue to execute normally while hooks append lightweight Eventloom observations through zaxy hook-event. The sink is intentionally graph-independent so session stop and pre-compaction hooks can record provenance even when the selected graph projection is unavailable. Custom clients can implement the same contract by emitting normalized triggers such as session-start, stop, precompact, checkpoint, command, and file-edit. Command and file-edit triggers become first-class command.completed and file.edit.applied events, which lets automatic capture feed retrieval and working-set projection without storing raw file content.

This deterministic capture path is the default Zaxy onboarding posture. Packet capture is optional and should be enabled only when raw provider request/response audit is worth the provider quota and transport-compatibility cost.

These commands print copyable JSON fragments and do not include bearer tokens, passwords, or admin secrets. Keep remote SSE credentials in the client secret store or environment, not in committed config.

The verified write targets for future client-specific installers are tracked in mcp-install-targets.md. That matrix is the guardrail for deciding when zaxy init may write or merge config directly versus printing copyable instructions.

Generated project-local stdio configs include ZAXY_DOMAIN and a domain-prefixed EVENTLOOM_THREAD, such as zaxy-default. This prevents clients that omit session_id from accidentally sharing the global default session across different projects. Codex user-level config is the exception: it must keep Eventloom/session/domain state out of config and let zaxy serve derive those values from the active project. For remote SSE configs, the same default is sent through the session header.

For local stdio clients, the generated config is intentionally self-contained: it forces development-mode local settings and defaults to the embedded Kuzu projection. Generated stdio configs set startup_timeout_sec to 90 so MCP clients do not kill startup while local indexes are opening or optional sidecars are warming. If you explicitly choose the optional Neo4j sidecar, Zaxy can reuse bolt://localhost:7687 or start a named Docker container, zaxy-neo4j, with the default local credentials. Leave NEO4J_AUTO_START=false when you manage Neo4j yourself; set NEO4J_AUTO_START=true only when you want Zaxy to start that local sidecar.

Run SSE daemon mode:

zaxy serve --transport sse --host 127.0.0.1 --port 8080

Production SSE requires either static bearer auth or OIDC. Static bearer auth uses MCP_REMOTE_AUTH_TOKEN or MCP_REMOTE_AUTH_TOKEN_FILE; clients send Authorization: Bearer <token> and a session header such as x-zaxy-session-id: agent-1. OIDC uses MCP_OIDC_ISSUER, MCP_OIDC_AUDIENCE, and MCP_OIDC_JWKS_URL; clients send an access token and Zaxy scopes the request from MCP_OIDC_SESSION_CLAIM. Production also requires MCP_ADMIN_TOKEN or MCP_ADMIN_TOKEN_FILE for replay and invalidation.

The MCP implementation lives in src/zaxy/mcp_server.py. Core orchestration lives in src/zaxy/core.py. Security helpers live in src/zaxy/security.py. See api.md for Python-level calls, configuration.md for environment variables, and security.md for remote transport hardening. The public overview is site/index.html, while README.md keeps the short command list.

MCP Tool Contract Snapshot

The v0.6 public-surface guardrail is docs/examples/mcp-tool-contract.json. That MCP tool contract snapshot records the tool count, tool names, descriptions, required fields, and full input schema for every public MCP tool exposed by src/zaxy/mcp_server.py.

Treat changes to that fixture as public contract changes. A schema change should be paired with docs, tests, and a changelog note explaining whether the affected tool is stable, beta, experimental, or internal. The snapshot is intentionally plain JSON so MCP clients and external adapter authors can inspect it without importing Python.

Representative Response Snapshots

The v0.6 response-shape guardrail is docs/examples/mcp-response-snapshots.json. It stores representative, normalized responses for memory_bootstrap, memory_checkout, memory_query, memory_verbatim, context_assemble, memory_feedback, and memory_synthesis_artifact, memory_synthesis_evidence, and coordination_checkout, covering startup, checkout, graph retrieval, verbatim source recall, prompt context assembly, feedback reinforcement, synthesis artifact writes, synthesis evidence row feedback, and accepted coordination state.

The snapshot deliberately preserves stable client fields rather than full prompt text. It covers startup sequence shape, recommended next tool, Eventloom status, checkout fact/citation diagnostics, quality status, purpose profile keys, feedback template keys, token-efficiency keys, required prompt sections, graph retrieval score explanation keys, verbatim source metadata keys, assembled context counts, feedback event identity, synthesis artifact event identity and normalized candidate outcome, and accepted coordination checkout counts. Update it only when the client-facing response contract intentionally changes.

Structured Error Payloads

MCP tool dispatch returns structured JSON error content instead of exposing raw Python exceptions to clients. The stable shape is:

{
  "error": {
    "code": "unknown_tool",
    "message": "Unknown tool: unknown_tool",
    "remediation": "Call list_tools and retry with one of the advertised tool names."
  }
}

The current error codes are:

Every error payload includes a human-readable message and remediation so MCP clients can surface actionable recovery text without parsing logs. Failed tool calls are still captured as lifecycle observations with the stable error summary, but secrets from arguments remain subject to the existing redaction path.