Skip to content

SEP-2822 Client Generated Session ID#2822

Closed
javapro108 wants to merge 10 commits into
modelcontextprotocol:mainfrom
javapro108:main
Closed

SEP-2822 Client Generated Session ID#2822
javapro108 wants to merge 10 commits into
modelcontextprotocol:mainfrom
javapro108:main

Conversation

@javapro108

@javapro108 javapro108 commented May 30, 2026

Copy link
Copy Markdown

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

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

@javapro108 javapro108 changed the title SEP Client Generated Session ID SEP-2822 Client Generated Session ID May 30, 2026
@javapro108 javapro108 requested review from a team as code owners May 30, 2026 20:38
@javapro108

Copy link
Copy Markdown
Author

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.
Thank You!

@localden

Copy link
Copy Markdown
Contributor

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.

@javapro108

Copy link
Copy Markdown
Author

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.

@kurtisvg

kurtisvg commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

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

@Agent-Hellboy

Agent-Hellboy commented Jun 2, 2026

Copy link
Copy Markdown

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.
I uses Mcp-Client-Session-Id to grant sessions to my agents.
if the spec formalize this, gateway might support this and in future i can use an available gateway.

@Agent-Hellboy

Agent-Hellboy commented Jun 2, 2026

Copy link
Copy Markdown

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.

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.

@LucaButBoring

Copy link
Copy Markdown
Contributor

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.

@AgentGymLeader

Copy link
Copy Markdown

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.

@bittola

bittola commented Jun 4, 2026

Copy link
Copy Markdown

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 Mcp-Session-Id and need to replicate it without breaking the stateless direction the spec is moving toward.

The server-minted handle pattern that #2567 implies (workflow_id threaded via x-mcp-header) inherits the same problems SEP-2567 originally raised against Mcp-Session-Id: cardinality questions (who mints, when to replace, behavior across sub-agents and forking), reliance on the LLM to thread the value correctly, and the bootstrap on top - parallel first calls from a host pipeline land on different instances, each mints its own workflow_id, and the conversation ends up with split state across instances.

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 traceparent precedent is the right framing. Header-only, client-originated, no server obligation, no protocol state. Servers that need routing get a hook; servers that don't are unaffected.

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.

@AgentGymLeader

Copy link
Copy Markdown

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.

@javapro108

javapro108 commented Jun 7, 2026

Copy link
Copy Markdown
Author

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?

  • Observability. No standard field to correlate requests for a workflow in logs or audit trails. Every deployment solves this ad hoc today.

  • Routing affinity. AWS Bedrock AgentCore (VM isolation) and Microsoft Dynamics 365 F&O (process-local form state) both need a stable ID present on the very first request. Explicit state handles can't solve this — if the host fires parallel tool calls at startup, no server response exists yet, so no handle has been issued. Split state before the LLM has done anything.

  • Tool/resource/prompt scoping. Without a stable identifier, servers return the full catalog on every request regardless of what the current unit of work needs. This doesn't scale when a server has tens or hundreds of tools — static catalogs bloat context and this is well-documented:

    • RAG-MCP (arxiv 2505.03275) measured tool selection accuracy at 13.62% baseline when exposing a large MCP pool, rising to 43.13% with targeted tool selection — a 3x improvement — while cutting prompt tokens by over 50%. Performance drops sharply beyond 100 tools, empirically establishing targeted selection as mandatory rather than optional at scale
    • The "Less is More" study (arxiv 2411.15399) showed that simply reducing tools from 46 to 19 turned a failing task into a successful one with no other changes
    • UC Berkeley's Gorilla project (NeurIPS 2024, Patil et al.) demonstrated that LLMs hallucinate and fail at accurate API calls at scale, motivating retrieval-augmented approaches as a necessary mitigation (arxiv 2305.15334)
    • Independently reported: Already raised in the MCP community: SEP-1576, SEP-1300, and Discussion #1567 — all independently converging on the need for server-side primitive scoping and filtering

    The draft caching spec (/specification/draft/server/utilities/caching) is complementary to this problem space. It defines cacheScope as "public" or "private" — scoped to all users or to an authorization context respectively. A third scope — "context" — would naturally complete this model: same user, same authorization, but different logical unit of work. That dimension is currently unaddressable: a server wanting to return different tool surfaces for different conversations from the same authenticated user has no cache scope to express it. This PR is out of scope to modify the caching spec, but flagging the connection as the two problems are closely related.

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.

  • A2A defines contextId as an identifier that logically groups related tasks and messages across a series of interactions.
  • Clients may provide a client-generated value, agents may accept and preserve it, and the semantics are deliberately flexible.
  • Agents MAY use the contextId to maintain internal state, conversational history, or LLM context across multiple interactions - enabling the "context" cache scope described above.

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.

@AgentGymLeader

AgentGymLeader commented Jun 7, 2026

Copy link
Copy Markdown

@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.

@localden localden added SEP draft SEP proposal with a sponsor. labels Jun 8, 2026
@localden localden added the proposal SEP proposal without a sponsor. label Jun 8, 2026
@kurtisvg

kurtisvg commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

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.

@kurtisvg kurtisvg closed this Jun 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

proposal SEP proposal without a sponsor. SEP

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

7 participants