SEP-2822 Client Generated Session ID#2822
Conversation
Initial Draft
Create 0000-client-generated-session-id.md
…generated-session-id.md
|
Hi There, This is my first pull on public repo. Please excuse me if there are any mistakes OR let me know if I can fix any issues. |
|
Thanks for the contribution! This does feel counter the current direction of the protocol. We explicitly wanted to make it stateless/sessionless, and this PR inverts that decision. @CaitieM20 and @kurtisvg to chime in as well. |
|
Thank you for the quick feedback — the concern makes complete sense given where the protocol is headed. The objective is to stay aligned with stateless server architecture. A server that wants to remain fully stateless can treat this purely as a log tag for troubleshooting and audit — no handshake, no stored session, nothing changes on the server side. The two patterns I was drawing from are already in the RC: traceparent from SEP-414 is a client-originated value in _meta with no server obligation, and this follows the same idea. Similarly, clients that authenticate already hold a bearer token for the duration of a conversation — the proposal is just one UUID riding alongside that, generated by the client, with no round-trip needed. If "session" is the wrong framing — and it probably is — I'm happy to rename throughout. "Correlation scope", "client context ID", or whatever fits the existing vocabulary better. Happy to revise if this is worth exploring further. |
|
I would encourage you to bring the PR to the Transports WG for discussion. I believe the preffered path for contributing is through a WG. There are a few other folks asking about sessions, it would be good to group them: https://github.com/modelcontextprotocol/transports-wg |
|
Hi everyone, I also have a use case for this. Currently, I am putting an adapter above the client that forwards this header, and my custom gateway understands it. |
No , it's a right naming. It's like giving session identity different form agent and user identity , it's different then user and agent, it's like giving a session identifier to anyone either user or agent. |
|
We have a use case for this in Bedrock AgentCore (docs, API ref) - on the current spec, we do VM isolation (customer MCP servers run inside VMs; we don't mandate their implementation details) according to the session ID which doubles as a form of sticky sessions, and that session ID that can be either client- or server-generated (we recommend a client-generated one). If no session ID is ever provided, we create a new VM on every request, which adds a fair bit of latency to each call. We can't use explicit state handles as proposed by #2567 without doing some kind of deep proxy to reshape all customer tools to support handles as parameters, which I'm not sure how we would do reliably. We're still figuring out what exactly the right way to handle this should be, and having something like this would be very beneficial for us. |
|
This use case is helpful because it separates two concerns that can get conflated: protocol state on the MCP server versus a client-supplied correlation/runtime-isolation key used by infrastructure around the server. I would be cautious about standardizing this as a general session primitive, given the stateless direction called out above. But there may be room for the Transports WG to consider whether a transport-level correlation key belongs in the metadata, with no server obligation to store state and no semantics beyond routing, isolation, or log correlation. That framing might let deployments like Bedrock AgentCore address isolation while preserving the protocol's stateless/sessionless posture. |
|
Adding a use case in support of this proposal. Continuing from the thread on #2567 : we run the stateful MCP server for Dynamics 365 Finance and Operations that @vanya-lebedev described earlier in that thread. Server-side form workflows require sticky routing to a specific backend instance because the form state is process-local. We had this with The server-minted handle pattern that #2567 implies (workflow_id threaded via x-mcp-header) inherits the same problems SEP-2567 originally raised against Deployment-layer routing on identity doesn't fix this either at our scale. A single user identity can have hundreds of agents in parallel, each in its own workflow. Routing all of them to the same instance to preserve workflow affinity would create per-user hot-spots and defeat horizontal scaling. What we actually need is exactly what this PR proposes: a stable, client-generated, per-workflow identifier present on every request including the first. Server-optional usage (log tag, audit, routing, ignore) matches our pattern - we'd use it for routing while staying spec-compliant for clients that don't care. The For broader reference, this is essentially how browser-based stateful apps have handled sticky routing for decades - HTTP cookies set by the gateway (Azure ARR or similar) and auto-echoed by the browser. That pattern works because the first HTTP request is naturally serialized (one page load before anything else); the cookie gets set on that response and propagates to all subsequent parallel requests. MCP hosts don't have that natural serialization point - some pipeline tool calls in parallel from the start - which is why client-minted (rather than server-set) is the right shape here. For prioritization context: without a protocol-level mechanism the parallel-first-call failure surfaces as flaky agent workflows in production. We can apply client-side mitigations (tool descriptions discouraging pipelining, etc.) but can't fully prevent it. F&O is part of the Dynamics 365 platform deployed across tens of thousands of enterprise organizations, so the impact lands at meaningful scale. Happy to share specifics in the Transports WG if useful. |
|
This Dynamics example seems like a useful concrete data point for the Transports WG discussion. The part I would preserve is the same boundary as above: not a general session primitive and not protocol state on the MCP server, but a client-originated correlation/runtime-isolation key that infrastructure can use before the first tool call. The bootstrap case here is important because a server-minted workflow handle cannot help if parallel first calls have already been routed to different instances. So the narrow question may be whether transports need an optional, server-ignorable correlation metadata slot with traceparent-like properties: client-originated, present from the first request, no server storage obligation, and no semantics beyond routing, isolation, or log correlation. |
|
Thank you @kurtisvg, @LucaButBoring, @bittola, @Agent-Hellboy, @AgentGymLeader, @localden for your feedback and recommendations. Based on the discussion here and in the Transports WG, summarizing the core problem — focusing on the gap rather than the solution for now. The gap: When a host dispatches requests through multiple clients simultaneously, servers have no standard way to know those requests belong together. None of the current per-request fields answer: which logical unit of work does this request belong to?
While exploring how other protocols handle this, A2A has a dedicated section that aligns closely with what this PR proposes: A2A spec §3.4.1.
MCP and A2A are increasingly deployed together in agentic pipelines. Having no equivalent primitive in MCP creates an interoperability gap and forces every deployment to reinvent what A2A has already standardized. A2A's approach of leaving scope flexible while standardizing the carrier may be worth exploring. Happy to reshape the PR around this problem framing if that's more useful. |
|
@javapro108 nice writeup. Framing it as the gap instead of "session id" is the right move. The bit I'd hold onto while reshaping: a client-set correlation id the server can just ignore — no stored state, traceparent-style, there from the first request. Standardize the carrier, leave the scope loose like that A2A contextId you pointed to. That's the version that won't bite people later. |
|
Hey folks -- appreciate the interest on this topic. Currently the recommended path for SEPs is to go through working groups instead of proposing them directly to the spec. This allows for some level of refinement and input from the community before they are proposed to the Core Maintainers. The transport working group has already spent a fair amount of time discussing sessions, and I think is the best group to carry this discussion forward. As such, I think we should move this discussion to https://github.com/modelcontextprotocol/transports-wg and the weekly transport group meetings (you can find info on the next one at meet.modelcontextprotocol.io). Previously, there has been a lot of ambiguity around sessions and their use-cases. Feedback from the Core Maintainers was that none of the previously presented use-cases were compelling enough to warrant the complexity from having a logical session. I've opened this issue here to collect use-cases around sessions and form a concrete problem statement. I think the important first step is making sure we clearly define the scope of what sessions should have. Please re-direct feedback to that issue. |
Adds Mcp-Client-Session-Id — a client-generated ID that flows on every request
within a logical conversation context, carried as an HTTP header on Streamable HTTP
transports and in params._meta for all other transports. Servers may use it for
log correlation, audit, dynamic tool scoping, or ignore it entirely. No server
obligation, no protocol state, no breaking changes.
Motivation and Context
The 2026-07-28 RC removes transport-level sessions (SEP-2567, SEP-2575)
but leaves no standard way for clients to group related requests together.
It creates some gaps for observability, audit and server requiring sessions / context. When a multi-step agent workflow fails, there is no standard way to pull all requests for that workflow from logs or audit trails.
This proposal adds no protocol state and no server obligation — just a minimal client-generated primitive that makes stateless deployments observable and gives servers a reliable key to work with if they need one.
How Has This Been Tested?
Additional change in specification.
Breaking Changes
None
Types of changes
Checklist
Additional context