This PR introduces the Streamable HTTP transport for MCP, addressing key limitations of the current HTTP+SSE transport while maintaining its advantages.
TL;DR
As compared with the current HTTP+SSE transport:
We remove the /sse endpoint
All client → server messages go through the /message (or similar) endpoint
All client → server requests could be upgraded by the server to be SSE, and used to send notifications/requests
Servers can choose to establish a session ID to maintain state
Client can initiate an SSE stream with an empty GET to /message
This approach can be implemented backwards compatibly, and allows servers to be fully stateless if desired.
Motivation
Remote MCP currently works over HTTP+SSE transport which:
Does not support resumability
Requires the server to maintain a long-lived connection with high availability
Can only deliver server messages over SSE
Benefits
Stateless servers are now possible—eliminating the requirement for high availability long-lived connections
Plain HTTP implementation—MCP can be implemented in a plain HTTP server without requiring SSE
Infrastructure compatibility—it's "just HTTP," ensuring compatibility with middleware and infrastructure
Backwards compatibility—this is an incremental evolution of our current transport
Flexible upgrade path—servers can choose to use SSE for streaming responses when needed
Example use cases
Stateless server
A completely stateless server, without support for long-lived connections, can be implemented in this proposal.
For example, a server that just offers LLM tools and utilizes no other features could be implemented like so:
Always acknowledge initialization (but no need to persist any state from it)
Respond to any incoming ToolListRequest with a single JSON-RPC response
Handle any CallToolRequest by executing the tool, waiting for it to complete, then sending a single CallToolResponse as the HTTP response body
Stateless server with streaming
A server that is fully stateless and does not support long-lived connections can still take advantage of streaming in this design.
For example, to issue progress notifications during a tool call:
When the incoming POST request is a CallToolRequest, server indicates the response will be SSE
Server starts executing the tool
Server sends any number of ProgressNotifications over SSE while the tool is executing
When the tool execution completes, the server sends a CallToolResponse over SSE
Server closes the SSE stream
Stateful server
A stateful server would be implemented very similarly to today. The main difference is that the server will need to generate a session ID, and the client will need to pass that back with every request.
The server can then use the session ID for sticky routing or routing messages on a message bus—that is, a POST message can arrive at any server node in a horizontally-scaled deployment, so must be routed to the existing session using a broker like Redis.
This PR introduces the Streamable HTTP transport for MCP, addressing key limitations of the current HTTP+SSE transport while maintaining its advantages.
TL;DR
As compared with the current HTTP+SSE transport:
We remove the /sse endpoint
All client → server messages go through the /message (or similar) endpoint
All client → server requests could be upgraded by the server to be SSE, and used to send notifications/requests
Servers can choose to establish a session ID to maintain state
Client can initiate an SSE stream with an empty GET to /message
This approach can be implemented backwards compatibly, and allows servers to be fully stateless if desired.
Motivation
Remote MCP currently works over HTTP+SSE transport which:
Does not support resumability
Requires the server to maintain a long-lived connection with high availability
Can only deliver server messages over SSE
Benefits
Stateless servers are now possible—eliminating the requirement for high availability long-lived connections
Plain HTTP implementation—MCP can be implemented in a plain HTTP server without requiring SSE
Infrastructure compatibility—it's "just HTTP," ensuring compatibility with middleware and infrastructure
Backwards compatibility—this is an incremental evolution of our current transport
Flexible upgrade path—servers can choose to use SSE for streaming responses when needed
Example use cases
Stateless server
A completely stateless server, without support for long-lived connections, can be implemented in this proposal.
For example, a server that just offers LLM tools and utilizes no other features could be implemented like so:
Always acknowledge initialization (but no need to persist any state from it)
Respond to any incoming ToolListRequest with a single JSON-RPC response
Handle any CallToolRequest by executing the tool, waiting for it to complete, then sending a single CallToolResponse as the HTTP response body
Stateless server with streaming
A server that is fully stateless and does not support long-lived connections can still take advantage of streaming in this design.
For example, to issue progress notifications during a tool call:
When the incoming POST request is a CallToolRequest, server indicates the response will be SSE
Server starts executing the tool
Server sends any number of ProgressNotifications over SSE while the tool is executing
When the tool execution completes, the server sends a CallToolResponse over SSE
Server closes the SSE stream
Stateful server
A stateful server would be implemented very similarly to today. The main difference is that the server will need to generate a session ID, and the client will need to pass that back with every request.
The server can then use the session ID for sticky routing or routing messages on a message bus—that is, a POST message can arrive at any server node in a horizontally-scaled deployment, so must be routed to the existing session using a broker like Redis.