ADR 0002: Optional MCP Operator Surface
Status
ProposedDate
2026-04-26Context
CrateStack v0 is designed as a Rust-native, schema-first framework layer that generates:- a SQLx-backed ORM
- REST CRUD endpoints
- custom procedure endpoints
- authorization enforcement
- codec and envelope based REST body handling
- CrateStack’s primary API direction is REST-only, no RPC.
- CrateStack’s primary transport direction avoids JSON assumptions.
- MCP itself is a separate protocol surface and is JSON-RPC based.
Decision
CrateStack will support an optional MCP operator surface. The MCP operator will be generated from the.cstack schema and will expose selected resources and tools to MCP-compatible clients.
The MCP operator is explicitly separate from the primary REST API.
CrateStack’s primary application API remains:
Terminology
MCP Resource
An MCP resource is a read-only data item exposed by the server for client context. In CrateStack, MCP resources may be generated from:- schema metadata
- selected model collections
- selected model records
- selected read-only procedure outputs
MCP Tool
An MCP tool is an invokable operation exposed by the server. In CrateStack, MCP tools should primarily be generated from schema-defined procedures. Optional CRUD-derived tools may be added later, but procedures are the preferred tool boundary.MCP Operator
The MCP operator is the generated server adapter that maps MCP resource and tool calls to CrateStack ORM and procedure operations while enforcing CrateStack authorization policies.Schema Design
MCP exposure should be explicit. Recommended initial schema syntax:Exposure Defaults
MCP exposure must be default-off. A model, procedure, or resource is not exposed to MCP unless explicitly annotated or included through a clear MCP block directive. Recommended v0 default:- exposed through MCP, and
- authorized by CrateStack permissions.
Permission Model
MCP must not bypass permissions.MCP Resource Permission
MCP resources derived from model data must enforce model read policies. Example:MCP Tool Permission
MCP tools derived from procedures must enforce procedure-level@allow before invoking the procedure implementation.
Example:
publish_post.
Procedure Internal Permissions
Procedure implementations still use normal policy-protected ORM APIs. No system bypass is introduced for MCP. The v0 rule remains:Generated Surface
When MCP support is enabled, the macro may generate:MCP Resource Mapping
For a model annotated as:- Schema metadata resources.
- Record-by-id resources for explicitly exposed models.
- Optional collection resources with limit enforcement.
MCP Tool Mapping
For a procedure annotated as:Authentication and Context
MCP does not replace CrateStack authentication delegation. The MCP integration must provide a way to constructCoolContext from the MCP session/request.
Potential context sources:
- OAuth/JWT claims supplied by the MCP transport layer
- server-side session identity
- local trusted identity for stdio deployments
- explicit anonymous context
Transport Considerations
CrateStack REST transport remains codec/envelope based and may use CBOR/COSE. MCP transport is separate. MCP may require JSON-RPC messages. This must not contaminate the REST codec architecture. Therefore:cratestack-codec-jsonremains optional for REST.- MCP support may depend on JSON internally as required by the MCP protocol.
- This JSON dependency must live in
cratestack-mcp, not incratestack-coreor REST codec crates.
Crate Layout
Add an optional crate:cratestack-mcp.
Schema Compiler Changes
The parser and semantic analyzer must support:mcpconfiguration block@@mcp.resource(...)model attribute@mcp.tool(...)procedure attribute
Security Requirements
- MCP exposure is opt-in.
- MCP resource reads enforce model read policies.
- MCP tools enforce procedure permissions.
- MCP tools do not bypass model policies inside procedure implementations.
- No
as_systemis introduced for MCP. - MCP collection resources must have strict default limits.
- MCP resource and tool descriptions must not leak sensitive schema details unless explicitly exposed.
- MCP must have an explicit auth/context extraction strategy.
- Local stdio MCP deployments must be treated carefully and not assumed safe by default.
- Generated MCP tool names must avoid collisions.
- Generated MCP resource URIs must avoid exposing internal database names unless explicitly configured.
- Dangerous procedures should require explicit
@mcp.toolannotation.
Consequences
Positive Consequences
- AI agents can discover and use CrateStack-backed capabilities automatically.
- Procedures become reusable across REST, local Rust calls, and MCP tools.
- Model read policies also protect MCP resources.
- MCP support does not disrupt the REST-first architecture.
- JSON remains out of the core REST codec layer.
- MCP dependencies stay isolated.
- CrateStack can support agent workflows without making RPC the primary product API.
Negative Consequences
- MCP introduces a second protocol surface.
- MCP is JSON-RPC based, which conflicts philosophically with the primary no-RPC/no-JSON direction.
- Additional security review is required.
- MCP tool exposure can create dangerous agent-accessible operations if annotations are too broad.
- Generated schema metadata could leak sensitive model structure if exposed carelessly.
- MCP clients may behave differently, requiring compatibility testing.
Alternatives Considered
Alternative 1: Do Not Support MCP
Rejected because MCP is valuable for agent-facing integration and can be generated from CrateStack’s schema and procedure metadata.Alternative 2: Treat MCP as the Primary API
Rejected because CrateStack’s primary API is REST with codec/envelope support. MCP is a separate agent-facing surface.Alternative 3: Automatically Expose All Procedures as MCP Tools
Rejected because this creates a high risk of accidental exposure. MCP tools must be explicit and default-off.Alternative 4: Automatically Expose All Models as MCP Resources
Rejected because this may leak data and schema structure. Model MCP resources must be explicit and policy-protected.Alternative 5: Reuse REST Routes for MCP
Rejected because MCP has its own discovery and invocation semantics. It should be implemented as a separate adapter over the same CrateStack ORM/procedure layer, not as a wrapper over REST endpoints.Decision Drivers
- Preserve REST-first architecture.
- Preserve CBOR/COSE primary API support.
- Enable agent-native integrations.
- Keep MCP optional and isolated.
- Reuse procedures as the safest tool boundary.
- Enforce default-deny permissions.
- Avoid accidental data/tool exposure.
- Avoid contaminating core with MCP-specific JSON-RPC dependencies.
Follow-Up Work
- Select MCP Rust SDK or decide to implement protocol bindings directly.
- Define exact
.cstackMCP syntax. - Define generated MCP resource URI scheme.
- Define MCP tool naming rules.
- Define MCP context extraction strategy.
- Define collection resource limits.
- Add MCP section to the PRD.
- Add MCP dependencies to the dependency decision log.
- Add MCP security test plan.
- Add compatibility tests with at least one MCP client.