SEP-2567: Sessionless MCP via Explicit State Handles — rust-sdk implementation
Spec PR: modelcontextprotocol/modelcontextprotocol#2567
Track: Specification · Stage: final · Priority: P0 · Theme: Transport Evolution and Scalability
Needs code changes: Yes (Large)
Summary
Removes protocol-level sessions, replacing implicit session-scoped state with explicit,
server-minted state handles. Builds on SEP-1442 (stateless-by-default) but argues the opt-in
stateful path should not exist at all.
What changes:
- No
session/create, session/destroy, or Mcp-Session-Id header.
tools/list / resources/list / prompts/list MUST NOT depend on per-connection or prior-tool-call state (so list endpoints become cacheable at (deployment, auth) granularity).
- Stateful workflows use
create_*() -> handle + threaded parameters (guidance, not a protocol construct).
Why this needs code changes in rust-sdk
The streamable HTTP transport mints and threads a session id today, but a disable path already
exists:
- Server:
StreamableHttpServerConfig.stateful_mode (default true); when false the server "disables sessions entirely (stateless mode)" per the doc comment, backed by the SessionManager/SessionStore trait (session.rs, with Local…/Never… stores and RestoreOutcome/SessionRestoreMarker). The session id rides on HEADER_SESSION_ID.
- Client:
streamable_http_client.rs carries session_id: Arc<str> through requests and SSE reconnects.
- List handlers live behind
service/server.rs + handler/server/router.rs.
So "no sessions" is partly reachable via stateful_mode = false. The remaining work is: making that
path the default/clean one for V_2026_07_28, ensuring list endpoints are state-independent, and
removing the client's hard dependency on a session id.
Proposed work
Affected areas
transport/streamable_http_server/session.rs, transport/streamable_http_server/tower.rs,
transport/streamable_http_client.rs, service/server.rs, handler/server/router.rs.
Notes / risks
- Overlaps heavily with SEP-2575. Treat as one transport-statelessness workstream; this SEP is the application-state half, 2575 is the handshake half.
- Making client
session_id optional touches several Arc<str> call sites in streamable_http_client.rs (reconnect/get-stream paths) — mechanical but broad.
Related existing issues
SEP-2567: Sessionless MCP via Explicit State Handles — rust-sdk implementation
Spec PR: modelcontextprotocol/modelcontextprotocol#2567
Track: Specification · Stage: final · Priority: P0 · Theme: Transport Evolution and Scalability
Needs code changes: Yes (Large)
Summary
Removes protocol-level sessions, replacing implicit session-scoped state with explicit,
server-minted state handles. Builds on SEP-1442 (stateless-by-default) but argues the opt-in
stateful path should not exist at all.
What changes:
session/create,session/destroy, orMcp-Session-Idheader.tools/list/resources/list/prompts/listMUST NOT depend on per-connection or prior-tool-call state (so list endpoints become cacheable at(deployment, auth)granularity).create_*() -> handle+ threaded parameters (guidance, not a protocol construct).Why this needs code changes in rust-sdk
The streamable HTTP transport mints and threads a session id today, but a disable path already
exists:
StreamableHttpServerConfig.stateful_mode(defaulttrue); whenfalsethe server "disables sessions entirely (stateless mode)" per the doc comment, backed by theSessionManager/SessionStoretrait (session.rs, withLocal…/Never…stores andRestoreOutcome/SessionRestoreMarker). The session id rides onHEADER_SESSION_ID.streamable_http_client.rscarriessession_id: Arc<str>through requests and SSE reconnects.service/server.rs+handler/server/router.rs.So "no sessions" is partly reachable via
stateful_mode = false. The remaining work is: making thatpath the default/clean one for
V_2026_07_28, ensuring list endpoints are state-independent, andremoving the client's hard dependency on a session id.
Proposed work
stateful_mode = falseserver path neither requires nor emitsHEADER_SESSION_ID, and verify theNever…-store path is the one selected.tools/list/resources/list/prompts/listhandlers (handler/server/router.rs) so results don't depend on per-connection or prior-call state in the sessionless path (precondition for the SEP-2549 caching story).session_idoptional (Option<Arc<str>>) so it can operate without one when the negotiated version isV_2026_07_28; keep sending it for older negotiated versions.HEADER_SESSION_IDhandling for back-compat behind older protocol versions.create_*() -> handlepattern (state handles are app-level, not a protocol construct).Affected areas
transport/streamable_http_server/session.rs,transport/streamable_http_server/tower.rs,transport/streamable_http_client.rs,service/server.rs,handler/server/router.rs.Notes / risks
session_idoptional touches severalArc<str>call sites instreamable_http_client.rs(reconnect/get-stream paths) — mechanical but broad.Related existing issues
Mcp-Session-Id(sessionless work changes how session identity is surfaced)