Skip to content

ADR-0004: Stateless MCP server (spec 2026-07-28) with layered approval

Context

MCP spec 2026-07-28 removed sessions and initialize; every request is self-describing, elicitation became multi-round-trip (input_required + retry with inputResponses), SSE is deprecated, Dynamic Client Registration is deprecated in favour of Client ID Metadata Documents. Cloudflare deprecated McpAgent in favour of createMcpHandler (one server per request).

Decision

packages/mcp-server uses @modelcontextprotocol/server 2.x, served on Workers via createMcpHandler (legacy: "reject"), wrapped by @cloudflare/workers-oauth-provider (OAuth 2.1, CIMD with DCR fallback). Scopes: site:read, site:write, site:publish, site:rollback. All cross-call state is carried by server-minted handles (snap_…, draft_…, pub_…) stored in D1/KV and re-authorized against the caller on every call — ids in the contracts follow the same prefixed form. Every tool declares outputSchema, returns structuredContent, sets honest annotations (destructiveHint: true only for publish/rollback/delete) and tools/list is deterministic. Approval is layered: policy engine → publish returns input_required with a diff summary → accept completes; hosts without elicitation use a confirm_token on a second call. Decisions are audit-logged.

Alternatives considered

Alternative Pros Cons Why not
McpAgent (Durable Object per session) Familiar, stateful Deprecated and feature-frozen Dead end
Legacy SDK 1.x with SSE Wider old-client support Deprecated transport, 12-month removal window Support legacy only via isLegacyRequest routing if demanded
Approval only in the host (Claude Code permission prompts) Zero server work Not every host gates; policy must hold without the host Defence in depth required

Consequences

  • Positive: scales horizontally, no session affinity, works from any MCP client.
  • Negative: more explicit handle plumbing; two approval paths to test.
  • Risks: host elicitation support is uneven in 2026; the confirm_token fallback must be first-class, not an afterthought.