Skip to content

mocapi Constitution — Architectural Invariants

These are the load-bearing invariants of mocapi: the properties a change must not violate without a superseding ADR. This file is an index of invariants, not a restatement of the ADRs — each entry links its governing decision. Conduct rules (formatting, warnings, imports, workflow) live in ../CLAUDE.md; product direction lives in roadmap.md.

Changing an invariant means writing a new ADR (status Accepted) that supersedes the cited one, updating the affected design/ doc(s) in the same change, and updating the entry here.

Invariants

I1 — Stateless request model

Every request is self-contained: no sessions, no handshake, and no server-initiated request channel. Correlation state travels in the request envelope, not in server-held session state.

Scoped exception: the opt-in mocapi-tasks module confines all task state (status, ledger, result) behind the TaskStore SPI. Core stays byte-for-byte stateless when the module is absent; a client's tasks/* requests still carry their own correlation (taskId), so no server-initiated channel or handshake is introduced. → ADR-0019, ADR-0020, ADR-0037

I2 — Single protocol/transport coupling

McpServerMcpTransport is the only seam between the protocol layer and any transport. mocapi-server depends on no I/O framework (no Servlet API, no Spring MVC); transports own their wire-format validation and map results to their native error format. An extension module may still contribute to a transport's own validation table (e.g. RoutedParamContributor extending the Streamable HTTP Mcp-Name table) without the transport depending on that extension or ceding ownership of wire validation — the contribution contract is additive-only and the transport enforces every entry identically. → ADR-0002, ADR-0038, ADR-0039

I3 — Spec-compliance target

mocapi tracks the current MCP revision (2026-07-28) with a clean-break philosophy: features the same revision deprecates at introduction are not adopted. → ADR-0019, ADR-0022, ADR-0026

I4 — Module boundaries & packaging

The module split (api / model / server / transports / autoconfigure / observability / security / prompts) and its packaging rules are deliberate; dependencies flow one way and modules do not reach across their boundaries. → ADR-0001

I5 — Static handler discovery

Tools, prompts, and resources are discovered from annotated Spring components at startup. There is no dynamic registration and no list-changed / resource -update push; subscriptions/listen is answered as unimplemented. → ADR-0010

I6 — Declared not-implemented surface

The canonical "does mocapi do X?" list. Anything on it is a deliberate, rationale-backed omission; conformance tooling asserts against it. → ADR-0022

I7 — Model is 1:1 with the MCP schema

mocapi-model mirrors the MCP schema.ts shapes (params, results, shared data types); deprecated spec types stay as @Deprecated rather than being deleted. → ADR-0014

I8 — Authorization model

Bearer-token validation with mandatory audience enforcement, RFC 9728 Protected Resource Metadata, and the composable Guard SPI. These are the resource-server obligations mocapi guarantees. → ADR-0013, ADR-0012

I9 — Error-code allocation

mocapi-private JSON-RPC codes live only in the implementation-defined sub-range (-32000..-32019); spec-defined codes (-32020..-32099) are used verbatim, never reassigned. → ADR-0023