-
Notifications
You must be signed in to change notification settings - Fork 996
Description
SEP-1288: WebSocket Transport for Model Context Protocol (MCP)
Status: in-review (sponsored by @Kludex)
Type: Standards Track
Created: 2025-08-02
Authors: Larry Maccherone (Larry@Maccherone.com, @lmaccherone)
EDITS MADE 2025-08-26
Restructured some of the motivation and rationale content as a Q&A
EDITS MADE 2025-08-24
This past week, there was a lot of discussion around SEP-1364. The net-net of that is that at least some members of the transport WG seem inclined to expand the scope to possibly introduce new concepts like "context/start" and "context/end". I suspect that conversation is likely to continue for some time and this SEP is being reviewed at a core maintainer meeting on 2025-08-27.
So, I decided to once again decouple this SEP-1287 from SEP-1364. So, rather than merely reference SEP-1364, it now specifies everything related to the mcpSessionId
field necessary for this transport. Note, this is not simply restoring the version I had before which had a message envelope to transmit mcpSessionId. It now moves mcpSessionId down into the JSON-RPC package and allows for calling initialize
again to renegotiate version and capabilities for a given session, which is essentially how it is specified in the original SEP-1364 alternative 2.
EDITS MADE 2025-08-20
- Now aligns with SEP-1364, which pushes the MCP session into the data layer as
sessionId
field in JSON-RPC package. Assumes alternative 2 in SEP-1364 is chosen. - The primary impact of the above is that this SEP no longer calls for the inclusion of a WebSocket-specific envelope around the JSON-RPC package
- However, it also more strongly argued for only supporting a single way to pass auth token, namely by smuggling it in with the WebSocket subprotocol list
- Focused motivation as opposed to bidirectional HTTP streams. Prior to this edit, some content read like an alternative to the new deprecated HTTP+SSE transport
Abstract
This SEP proposes a WebSocket transport layer for the Model Context Protocol (MCP). The proposed transport would enable long-lived bidirectional communication between MCP clients and servers with session persistence across network interruptions.
Motivation
The current MCP specification defines stdio and Streamable HTTP transport layers, but lacks a WebSocket transport option. Based on community feedback and real-world implementation experience, WebSocket transport addresses several critical pain points.
Q&A
Q: What is the primary motivation for this SEP?
A: There is not currently a great transport for implementing the stateful usage scenarios currently defined in MCP--in particular, server-initiatied communications like `notifications/resources/updated` and `notifications/*/list_changed` are not well supported. These open MCP up to more real-time use cases.Q: What does WebSockets bring that Streamable HTTP does not?
Biggest advantages:
-
More mature cloud-provider support, particularly functions as a service offerings. As an example, in Cloudflare each edge Workers Durable Object instance can maintain, for days, up to 32,000 simultaneous hibernatable WebSocket connections, which incur charges only while actively processing messages. For streamable HTTP, the connection must either be short-lived or kept alive with workarounds and consuming chargeable resources even when not processing messages.
I'm told by heavy users of those platforms that there are similar constraints on using it with AWS and Azure serverless offerings. It's unclear to me that Google supports it as well.
-
Intermediaries and reliability WebSockets are well supported by network providers and enterprise intermediaries, while streamable HTTP support is expected to take years for parity, if ever. This results in more frequent drops or even in the inability to make a streamable connection in some circumstances.
-
Reduced Protocol Overhead: WebSockets have smaller per-frame overhead compared even to HTTP/2 bidirectional streams.
-
Simpler Semantics: HTTP/2 bidirectional streams' multiplexing and prioritization capabilities are more complex than WebSockets semantics for little benefit in this context.
If you need more validation, take a look at all of the implementations of push notifications in GraphQL. They are almost universally built on WebSockets. The HTTP/2 streams experiments you can find complain about the same 4 things I listed above and many others.
Q: Why shouldn't we let this flow through the transports WG before considering?
A: The Transport WG is currently gridlocked between those that want big changes to "make MCP stateless" and those that want to make incremental improvements. The stateless MCP camp would sacrifice better support for existing MCP features like `notifications/resources/updated` for the load-balancer scalability benefits of a purely stateless MCP. WebSockets solve immediate, real-world problems that can't wait for that debate around stateless MCP to resolve.Q: Why did you move Mcp-Session-Id out of a header and down into the MCP JSON-RPC package as mcpSessionId?
A: WebSockets don't provide access to headers, URLs, or cookies after connection establishment, so we need another way to transmit session metadata. We considered message envelopes but chose to add an optional `mcpSessionId` field to the JSON-RPC package instead. This aligns with SEP-1364's and SEP-1359's approach for Streamable HTTP sessions and avoids the complexity of transport-specific envelopes. All three call for a change to the core MCP protocol by adding an optional field to the schema.Q: Why does the SEP currently not support passing auth tokens in on the Authorization header like the Streamable HTTP transport?
A: Headers are not directly accessible in the JavaScript WebSockets API. This is not just a browser limitation. It applies to server-side implementations like Deno, Fastly, Cloudflare Workers, etc., as well.Q: Fair enough. But why not support both the Authorization header, subprotocols, and possibly others?
A: The original draft had several other mechanisms including the Authorization header and we could add that back if desired, but it's currently drafted as the ONE GOOD WAY that works for everyone.Specification
The complete technical specification for this SEP is available in the accompanying specification PR
Rationale
This section provides the rationale for design choices in the WebSocket Transport for MCP SEP that might be questioned. While the WebSocket transport specification follows the Streamable HTTP transport patterns where possible, there are intentional deviations based on the different characteristics of WebSocket usage.
Decision: Required MCP sessions
Streamable HTTP: Sessions are optional (MAY
)
WebSocket Transport: Sessions are required (MUST
)
Rationale: A key motivation for this WebSocket transport is to enable statefull bi-directional usage, particularly server-initiated messages. So you would only opt for WebSocket transport if you need this capability. Streamable HTTP has robust support for stateless uses that don't necessarily require MCP sessions.
Further, this transport was designed such that a single MCP server could support all three channels (stateless HTTP POST, HTTP GET initiated bidirectional streams, and WebSocket). The reference implementation supports stateless HTTP interactions and only requires WebSockets for server-initiated messages, like notifications/resources/updated
or notifications/*/list_changed
.
Decision: Single Connection Per Session
Streamable HTTP: Supports multiple concurrent connections per session
WebSocket Transport: Requires exactly one active connection per session (MUST
close previous connections)
Rationale:
Unambigous:
- Single connection per session eliminates ambiguity about which connection should receive server-initiated notifications
HTTP is stateless. WebSockets are stateful:
- Each HTTP POST in the Streamable HTTP transport is stateless so each such request is a separate connection
- There is no way for servers to initiate notifications to the client via HTTP POST so there is no need to know which connection to send notifications over
- However, if the Streamable HTTP transport were split such that bidirectional streams established with HTTP GET were considered a separate transport, it might also make sense to have one connection per mcpSessionId so it too could know which connection to use for which subscription, but that is beyond the scope of this SEP
Network Resource Efficiency:
- WebSocket connections are more constrained on clients than HTTP requests
- Single connection reduces server resource usage (memory, file descriptors, connection tracking)
- Eliminates potential connection leaks from clients that don't properly close old connections
Cleaner Reconnection Semantics:
- Required closing of inactive connections prevents "zombie" connections from interfering with session state
- Eliminates race conditions between multiple connections competing for the same session
Backward Compatibility
Because this is an additional transport layer, there are no backward compatibility concerns. Existing stdio and Streamable HTTP transports remain unchanged and fully functional.
That said, this transport requires the addition of an mcpSessionId to the JSON-RPC pacakge. The schema for that will show it as optional but the behavior for usage over WebSockets will error if that is missing.
As written, this SEP also allows for version and capabilities for a given session to be renegotiated by calling initialize again. This is probably best moved out of transports and into the core specification at some point. I would be fine with excluding that capability for now. It was only included because that's what SEP-1364 alternative 2 did.
Reference Implementation
Reference implementations will be provided for:
- MCPReconnectingWSClient: JavaScript/TypeScript client library with automatic reconnection and MCP session management
- MCPWebSocketServer: Server-side WebSocket handler implementing full lifecycle
Future Considerations
Compatibility with Future MCP Versions
This transport specification is designed to stay at the transport layer and should be compatible with future MCP protocol versions.
Security Implications
This SEP has no additional security implications beyond the standard WebSocket security considerations already documented in the SEP.
References
Metadata
Metadata
Assignees
Labels
Type
Projects
Status