You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This proposal establishes sessions as a first-class protocol concept in MCP, providing message ID uniqueness boundaries, state management, and continuity capabilities independent of transport mechanisms. Currently, sessions exist only in the HTTP transport specification, creating ambiguity about session boundaries and message ID uniqueness for other transports. This proposal defines logical sessions at the protocol layer while allowing transports to manage connections as needed.
Motivation
Currently, sessions exist only in the HTTP transport specification, leaving gaps:
No protocol-level session definition
Unclear session boundaries for stdio transport
No protocol-level termination mechanism
Ambiguous separation between transport connections and logical sessions
Issue #984 highlights conflicting interpretations: sessions as transport state vs. sessions as application context. This proposal resolves the ambiguity by defining logical sessions at the protocol layer while allowing transports to manage connections as needed.
Specification
Session Definition
A session is a bounded sequence of client-server interactions that:
Begins with successful initialization
Maintains a unique namespace for message IDs
Preserves negotiated capabilities and protocol version
Ends explicitly (termination) or implicitly (invalidation)
Sessions are optional - stateless servers need not implement them.
Other error conditions should use standard JSON-RPC error codes as defined in the JSON-RPC specification.
Session Lifecycle
stateDiagram
Start --> Active: Initialize (server returns new session id)
Active --> End: Server expires ("invalid session" response)
Active --> End: Client terminates (session/terminate)
Loading
Operations
Create: InitializeRequest → server MAY return sessionId in InitializeResult
Use: Both parties include sessionId in all subsequent messages
Validate: Server validates sessionId on each message, returns error if invalid
Terminate:
Client: sends session/terminate request
Server: returns invalid session error
Re-initialize: On invalid session error, client sends new InitializeRequest (creates new session)
Message ID Uniqueness
Message IDs must be unique within specific boundaries:
Scope: Client and server maintain separate ID spaces (IDs are unique per-party, not globally)
Session Boundary: New sessions start with fresh message ID namespaces
Continuity: Within a session, message IDs must be unique across the session's entire lifetime
Implementation: Each party (client/server) is responsible for ensuring uniqueness of IDs in messages they originate
Example:
Client sends requests with IDs: 1, 2, 3...
Server sends requests with IDs: 1, 2, 3...
After session ends and new one begins, both start fresh ID sequences
Transport Mapping
The protocol defines logical session semantics. Transports implement these semantics as appropriate:
HTTP Transport
Maps protocol sessions to the existing Mcp-Session-Id header system
Session validation occurs on each request via headers
Stdio Transport
Process lifetime typically bounds session
MAY persist sessions externally for continuity across process restarts
Custom Transports
MAY implement stateless operation (ignore session fields)
MUST preserve message ID uniqueness per logical session
Note: HTTP header requirements
While sessions are protocol-level concepts, HTTP transport still requires headers in specific cases:
GET requests (SSE streams): SessionId must be included in Mcp-Session-Id header since GET requests contain no protocol message content where sessionId could be included.
Servers supporting old protocol versions MUST include sessionId in headers for backward compatibility when communicating with clients at those protocol versions:
DELETE requests (session termination): SessionId included in Mcp-Session-Id header for backward compatibility with existing HTTP transport session termination mechanism.
POST requests: SessionId included in Mcp-Session-Id header for backward compatibility with existing HTTP transport session termination mechanism.
The situation may be analogous for future transports, where session information is needed before/after protocol messages are flowing between client and server.
Rationale
Design Decisions
Continuous validation vs explicit resumption
We considered an explicit session/resume request but decided against it because:
Current HTTP transport specification uses continuous validation successfully
Couldn't come up with compelling use cases for the extra information that an explicit 'session/resume' might carry (e.g., capability renegotiation)
*Note: @jonathanhefner cites client wanting to enable sampling mid-session as an example of such a use case. Decision becomes one of cost/benefit.
Simpler mental/state management model
For authorization, matches proven patterns in gRPC, cloud APIs where tokens refresh transparently
Session status queries vs implicit validation
We considered adding a session/status method to allow clients to check session validity before making requests, but decided it was sufficient for clients to simply consider a session valid until receiving an invalid/expired session error from the server (or terminating the session explicitly). This approach:
Reduces protocol complexity
Matches existing HTTP transport behavior
Avoids race conditions between status checks and actual requests
Follows the principle that the authoritative source of session validity is the server's response to actual requests
Session capability discovery
We considered adding a sessions field to ServerCapabilities but decided against it because:
No compelling use cases for knowing session support before connecting
Adds version-conditional logic complexity (servers must omit the field in older protocol versions)
Session support is immediately discoverable via sessionId presence in InitializeResult
Follows the principle of preferring immediate discovery over advance advertisement when the information isn't actionable
Protocol-level vs wire-level session placement
SessionId is placed in the protocol message types (Request, Notification, Result) rather than the JSON-RPC envelope because:
Sessions are a protocol concept, not a transport/wire format concern
Protocol handlers naturally receive sessionId with the message content
Transport independence - sessionId travels with protocol semantics regardless of wire format
Cleaner inheritance - SessionTerminateRequest naturally has sessionId via Request
No need for "envelope extraction" or type casting in handlers
Unified vs separate session types
Issue #984 distinguished between "transport sessions" (communication state) and "logical sessions" (shared context). We considered creating separate session types for these different concerns but decided a single unified session concept is cleaner and sufficient. Our unified sessions serve both purposes:
Maintain protocol negotiation state (addressing transport session needs)
Provide conversation context boundaries (addressing logical session needs)
Remain independent of transport connections while allowing transport-specific implementations
This proposal directly addresses the concerns raised in Issue #984:
Logical vs Transport Sessions: Rather than creating two separate session types, this proposal unifies the concepts - a single session definition serves both transport state and logical context needs while remaining independent of transport connections.
Message ID uniqueness boundaries: Sessions explicitly define message ID uniqueness boundaries with clear scoping rules.
Out-of-band requests: Server-initiated requests (elicitation, sampling) work naturally within sessions with servers including sessionId to support future multi-session scenarios.
Backward Compatibility
Protocol-level sessions are defined as part of a new protocol version, ensuring backward compatibility through MCP's standard protocol version negotiation mechanism:
New Client + Old Server: If an old server doesn't support the new protocol version, negotiation will fall back to the highest mutually supported version (without protocol-level sessions).
Old Client + New Server: If an old client doesn't understand the new protocol version, the server will negotiate down to a supported version (without protocol-level sessions).
Same Protocol Version: When both parties support the session-enabled protocol version:
Optional sessionId fields allow sessionless interaction for stateless servers
Session support discovered via sessionId presence in InitializeResult
Clients can ignore session features if not needed
Optional fields also provide type definition reuse convenience across protocol versions.
The optionality of sessionId serves operational purposes (enabling sessionless servers) and convenience (type definition reuse), rather than being the primary backward compatibility mechanism - that role is filled by protocol version negotiation.
Reference Implementation
A reference implementation will be provided demonstrating:
Protocol-level session support in client and server
Session timeout handling
Error handling for invalid sessions
Integration with existing HTTP transport session mechanics
Sessions MUST NOT be used for authentication: Session IDs identify conversation context only. Every request with authorization requirements MUST include valid authentication credentials independently of any session ID.
All requests MUST be verified: For servers that implement authorization, every inbound request must have its authorization validated, regardless of session ID.
Session IDs SHOULD be bound to users: Servers should combine session IDs with user-specific information to prevent session hijacking. The user ID is derived from the authorization token, not provided by the client.
Secure session ID generation: Session IDs MUST use cryptographically secure random generation to prevent guessing attacks.
Authorization context changes: If the authenticated principal changes, servers MUST invalidate the session to maintain security boundaries.
Token Expiry and Re-authentication
When authorization tokens expire during an active session:
Clients SHOULD obtain refreshed credentials and continue using the same session ID
Servers MUST validate the refreshed credentials normally
If refreshed credentials represent the same principal, the session continues
If refreshed credentials represent a different principal, the session MUST be invalidated
Authorization-Session Relationship
Sessions and authorization serve complementary purposes:
Authorization (Transport Level): Validates identity and permissions on every request
Sessions (Protocol Level): Maintains conversation state and message ID boundaries
This separation ensures that session state never bypasses security requirements while enabling stateful conversation management.
SEP: Protocol-Level Sessions for MCP
Preamble
Abstract
This proposal establishes sessions as a first-class protocol concept in MCP, providing message ID uniqueness boundaries, state management, and continuity capabilities independent of transport mechanisms. Currently, sessions exist only in the HTTP transport specification, creating ambiguity about session boundaries and message ID uniqueness for other transports. This proposal defines logical sessions at the protocol layer while allowing transports to manage connections as needed.
Motivation
Currently, sessions exist only in the HTTP transport specification, leaving gaps:
Issue #984 highlights conflicting interpretations: sessions as transport state vs. sessions as application context. This proposal resolves the ambiguity by defining logical sessions at the protocol layer while allowing transports to manage connections as needed.
Specification
Session Definition
A session is a bounded sequence of client-server interactions that:
Sessions are optional - stateless servers need not implement them.
Protocol Changes
New Types
Modified Messages
Session Timeout Semantics
The
sessionTimeoutfield in InitializeResult is advisory:New Methods
Error Handling
Invalid session errors use standard JSON-RPC error format with MCP-defined error code:
{ "jsonrpc": "2.0", "error": { "code": -32003, "message": "Invalid or expired session", "data": { "sessionId": "abc123" } }, "id": null }Other error conditions should use standard JSON-RPC error codes as defined in the JSON-RPC specification.
Session Lifecycle
stateDiagram Start --> Active: Initialize (server returns new session id) Active --> End: Server expires ("invalid session" response) Active --> End: Client terminates (session/terminate)Operations
Message ID Uniqueness
Message IDs must be unique within specific boundaries:
Example:
Transport Mapping
The protocol defines logical session semantics. Transports implement these semantics as appropriate:
HTTP Transport
Stdio Transport
Custom Transports
Note: HTTP header requirements
While sessions are protocol-level concepts, HTTP transport still requires headers in specific cases:
Mcp-Session-Idheader since GET requests contain no protocol message content where sessionId could be included.Servers supporting old protocol versions MUST include sessionId in headers for backward compatibility when communicating with clients at those protocol versions:
DELETE requests (session termination): SessionId included in
Mcp-Session-Idheader for backward compatibility with existing HTTP transport session termination mechanism.POST requests: SessionId included in
Mcp-Session-Idheader for backward compatibility with existing HTTP transport session termination mechanism.The situation may be analogous for future transports, where session information is needed before/after protocol messages are flowing between client and server.
Rationale
Design Decisions
Continuous validation vs explicit resumption
We considered an explicit
session/resumerequest but decided against it because:Session status queries vs implicit validation
We considered adding a
session/statusmethod to allow clients to check session validity before making requests, but decided it was sufficient for clients to simply consider a session valid until receiving an invalid/expired session error from the server (or terminating the session explicitly). This approach:Session capability discovery
We considered adding a
sessionsfield to ServerCapabilities but decided against it because:Protocol-level vs wire-level session placement
SessionId is placed in the protocol message types (Request, Notification, Result) rather than the JSON-RPC envelope because:
Unified vs separate session types
Issue #984 distinguished between "transport sessions" (communication state) and "logical sessions" (shared context). We considered creating separate session types for these different concerns but decided a single unified session concept is cleaner and sufficient. Our unified sessions serve both purposes:
Related Work
Response to Issue #984
This proposal directly addresses the concerns raised in Issue #984:
Logical vs Transport Sessions: Rather than creating two separate session types, this proposal unifies the concepts - a single session definition serves both transport state and logical context needs while remaining independent of transport connections.
Message ID uniqueness boundaries: Sessions explicitly define message ID uniqueness boundaries with clear scoping rules.
Out-of-band requests: Server-initiated requests (elicitation, sampling) work naturally within sessions with servers including sessionId to support future multi-session scenarios.
Backward Compatibility
Protocol-level sessions are defined as part of a new protocol version, ensuring backward compatibility through MCP's standard protocol version negotiation mechanism:
New Client + Old Server: If an old server doesn't support the new protocol version, negotiation will fall back to the highest mutually supported version (without protocol-level sessions).
Old Client + New Server: If an old client doesn't understand the new protocol version, the server will negotiate down to a supported version (without protocol-level sessions).
Same Protocol Version: When both parties support the session-enabled protocol version:
Optional fields also provide type definition reuse convenience across protocol versions.
The optionality of sessionId serves operational purposes (enabling sessionless servers) and convenience (type definition reuse), rather than being the primary backward compatibility mechanism - that role is filled by protocol version negotiation.
Reference Implementation
A reference implementation will be provided demonstrating:
Implementation Status:
Security Implications
Per the Security Best Practices specification:
Core Security Principles
Sessions MUST NOT be used for authentication: Session IDs identify conversation context only. Every request with authorization requirements MUST include valid authentication credentials independently of any session ID.
All requests MUST be verified: For servers that implement authorization, every inbound request must have its authorization validated, regardless of session ID.
Session IDs SHOULD be bound to users: Servers should combine session IDs with user-specific information to prevent session hijacking. The user ID is derived from the authorization token, not provided by the client.
Secure session ID generation: Session IDs MUST use cryptographically secure random generation to prevent guessing attacks.
Authorization context changes: If the authenticated principal changes, servers MUST invalidate the session to maintain security boundaries.
Token Expiry and Re-authentication
When authorization tokens expire during an active session:
Authorization-Session Relationship
Sessions and authorization serve complementary purposes:
This separation ensures that session state never bypasses security requirements while enabling stateful conversation management.