Skip to content

Commit 880673a

Browse files
Merge pull request modelcontextprotocol#206 from modelcontextprotocol/justin/new-http-transport
[RFC] Replace HTTP+SSE with new "Streamable HTTP" transport
2 parents eb4abdf + 3a57a03 commit 880673a

File tree

4 files changed

+203
-29
lines changed

4 files changed

+203
-29
lines changed

docs/specification/draft/basic/_index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ See the following pages for more details on the different components:
5454
## Auth
5555

5656
MCP provides an [Authorization]({{< ref "/specification/draft/basic/authorization" >}})
57-
framework for HTTP+SSE transport. Implementations using HTTP+SSE transport **SHOULD**
57+
framework for use with HTTP. Implementations using an HTTP-based transport **SHOULD**
5858
conform to this specification, whereas implementations using STDIO transport **SHOULD
5959
NOT** follow this specification, and instead retrieve credentials from the environment.
6060

docs/specification/draft/basic/authorization.md

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ weight: 15
1212

1313
The Model Context Protocol provides authorization capabilities at the transport level,
1414
enabling MCP clients to make requests to restricted MCP servers on behalf of resource
15-
owners. This specification defines the authorization flow for HTTP+SSE transport.
15+
owners. This specification defines the authorization flow for HTTP-based transports.
1616

1717
### 1.2 Protocol Requirements
1818

1919
Authorization is **OPTIONAL** for MCP implementations. When supported:
2020

21-
- Implementations using an HTTP+SSE transport **SHOULD** conform to this specification.
21+
- Implementations using an HTTP-based transport **SHOULD** conform to this specification.
2222
- Implementations using an STDIO transport **SHOULD NOT** follow this specification, and
2323
instead retrieve credentials from the environment.
2424
- Implementations using alternative transports **MUST** follow established security best
@@ -120,19 +120,17 @@ For example: `MCP-Protocol-Version: 2024-11-05`
120120

121121
#### 2.3.2 Authorization Base URL
122122

123-
The authorization base URL **MUST** be determined from the [SSE
124-
endpoint]({{< ref "specification/draft/basic/transports#http-with-sse" >}}) URL by
125-
discarding any existing `path` component. For example:
123+
The authorization base URL **MUST** be determined from the MCP server URL by discarding
124+
any existing `path` component. For example:
126125

127-
If the SSE endpoint is `https://api.example.com/v1/sse`, then:
126+
If the MCP server URL is `https://api.example.com/v1/mcp`, then:
128127

129128
- The authorization base URL is `https://api.example.com`
130129
- The metadata endpoint **MUST** be at
131130
`https://api.example.com/.well-known/oauth-authorization-server`
132131

133132
This ensures authorization endpoints are consistently located at the root level of the
134-
domain serving the SSE endpoint, regardless of any path components in the SSE endpoint
135-
URL.
133+
domain hosting the MCP server, regardless of any path components in the MCP server URL.
136134

137135
#### 2.3.3 Fallbacks for Servers without Metadata Discovery
138136

@@ -147,7 +145,7 @@ For servers that do not implement OAuth 2.0 Authorization Server Metadata, clien
147145
| Token Endpoint | /token | Used for token exchange & refresh |
148146
| Registration Endpoint | /register | Used for dynamic client registration |
149147

150-
For example, with an SSE endpoint of `https://api.example.com/v1/sse`, the default
148+
For example, with an MCP server hosted at `https://api.example.com/v1/mcp`, the default
151149
endpoints would be:
152150

153151
- `https://api.example.com/authorize`
@@ -253,6 +251,9 @@ requirements for resource requests. Specifically:
253251
Authorization: Bearer <access-token>
254252
```
255253

254+
Note that authorization **MUST** be included in every HTTP request from client to server,
255+
even if they are part of the same logical session.
256+
256257
2. Access tokens **MUST NOT** be included in the URI query string
257258

258259
Example request:

docs/specification/draft/basic/transports.md

Lines changed: 191 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ The protocol currently defines two standard transport mechanisms for client-serv
1212
communication:
1313

1414
1. [stdio](#stdio), communication over standard in and standard out
15-
2. [HTTP with Server-Sent Events](#http-with-sse) (SSE)
15+
2. [Streamable HTTP](#streamable-http)
1616

1717
Clients **SHOULD** support stdio whenever possible.
1818

@@ -48,38 +48,210 @@ sequenceDiagram
4848
deactivate Server Process
4949
```
5050

