modelcontextprotocol / modelcontextprotocol/kotlin-sdk
[Proposal] SEP-2567: Sessionless MCP via Explicit State Handles architecture & migration design (#814)
Nobody has claimed this yet.
- Dominant language
- Kotlin
- Stars
- 1.5k
- Forks
- 248
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 23
Description
Proposal: SEP-2567 Sessionless MCP via Explicit State Handles Architecture & Migration Design (#814)
Motivation & Context
Tracking implementation of SEP-2567 in kotlin-sdk for the 2026-07-28 MCP specification release (aligned with umbrella issue #842).
In earlier versions of the MCP specification, protocol sessions were represented via the Mcp-Session-Id transport header and server-side session tables. In practice, session-scoped state created severe architectural bottlenecks:
- Cache Invalidation & Redundant Round-Trips: The possibility that
tools/list,resources/list, orprompts/listmight vary per session forced clients and multi-agent orchestrators to re-fetch the entire catalog on every new connection ($O(\text{subagents} \times \text{servers})$ re-fetches), even when virtually no servers actually altered their list outputs dynamically per connection. - Rigid 1:1 Cardinality: Implicit session state prevented mixed shared/isolated state topologies (for instance, multiple subagents needing to share an authenticated workspace context while isolating execution handles or transaction sandboxes).
- Transport Fragility: Modern cloud load balancers and horizontal auto-scaling struggle with long-lived session affinity without sticky routing or distributed session replication.
SEP-2567 eliminates protocol-level sessions from MCP:
- No
Mcp-Session-Idheader is generated or required on the wire. tools/list,resources/list, andprompts/listMUST NOT depend on per-connection or prior-tool-call state; their outputs are strictly cacheable at(deployment, auth)granularity.- Stateful workflows transition to explicit, server-minted state handles (e.g.,
create_*() -> handlepassed into subsequent operations).
This proposal outlines the Kotlin Multiplatform architecture to transition kotlin-sdk (kotlin-sdk-core, kotlin-sdk-server, and kotlin-sdk-client) to a sessionless model.
Proposed Architecture & Component Design
1. Transport Header & Protocol Version Gating (kotlin-sdk-core)
In kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/:
- Protocol Version Negotiation:
For negotiated protocol version >=2026-07-28:Mcp-Session-Idis no longer emitted by client transports or parsed/required by server transports.- For backwards compatibility with legacy protocol versions (
< 2026-07-28), preserve optionalMcp-Session-Idextraction only when legacy protocol negotiation is explicitly active.
- Constant Deprecation:
@Deprecated( message = "Session IDs are removed in MCP spec 2026-07-28 per SEP-2567. Use explicit state handles instead.", level = DeprecationLevel.WARNING ) public const val MCP_SESSION_ID_HEADER: String = "Mcp-Session-Id"
2. Streamable HTTP Transport Refactoring (kotlin-sdk-server & Ktor integration)
- Per-Request Dispatch:
Currently,StreamableHttpServerTransportmaintains an internal session map keyed by session ID to dispatch messages to specificServerSessioninstances.- Transition the HTTP POST endpoint (
/mcpor custom path) to stateless, per-request request-response dispatch. - Incoming requests are executed directly against a shared
ServerRequestHandleror statelessServerSessioninstance without session lookup locks. - SSE or standalone notification streams (if negotiated for keep-alives or asynchronous task progress per SEP-2663) decouple from transport session IDs.
- Transition the HTTP POST endpoint (
- Ktor Extension Simplification:
// Clean, stateless Ktor routing route("/mcp") { post { serverTransport.handlePost(call) } }
3. Explicit State Handle Utilities (kotlin-sdk-core / kotlin-sdk-server)
To provide first-class ergonomics for servers that maintain domain or transaction state across calls:
- Provide an explicit state handle abstraction:
@Serializable @JvmInline public value class StateHandle(public val value: String) { public companion object { public fun generate(): StateHandle = StateHandle(uuid4().toString()) } } - State Handle Storage SPI:
This makes state lifetime explicit, observable, and easily backed by Redis, Memcached, or distributed storage when running multi-instance servers behind stateless load balancers.public interface StateStore<T> { public suspend fun get(handle: StateHandle): T? public suspend fun put(handle: StateHandle, state: T, ttl: Duration? = null) public suspend fun remove(handle: StateHandle): T? } public class InMemoryStateStore<T>( private val defaultTtl: Duration = 1.hours ) : StateStore<T> { ... }
4. Client-Side Catalog Caching & Multi-Agent Sharing (kotlin-sdk-client)
- Cross-Call Cache Reusability:
Becausetools/list,resources/list, andprompts/listare guaranteed not to mutate based on ephemeral connection handles, clients can safely cache catalog responses at the host/auth scope:public class McpCatalogCache( private val client: ClientSession, private val cacheTtl: Duration = 15.minutes ) { private val tools = atomic<ListToolsResult?>(null) public suspend fun getTools(forceRefresh: Boolean = false): ListToolsResult = ... } - Subagents and concurrent coroutines sharing the same credentials can reuse the identical cached catalog without issuing parallel
tools/listRPC calls.
5. Testing & Conformance Plan
- Unit Tests:
- Verify that
StreamableHttpClientTransportdoes not sendMcp-Session-Idwhen negotiating protocol version2026-07-28. - Verify that server accepts POST requests without
Mcp-Session-Idheader and correctly returns JSON-RPC responses. - Verify that legacy clients sending
Mcp-Session-Idunder< 2026-07-28continue to function without breakage.
- Verify that
- Conformance Scenarios:
- Validate against the sessionless conformance test suite in
modelcontextprotocol/conformanceverifying stateless HTTP POST handling and cache stability.
- Validate against the sessionless conformance test suite in
Next Steps
Upon review and consensus on the sessionless architecture:
- Deprecate
Mcp-Session-Idand remove mandatory session lookups inStreamableHttpServerTransport. - Add
StateHandleandStateStoreutilities inkotlin-sdk-server. - Enable cross-connection catalog caching in
kotlin-sdk-client. - Update unit tests and conformance suite integration.
AI assistance disclosure: AI was used to discover this opportunity and draft the change or text. The submission was checked against the prepared artifact and recorded verification evidence.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reviewing the transport and protocol-version code under kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/, then inspect StreamableHttpServerTransport and the Ktor integration in kotlin-sdk-server. Compare the listed unit-test and conformance scenarios for 2026-07-28 and legacy versions; done means the migration design is agreed and its core, server, client, and test changes are covered.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- kotlin
- Domain
- api, backend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100