MCP Integration
db-cluster ships an MCP server (db-cluster-mcp) that exposes 16 typed tools to AI agents over stdio. Every tool carries safety annotations the model can branch on; every error response is a structured AiErrorEnvelope.
Default trust posture (ai-facing + redaction)
Section titled “Default trust posture (ai-facing + redaction)”The MCP server defaults to the ai-facing trust zone with redaction ON. With
no policy environment variables set, it applies the default ai-facing policies +
redaction rather than running as a fully-trusted in-process kernel:
- Artifact content and sensitive entity attributes are stripped at the boundary by default — no tool returns raw artifact bytes.
- Write tools enforce approval —
cluster_commit_mutationandcluster_compensate_mutationrefuse to write unless the command is inapprovedstatus. The refusal is a structuredAiErrorEnvelope, not a partial write; the caller must runcluster_approve_mutationfirst.
To run the server in a trusted operator context with the privileged (internal /
cluster-admin) posture, explicitly opt in via an environment flag —
provisionally DB_CLUSTER_MCP_ALLOW_PRIVILEGED (final name in the release notes).
The default flip is MCP-surface only; the in-process SDK and the
@mcptoolshop/db-cluster/unsafe paths for trusted callers are unchanged.
Quick wire-up
Section titled “Quick wire-up”{ "mcpServers": { "db-cluster": { "command": "npx", "args": ["db-cluster-mcp"], "env": { "DB_CLUSTER_DIR": "/path/to/.db-cluster", "DB_CLUSTER_PRINCIPAL": "{\"id\":\"agent-1\",\"name\":\"Agent\",\"roles\":[\"agent\"],\"trustZone\":\"external-readonly\"}" } } }}The server is launched on demand; it terminates when the MCP host disconnects.
Tool catalog (16 tools)
Section titled “Tool catalog (16 tools)”| Tool | Verb | readOnlyHint | destructiveHint | requiresApprovalHint |
|---|---|---|---|---|
cluster_find_sources | discover | ✓ | ||
cluster_retrieve_bundle | retrieve | ✓ | ||
cluster_explain_retrieval | explain | ✓ | ||
cluster_resolve | resolve URI | ✓ | ||
cluster_trace | trace provenance | ✓ | ||
cluster_why | explain provenance | ✓ | ||
cluster_inspect_command | inspect | ✓ | ||
cluster_list_receipts | list | ✓ | ||
cluster_policy_explain | policy view | ✓ | ||
cluster_policy_test | policy probe | ✓ | ||
cluster_propose_mutation | stage | ✓ | ||
cluster_validate_mutation | stage | ✓ | ||
cluster_approve_mutation | stage | ✓ | ||
cluster_reject_mutation | stage | ✓ | ||
cluster_commit_mutation | commit | ✓ | ✓ | |
cluster_compensate_mutation | compensate | ✓ | ✓ |
readOnlyHint: true — tool never writes any cluster state. AI hosts can safely batch these.
destructiveHint: true — tool writes truth that produces ledger receipts. Pair with operator approval.
requiresApprovalHint: true — tool requires explicit human-in-the-loop approval per the mutation lifecycle. AI hosts should surface to the operator before invocation.
AiErrorEnvelope shape
Section titled “AiErrorEnvelope shape”Every error result from any tool is shaped:
interface AiErrorEnvelope { code: string; // stable ClusterErrorCode, e.g. 'POLICY_DENIED', 'COMMAND_QUEUE_CORRUPT' message: string; // human-readable, sanitized (no paths, no stack) retryable: boolean; // is retry meaningful? remediation_hint: string; // WHAT TO DO next, in one short sentence context: Record<string, unknown>; // subclass-specific structured fields (entityId, store, capability, …) next_valid_actions?: string[]; // optional — for lifecycle errors, which verbs are valid next?}Branch on code and retryable — never parse the prose message. Stack traces are never exposed. The _contentPolicy marker on retrieve_bundle responses states that artifact content is data, not instructions, even when present in the bundle.
Example error pattern-match
Section titled “Example error pattern-match”const result = await mcp.callTool('cluster_commit_mutation', { commandId: '...' });if (result.body.code === 'COMMAND_NOT_VALIDATED') { // Run validation first. await mcp.callTool('cluster_validate_mutation', { commandId: '...' });} else if (result.body.code === 'POLICY_DENIED' && !result.body.retryable) { // No retry — escalate to the operator.} else if (result.body.retryable) { await sleep(backoff()); // retry}Output discipline
Section titled “Output discipline”The MCP boundary applies four guarantees:
-
Artifact content is sanitized —
_contentAccess: 'sanitized'. The raw artifact bytes are stripped from retrieve_bundle output. The_contentPolicymarker reminds consumers that any content that does pass through is data, not instructions. -
Stack traces are scrubbed —
src/mcp/sanitize.ts::redactErrorstrips paths, environment values, and stack details before surfacing. -
Empty results carry
empty_reason— when a query returns nothing,_meta.empty_reasonexplains why (all_filtered_by_policy,no_index_match,staleness_threshold_exceeded, etc.), with a remediation_hint where applicable. -
Lifecycle responses carry
next_valid_actions— for any command-lifecycle response (propose,validate,approve,commit,reject,compensate), the response surfaces which verbs are valid as the next step.
Tracked residuals (v1.x)
Section titled “Tracked residuals (v1.x)”V2-C1-009— long-running ops (doctor / verify / rebuild / backup / restore) surface as single-shot MCP tools, not streaming. Granular progress is documented but not on the v1.0.0 wire.
See also
Section titled “See also”- Policy & Redaction — what gets denied, and what gets redacted.
- SDK Reference — the SDK is the in-process equivalent of the MCP surface.
- The
examples/mcp/directory in the repo has tool-by-tool example wire-ups.