Migrating to v0.12 Stateless MCP¶
This page preserves the historical migration reference for upgrading from v0.11.x stateful session/SSE transports to the v0.12.0 stateless MCP 2026-07-28 architecture (io.modelcontextprotocol/tasks, MCPInputRequiredResult, and subscriptions/listen).
Dual-Version Compatibility in v0.17.0+
While v0.12.0 through v0.16.x accepted only 2026-07-28 (server/discover), v0.17.0 added dual-version stateless Streamable HTTP negotiation on /mcp. Current releases (v0.17.0+) serve both 2026-07-28 (server/discover + SEP-2575 headers) and 2025-06-18 / 2025-03-26 (initialize, notifications/initialized, ping, and DELETE /mcp) on the same stateless endpoint. See Migrating to v0.14–v0.18 and Dual-Version Discovery for current protocol negotiation details.
1. Stateless MCP 2026-07-28 Transport¶
When targeting the 2026-07-28 protocol revision:
- Send one independent
POST /mcprequest per JSON-RPC operation; no server-sideMcp-Session-Idstate orLast-Event-IDreplay buffer is required. - Pass protocol version, client capabilities, and optional client identity inside
params._meta(io.modelcontextprotocol/protocolVersion,io.modelcontextprotocol/clientCapabilities,io.modelcontextprotocol/clientInfo) on every request. - Send matching SEP-2575 routing headers:
MCP-Protocol-Version: 2026-07-28Mcp-Method: <jsonrpc-method>Mcp-Name: <target-name-or-uri>fortools/call,resources/read,prompts/get,tasks/get,tasks/update, andtasks/cancel.- Use the
=?base64?<urlsafe-base64>?=encoding sentinel for header values containing non-ASCII or control characters. - Call
server/discoverfor stateless capability discovery.
2. MCPConfig Stateless Transport Settings¶
v0.12.0 removed the legacy stateful session and idle-stream settings (session_store, session_max_idle_seconds, sse_max_streams, and sse_max_idle_seconds) and replaced them with stateless caching and subscription stream controls:
"""Snippet: stateless MCP transport defaults."""
from litestar_mcp import MCPConfig
config = MCPConfig(
cache_ttl_ms=0,
cache_scope="private",
subscription_max_streams=10_000,
subscription_keepalive_seconds=15,
)
allowed_originsis an exact additional allowlist ofOriginvalues accepted alongside the request's own origin. Requests without anOriginheader remain valid; requests with an untrustedOriginheader are rejected with HTTP403 Forbidden.
3. MCP Tasks Extension (io.modelcontextprotocol/tasks)¶
Background task execution moved to the opt-in io.modelcontextprotocol/tasks extension configured via MCPConfig(tasks=True) or MCPConfig(tasks=MCPTaskConfig(...)):
- Clients opt into task-augmented execution per request by passing
params.task(and advertising"io.modelcontextprotocol/tasks": {}in client capabilities). - Replace legacy
tasks/resultandtasks/listcalls with: tasks/get: Poll the currentTaskRecordstatus (working,input_required,completed,failed,cancelled) and terminal result.tasks/update: Supply interactiveinputResponseswhen a task is paused instatus == "input_required".tasks/cancel: Request cooperative cancellation of an in-flight task.task_support("optional","required","forbidden") is enforced as a server-side policy on each tool:"optional"tools execute as a background task whenparams.taskis provided, or fall back to synchronous execution when omitted."required"tools reject calls that do not opt intoio.modelcontextprotocol/taskswith JSON-RPC error-32021(MISSING_REQUIRED_CLIENT_CAPABILITY).
4. Multi-Round-Trip Requests (MRTR) & MCPInputRequiredResult¶
Tools, resources, and prompts can pause to collect interactive client input by returning MCPInputRequiredResult(input_requests=..., request_state=...):
- When the client retries the call (or submits
tasks/updateon aninput_requiredtask), readget_mcp_request_context().input_responsesandget_mcp_request_context().request_state. - Because
requestStateis round-tripped through the client, protect any authorization-sensitive state with AEAD or HMAC-SHA256 bound to the authenticated principal (owner_id), original method/arguments, and an expiration timestamp. - Never treat
clientInfoas an authorization identity. See Authorization, Guards, Scopes & Input Safety for a complete HMACrequestStatesealing example.
5. Caching Hints & subscriptions/listen¶
- Cache Metadata (
ttlMs&cacheScope): Discovery (server/discover), catalog list (*/list), andresources/readresults includettlMs(MCPConfig.cache_ttl_ms) andcacheScope(MCPConfig.cache_scope, defaulting to"private"). - Multiplexed SSE Subscriptions (
subscriptions/listen): Clients subscribe to catalog list changes, resource URIs, or task status updates over a singlePOST /mcp(method: "subscriptions/listen") Server-Sent Events stream: - The initial SSE event acknowledges the accepted filter and assigns a subscription ID.
- Subsequent
notifications/tasks,notifications/resources/updated, andnotifications/*_list_changedframes carry the subscription ID. - Active streams emit periodic keepalive comments (
MCPConfig.subscription_keepalive_seconds=15.0) and fan out across multi-worker deployments whenMCPConfig.subscription_channelsis bound to a LitestarChannelsPluginbackend.