ADR-001
Thin Translator
Status: Accepted
Date: 2026-07-30
Category: Architecture Decision Record
Context
cks-mcp sits directly below the LLM client in the CKS ecosystem's
layering — see Architecture § Architectural Role.
cks-runtime documents this same kind of layering discipline one level
in, between itself and cks-core, in its own ADR-001 ("Runtime
Layering"). This decision extends that same discipline one layer further
out, to the MCP boundary.
Every canonical operation a tool call performs — validating a structure,
evolving it, merging two branches — already has a home: cks-core owns
semantic behavior, cks-runtime owns sessions, transactions, and storage.
Problem
An MCP server is the natural place to add conveniences: caching, request
batching, alternate validation shortcuts, session bookkeeping outside the
Runtime's own model. Each of these would be a small, locally-reasonable
addition. Accumulated, they would duplicate — and eventually drift from —
logic that cks-core and cks-runtime already own, exactly the coupling
Runtime Layering exists to prevent one layer further in.
Decision
cks-mcp implements no semantic logic and no operational state
management of its own. Its only responsibility is translating MCP tool
calls into cks-runtime operations and translating the results back into
MCP-shaped responses.
Concretely:
- Every tool handler in
tools/either calls intocks-runtime(session, transaction, operation) orcks-core(parsing, serialization) to do the actual work — it does not reimplement validation or evolution rules. - Concerns that are legitimately the server's own — MCP transport,
provenance signing, SSRF protection, structured error shaping — live in
dedicated modules (
server.py,provenance.py,verify_source.py,errors.py) rather than inside tool handlers, and are documented as the server's actual responsibilities in Architecture.
Consequences
Positive:
cks-mcpcan add new tools without ever risking semantic drift fromcks-core— a new tool is a new translation, not a new rule.- Bugs in validation or evolution semantics are fixed once, in
cks-coreorcks-runtime, and every consumer (not justcks-mcp) benefits. - The server stays swappable: another MCP-like adapter could expose the
same
cks-runtimeoperations differently withoutcks-coreorcks-runtimeneeding to change.
Negative:
- Some conveniences that would be trivial to bolt on locally (e.g. a cache of recently-validated structures) require a justified exception or an upstream change instead of a quick local patch.
- Provenance and SSRF protection, while consistent with "own only what's
genuinely yours," still make
cks-mcplarger than a pure pass-through would be — see ADR-002 for why that specific exception is justified.
Alternatives Considered
Embed a local validation fast-path
Skip a full cks-core validation round-trip for common cases by
reimplementing a subset of the rules directly in cks-mcp. Rejected: any
divergence between the fast-path and cks-core's actual rules becomes a
silent correctness bug, and cks-core's own evolution would require this
duplicate to be kept in sync by hand.
Session bookkeeping in cks-mcp
Track session state directly in the MCP server process instead of
delegating entirely to cks-runtime.Runtime. Rejected: this is exactly
the "Runtime-Embedded Semantics" pattern the ecosystem's Runtime Layering
ADR rejects one layer down, applied to cks-mcp instead of an adapter —
the reasoning transfers unchanged.
Rationale
Keeping cks-mcp thin means every consumer of cks-core/cks-runtime —
not just the MCP surface — benefits from correctness fixes and semantic
evolution in one place. The cost (occasionally needing an upstream change
instead of a local shortcut) is small compared to the alternative: a
translator that quietly becomes a second, divergent implementation of
rules that already exist.
Status
Accepted. New tools and features should extend cks-runtime/cks-core
when they need new semantic capability, and add to cks-mcp only the
translation and MCP-boundary concerns.