51-
## HTTP with SSE
51+
## Streamable HTTP
5252

53-
In the **SSE** transport, the server operates as an independent process that can handle
54-
multiple client connections.
53+
{{< callout type="info" >}} This replaces the [HTTP+SSE
54+
transport]({{< ref "/specification/2024-11-05/basic/transports#http-with-sse" >}}) from
55+
protocol version 2024-11-05. See the [backwards compatibility](#backwards-compatibility)
56+
guide below. {{< /callout >}}
5557

56-
The server **MUST** provide two endpoints:
58+
In the **Streamable HTTP** transport, the server operates as an independent process that
59+
can handle multiple client connections. This transport uses HTTP POST and GET requests.
60+
Server can optionally make use of
61+
[Server-Sent Events](https://en.wikipedia.org/wiki/Server-sent_events) (SSE) to stream
62+
multiple server messages. This permits basic MCP servers, as well as more feature-rich
63+
servers supporting streaming and server-to-client notifications and requests.
5764

58-
1. An SSE endpoint, for clients to establish a connection and receive messages from the
59-
server
60-
2. A regular HTTP POST endpoint for clients to send messages to the server
65+
The server **MUST** provide a single HTTP endpoint path (hereafter referred to as the
66+
**MCP endpoint**) that supports both POST and GET methods. For example, this could be a
67+
URL like `https://example.com/mcp`.
6168

62-
When a client connects, the server **MUST** send an `endpoint` event containing a URI for
63-
the client to use for sending messages. All subsequent client messages **MUST** be sent
64-
as HTTP POST requests to this endpoint.
69+
### Message Exchange
6570

66-
Server messages are sent as SSE `message` events, with the message content encoded as
67-
JSON in the event data.
71+
1. Every JSON-RPC message sent from the client **MUST** be a new HTTP POST request to the
72+
MCP endpoint.
73+
74+
2. When the client sends a JSON-RPC _request_ to the MCP endpoint via POST:
75+
76+
- The client **MUST** include an `Accept` header, listing both `application/json` and
77+
`text/event-stream` as supported content types.
78+
- The server **MUST** either return `Content-Type: text/event-stream`, to initiate an
79+
SSE stream, or `Content-Type: application/json`, to return a single JSON-RPC
80+
_response_. The client **MUST** support both these cases.
81+
- If the server initiates an SSE stream:
82+
- The SSE stream **SHOULD** eventually include a JSON-RPC _response_ message.
83+
- The server **MAY** send JSON-RPC _requests_ and _notifications_ before sending a
84+
JSON-RPC _response_. These messages **SHOULD** relate to the originating client
85+
_request_.
86+
- The server **SHOULD NOT** close the SSE stream before sending the JSON-RPC
87+
_response_, unless the [session](#session-management) expires.
88+
- After the JSON-RPC _response_ has been sent, the server **MAY** close the SSE
89+
stream at any time.
90+
- Disconnection **MAY** occur at any time (e.g., due to network conditions).
91+
Therefore:
92+
- Disconnection **SHOULD NOT** be interpreted as the client cancelling its
93+
request.
94+
- To cancel, the client **SHOULD** explicitly send an MCP `CancelledNotification`.
95+
- To avoid message loss due to disconnection, the server **MAY** make the stream
96+
[resumable](#resumability-and-redelivery).
97+
98+
3. When the client sends a JSON-RPC _notification_ or _response_ to the MCP endpoint via
99+
POST:
100+
101+
- If the server accepts the message, it **MUST** return HTTP status code 202 Accepted
102+
with no body.
103+
- If the server cannot accept the message, it **MUST** return an HTTP error status
104+
code (e.g., 400 Bad Request). The HTTP response body **MAY** comprise a JSON-RPC
105+
_error response_ that has no `id`.
106+
107+
4. The client **MAY** also issue an HTTP GET to the MCP endpoint. This can be used to
108+
open an SSE stream, allowing the server to communicate to the client without the
109+
client first sending a JSON-RPC _request_.
110+
- The client **MUST** include an `Accept` header, listing `text/event-stream` as a
111+
supported content type.
112+
- The server **MUST** either return `Content-Type: text/event-stream` in response to
113+
this HTTP GET, or else return HTTP 405 Method Not Allowed, indicating that the
114+
server does not offer an SSE stream at this endpoint.
115+
- If the server initiates an SSE stream:
116+
- The server **MAY** send JSON-RPC _requests_ and _notifications_ on the stream.
117+
These messages **SHOULD** be unrelated to any concurrently-running JSON-RPC
118+
_request_ from the client.
119+
- The server **MUST NOT** send a JSON-RPC _response_ on the stream **unless**
120+
[resuming](#resumability-and-redelivery) a stream associated with a previous
121+
client request.
122+
- The server **MAY** close the SSE stream at any time.
123+
- The client **MAY** close the SSE stream at any time.
124+
125+
### Multiple Connections
126+
127+
1. The client **MAY** remain connected to multiple SSE streams simultaneously.
128+
2. The server **MUST** send each of its JSON-RPC messages on only one of the connected
129+
streams; that is, it **MUST NOT** broadcast the same message across multiple streams.
130+
- The risk of message loss **MAY** be mitigated by making the stream
131+
[resumable](#resumability-and-redelivery).
132+
133+
### Resumability and Redelivery
134+
135+
To support resuming broken connections, and redelivering messages that might otherwise be
136+
lost:
137+
138+
1. Servers **MAY** attach an `id` field to their SSE events, as described in the
139+
[SSE standard](https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation).
140+
- If present, the ID **MUST** be globally unique across all streams within that
141+
[session](#session-management)—or all streams with that specific client, if session
142+
management is not in use.
143+
2. If the client wishes to resume after a broken connection, it **SHOULD** issue an HTTP
144+
GET to the MCP endpoint, and include the
145+
[`Last-Event-ID`](https://html.spec.whatwg.org/multipage/server-sent-events.html#the-last-event-id-header)
146+
header to indicate the last event ID it received.
147+
- The server **MAY** use this header to replay messages that would have been sent
148+
after the last event ID, _on the stream that was disconnected_, and to resume the
149+
stream from that point.
150+
- The server **MUST NOT** replay messages that would have been delivered on a
151+
different stream.
152+
153+
In other words, these event IDs should be assigned by servers on a _per-stream_ basis, to
154+
act as a cursor within that particular stream.
155+
156+
### Session Management
157+
158+
An MCP "session" consists of logically related interactions between a client and a
159+
server, beginning with the [initialization phase]({{< ref "lifecycle" >}}). To support
160+
servers which want to establish stateful sessions:
161+
162+
1. A server using the Streamable HTTP transport **MAY** assign a session ID at
163+
initialization time, by including it in an `Mcp-Session-Id` header on the HTTP
164+
response containing the `InitializeResult`.
165+
- The session ID **SHOULD** be globally unique and cryptographically secure (e.g., a
166+
securely generated UUID, a JWT, or a cryptographic hash).
167+
- The session ID **MUST** only contain visible ASCII characters (ranging from 0x21 to
168+
0x7E).
169+
2. If an `Mcp-Session-Id` is returned by the server during initialization, clients using
170+
the Streamable HTTP transport **MUST** include it in the `Mcp-Session-Id` header on
171+
all of their subsequent HTTP requests.
172+
- Servers that require a session ID **SHOULD** respond to requests without an
173+
`Mcp-Session-Id` header (other than initialization) with HTTP 400 Bad Request.
174+
3. The server **MAY** terminate the session at any time, after which it **MUST** respond
175+
to requests containing that session ID with HTTP 404 Not Found.
176+
4. When a client receives HTTP 404 in response to a request containing an
177+
`Mcp-Session-Id`, it **MUST** start a new session by sending a new `InitializeRequest`
178+
without a session ID attached.
179+
5. Clients that no longer need a particular session (e.g., because the user is leaving
180+
the client application) **SHOULD** send an HTTP DELETE to the MCP endpoint with the
181+
`Mcp-Session-Id` header, to explicitly terminate the session.
182+
- The server **MAY** respond to this request with HTTP 405 Method Not Allowed,
183+
indicating that the server does not allow clients to terminate sessions.
184+
185+
### Sequence Diagram
68186

69187
```mermaid
70188
sequenceDiagram
71189
participant Client
72190
participant Server
73191
74-
Client->>Server: Open SSE connection
75-
Server->>Client: endpoint event
76-
loop Message Exchange
77-
Client->>Server: HTTP POST messages
78-
Server->>Client: SSE message events
192+
note over Client, Server: initialization
193+
194+
Client->>+Server: POST InitializeRequest
195+
Server->>-Client: InitializeResponse<br>Mcp-Session-Id: 1868a90c...
196+
197+
Client->>+Server: POST InitializedNotification<br>Mcp-Session-Id: 1868a90c...
198+
Server->>-Client: 202 Accepted
199+
200+
note over Client, Server: client requests
201+
Client->>+Server: POST ... request ...<br>Mcp-Session-Id: 1868a90c...
202+
203+
alt single HTTP response
204+
Server->>Client: ... response ...
205+
else server opens SSE stream
206+
loop while connection remains open
207+
Server-)Client: ... SSE messages from server ...
208+
end
209+
Server-)Client: SSE event: ... response ...
210+
end
211+
deactivate Server
212+
213+
note over Client, Server: client notifications/responses
214+
Client->>+Server: POST ... notification/response ...<br>Mcp-Session-Id: 1868a90c...
215+
Server->>-Client: 202 Accepted
216+
217+
note over Client, Server: server requests
218+
Client->>+Server: GET<br>Mcp-Session-Id: 1868a90c...
219+
loop while connection remains open
220+
Server-)Client: ... SSE messages from server ...
79221
end
80-
Client->>Server: Close SSE connection
222+
deactivate Server
223+
81224
```
82225

226+
### Backwards Compatibility
227+
228+
Clients and servers can maintain backwards compatibility with the deprecated [HTTP+SSE
229+
transport]({{< ref "/specification/2024-11-05/basic/transports#http-with-sse" >}}) (from
230+
protocol version 2024-11-05) as follows:
231+
232+
**Servers** wanting to support older clients should:
233+
234+
- Continue to host both the SSE and POST endpoints of the old transport, alongside the
235+
new "MCP endpoint" defined for the Streamable HTTP transport.
236+
- It is also possible to combine the old POST endpoint and the new MCP endpoint, but
237+
this may introduce unneeded complexity.
238+
239+
**Clients** wanting to support older servers should:
240+
241+
1. Accept an MCP server URL from the user, which may point to either a server using the
242+
old transport or the new transport.
243+
2. Attempt to POST an `InitializeRequest` to the server URL, with an `Accept` header as
244+
defined above:
245+
- If it succeeds, the client can assume this is a server supporting the new Streamable
246+
HTTP transport.
247+
- If it fails with an HTTP 4xx status code (e.g., 405 Method Not Allowed or 404 Not
248+
Found):
249+
- Issue a GET request to the server URL, expecting that this will open an SSE stream
250+
and return an `endpoint` event as the first event.
251+
- When the `endpoint` event arrives, the client can assume this is a server running
252+
the old HTTP+SSE transport, and should use that transport for all subsequent
253+
communication.
254+
83255
## Custom Transports
84256

85257
Clients and servers **MAY** implement additional custom transport mechanisms to suit

schema/draft/schema.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ export interface InitializeResult extends Result {
167167
protocolVersion: string;
168168
capabilities: ServerCapabilities;
169169
serverInfo: Implementation;
170+
170171
/**
171172
* Instructions describing how to use the server and its features.
172173
*

0 commit comments

Comments
 (0)