HTTP with SSE(v2024-11-05)
https://modelcontextprotocol.io/specification/2024-11-05/basic/transports#http-with-sse
The server MUST provide two endpoints:
- An SSE endpoint, for clients to establish a connection and receive messages from the server
- A regular HTTP POST endpoint for clients to send messages to the server
双连接,一个SSE,一个POST。 SSE 用于服务器推送,POST用于客户端发送。
When a client connects, the server MUST send an endpoint event containing a URI for the client to use for sending messages. All subsequent client messages MUST be sent as HTTP POST requests to this endpoint. Server messages are sent as SSE message events, with the message content encoded as JSON in the event data.
即系有两个 endpoint:
- 一个 SSE,用于接收服务器推送(包括发现另外一个 endpoint url)
- 一个 server 接收 POST。

GET /sse HTTP/1.1
Accept: text/event-stream
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Cache-Control: no-cache
Connection: keep-alive
Host: localhost:3001
Origin: http://localhost:15000
Pragma: no-cache
Referer: http://localhost:15000/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36
mcp-protocol-version: 2024-11-05
sec-ch-ua: "Chromium";v="136", "Google Chrome";v="136", "Not.A/Brand";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Linux"
---
HTTP/1.1 200 OK
content-type: text/event-stream
cache-control: no-cache
access-control-allow-origin: http://localhost:15000
transfer-encoding: chunked
date: Sun, 31 Aug 2025 12:16:55 GMT
event: endpoint
data: ?sessionId=8a9a155c-3641-4bb2-a8b1-eb56574a83fd
event: message
data: {"jsonrpc":"2.0","id":0,"result":{"protocolVersion":"2025-03-26","capabilities":{"prompts":{},"resources":{},"tools":{}},"serverInfo":{"name":"rmcp","version":"0.6.0"},"instructions":"This server is a gateway to a set of mcp servers. It is responsible for routing requests to the correct server and aggregating the results."}}
event: message
data: {"jsonrpc":"2.0","id":1,"result":{"tools":[{"name":"echo","description":"Echoes back the input","inputSchema":{"type":"object","properties":{"message":{"type":"string","description":"Message to echo"}},"required":["message"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"add","description":"Adds two numbers","inputSchema":{"type":"object","properties":{"a":{"type":"number","description":"First number"},"b":{"type":"number","description":"Second number"}},"required":["a","b"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"longRunningOperation","description":"Demonstrates a long running operation with progress updates","inputSchema":{"type":"object","properties":{"duration":{"type":"number","default":10,"description":"Duration of the operation in seconds"},"steps":{"type":"number","default":5,"description":"Number of steps in the operation"}},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"printEnv","description":"Prints all environment variables, helpful for debugging MCP server configuration","inputSchema":{"type":"object","properties":{},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"sampleLLM","description":"Samples from an LLM using MCP's sampling feature","inputSchema":{"type":"object","properties":{"prompt":{"type":"string","description":"The prompt to send to the LLM"},"maxTokens":{"type":"number","default":100,"description":"Maximum number of tokens to generate"}},"required":["prompt"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"getTinyImage","description":"Returns the MCP_TINY_IMAGE","inputSchema":{"type":"object","properties":{},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"annotatedMessage","description":"Demonstrates how annotations can be used to provide metadata about content","inputSchema":{"type":"object","properties":{"messageType":{"type":"string","enum":["error","success","debug"],"description":"Type of message to demonstrate different annotation patterns"},"includeImage":{"type":"boolean","default":false,"description":"Whether to include an example image"}},"required":["messageType"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"getResourceReference","description":"Returns a resource reference that can be used by MCP clients","inputSchema":{"type":"object","properties":{"resourceId":{"type":"number","minimum":1,"maximum":100,"description":"ID of the resource to reference (1-100)"}},"required":["resourceId"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"startElicitation","description":"Demonstrates the Elicitation feature by asking the user to provide information about their favorite color, number, and pets.","inputSchema":{"type":"object","properties":{},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"getResourceLinks","description":"Returns multiple resource links that reference different types of resources","inputSchema":{"type":"object","properties":{"count":{"type":"number","minimum":1,"maximum":10,"default":3,"description":"Number of resource links to return (1-10)"}},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"structuredContent","description":"Returns structured content along with an output schema for client data validation","inputSchema":{"type":"object","properties":{"location":{"type":"string","minLength":1,"description":"City name or zip code"}},"required":["location"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"},"outputSchema":{"type":"object","properties":{"temperature":{"type":"number","description":"Temperature in celsius"},"conditions":{"type":"string","description":"Weather conditions description"},"humidity":{"type":"number","description":"Humidity percentage"}},"required":["temperature","conditions","humidity"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}]}}
event: message
data: {"jsonrpc":"2.0","id":2,"result":{"content":[{"type":"text","text":"Echo: I Love testing"}]}}
POST /sse?sessionId=8a9a155c-3641-4bb2-a8b1-eb56574a83fd HTTP/1.1
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 171
Host: localhost:3001
Origin: http://localhost:15000
Pragma: no-cache
Referer: http://localhost:15000/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36
accept: text/event-stream
content-type: application/json
mcp-protocol-version: 2024-11-05
sec-ch-ua: "Chromium";v="136", "Google Chrome";v="136", "Not.A/Brand";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Linux"
{"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"agentgateway-dashboard","version":"0.1.0"}},"jsonrpc":"2.0","id":0}
---
HTTP/1.1 200 OK
access-control-allow-origin: http://localhost:15000
access-control-allow-headers: mcp-protocol-version,content-type,cache-control
content-length: 0
date: Sun, 31 Aug 2025 12:16:55 GMT
POST /sse?sessionId=8a9a155c-3641-4bb2-a8b1-eb56574a83fd HTTP/1.1
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 54
Host: localhost:3001
Origin: http://localhost:15000
Pragma: no-cache
Referer: http://localhost:15000/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36
accept: text/event-stream
content-type: application/json
mcp-protocol-version: 2024-11-05
sec-ch-ua: "Chromium";v="136", "Google Chrome";v="136", "Not.A/Brand";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Linux"
{"method":"notifications/initialized","jsonrpc":"2.0"}
--- 
HTTP/1.1 200 OK
access-control-allow-origin: http://localhost:15000
access-control-allow-headers: mcp-protocol-version,content-type,cache-control
content-length: 0
date: Sun, 31 Aug 2025 12:16:55 GMT
POST /sse?sessionId=8a9a155c-3641-4bb2-a8b1-eb56574a83fd HTTP/1.1
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 58
Host: localhost:3001
Origin: http://localhost:15000
Pragma: no-cache
Referer: http://localhost:15000/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36
accept: text/event-stream
content-type: application/json
mcp-protocol-version: 2024-11-05
sec-ch-ua: "Chromium";v="136", "Google Chrome";v="136", "Not.A/Brand";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Linux"
{"method":"tools/list","params":{},"jsonrpc":"2.0","id":1}
---
HTTP/1.1 200 OK
access-control-allow-origin: http://localhost:15000
access-control-allow-headers: mcp-protocol-version,content-type,cache-control
content-length: 0
date: Sun, 31 Aug 2025 12:16:55 GMT
POST /sse?sessionId=8a9a155c-3641-4bb2-a8b1-eb56574a83fd HTTP/1.1
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 112
Host: localhost:3001
Origin: http://localhost:15000
Pragma: no-cache
Referer: http://localhost:15000/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36
accept: text/event-stream
content-type: application/json
mcp-protocol-version: 2024-11-05
sec-ch-ua: "Chromium";v="136", "Google Chrome";v="136", "Not.A/Brand";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Linux"
{"method":"tools/call","params":{"name":"echo","arguments":{"message":"I Love testing"}},"jsonrpc":"2.0","id":2}
---
HTTP/1.1 202 Accepted
access-control-allow-origin: http://localhost:15000
content-length: 0
date: Sun, 31 Aug 2025 12:33:32 GMT
Streamable HTTP(v2025-06-18)
https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#streamable-http
In the Streamable HTTP transport, the server operates as an independent process that can handle multiple client connections. This transport uses HTTP POST and GET requests. Server can optionally make use of Server-Sent Events (SSE) to stream multiple server messages. This permits basic MCP servers, as well as more feature-rich servers supporting streaming and server-to-client notifications and requests.
The server MUST provide a single HTTP endpoint(单个 endpoint) path (hereafter referred to as the MCP endpoint) that supports both POST and GET methods. For example, this could be a URL like https://example.com/mcp.
Sending Messages to the Server
Every JSON-RPC message sent from the client MUST be a new HTTP POST request to the MCP endpoint.
- The client MUST use HTTP POST to send JSON-RPC messages to the MCP endpoint.
- The client MUST include an Acceptheader, listing bothapplication/jsonandtext/event-streamas supported content types.
- The body of the POST request MUST be a single JSON-RPC request, notification, or response.
- If the input is a JSON-RPC response  or notification : 客户端发出的 response / notification
- If the server accepts the input, the server MUST return HTTP status code 202 Accepted with no body.
- If the server cannot accept the input, it MUST return an HTTP error status code (e.g., 400 Bad Request). The HTTP response body MAY comprise a JSON-RPC error response that has no id.
 
- If the input is a JSON-RPC request, the server MUST either return Content-Type: text/event-stream, to initiate an SSE stream, orContent-Type: application/json, to return one JSON object. The client MUST support both these cases.
- If the server initiates an SSE stream:
- The SSE stream SHOULD eventually include JSON-RPC response for the JSON-RPC request sent in the POST body. 最终,服务端应该对 request 用出响应(期间可能有多个服务端发出的 request/notification)
- The server MAY send JSON-RPC requests and notifications before sending the JSON-RPC response. These messages SHOULD relate to the originating client request. (服务端可以在接收到 request 后,发送自己的 request / notification。 而这些消息应该是与原始的 request 相关的 )
- The server SHOULD NOT close the SSE stream before sending the JSON-RPC response for the received JSON-RPC request, unless the session expires.
- After the JSON-RPC response has been sent, the server SHOULD close the SSE stream.
- Disconnection  MAY occur at any time (e.g., due to network conditions). Therefore:
- Disconnection SHOULD NOT be interpreted as the client cancelling its request.
- To cancel, the client SHOULD explicitly send an MCP CancelledNotification.
- To avoid message loss due to disconnection, the server MAY make the stream resumable.
 
 
Listening for Messages from the Server
- The client MAY issue an HTTP GET to the MCP endpoint. This can be used to open an SSE stream, allowing the server to communicate to the client, without the client first sending data via HTTP POST.
- The client MUST include an Acceptheader, listingtext/event-streamas a supported content type.
- The server MUST either return Content-Type: text/event-streamin response to this HTTP GET, or else return HTTP 405 Method Not Allowed, indicating that the server does not offer an SSE stream at this endpoint.
- If the server initiates an SSE stream:
- The server MAY send JSON-RPC requests and notifications on the stream.
- These messages SHOULD be unrelated to any concurrently-running JSON-RPC request from the client.
- The server MUST NOT send a JSON-RPC response on the stream unless resuming a stream associated with a previous client request.
- The server MAY close the SSE stream at any time.
- The client MAY close the SSE stream at any time.
 
Multiple Connections
- The client MAY remain connected to multiple SSE streams simultaneously.
- The server MUST send each of its JSON-RPC messages on only one of the connected streams; that is, it  MUST NOT broadcast the same message across multiple streams.
- The risk of message loss MAY be mitigated by making the stream resumable.
 
Resumability and Redelivery
To support resuming broken connections, and redelivering messages that might otherwise be
lost:
- Servers MAY attach an idfield to their SSE events, as described in the
 SSE standard.- If present, the ID MUST be globally unique across all streams within that
 session—or all streams with that specific client, if session
 management is not in use.
 
- If present, the ID MUST be globally unique across all streams within that
- If the client wishes to resume after a broken connection, it SHOULD issue an HTTP
 GET to the MCP endpoint, and include the
 Last-Event-ID
 header to indicate the last event ID it received.- The server MAY use this header to replay messages that would have been sent
 after the last event ID, on the stream that was disconnected, and to resume the
 stream from that point.
- The server MUST NOT replay messages that would have been delivered on a
 different stream.
 
- The server MAY use this header to replay messages that would have been sent
In other words, these event IDs should be assigned by servers on a per-stream basis, to
act as a cursor within that particular stream.
Session Management
An MCP “session” consists of logically related interactions between a client and a
server, beginning with the initialization phase. To support
servers which want to establish stateful sessions:
- A server using the Streamable HTTP transport MAY assign a session ID at
 initialization time, by including it in anMcp-Session-Idheader on the HTTP
 response containing theInitializeResult.- The session ID SHOULD be globally unique and cryptographically secure (e.g., a
 securely generated UUID, a JWT, or a cryptographic hash).
- The session ID MUST only contain visible ASCII characters (ranging from 0x21 to
 0x7E).
 
- The session ID SHOULD be globally unique and cryptographically secure (e.g., a
- If an Mcp-Session-Idis returned by the server during initialization, clients using
 the Streamable HTTP transport MUST include it in theMcp-Session-Idheader on
 all of their subsequent HTTP requests.- Servers that require a session ID SHOULD respond to requests without an
 Mcp-Session-Idheader (other than initialization) with HTTP 400 Bad Request.
 
- Servers that require a session ID SHOULD respond to requests without an
- The server MAY terminate the session at any time, after which it MUST respond
 to requests containing that session ID with HTTP 404 Not Found.
- When a client receives HTTP 404 in response to a request containing an
 Mcp-Session-Id, it MUST start a new session by sending a newInitializeRequest
 without a session ID attached.
- Clients that no longer need a particular session (e.g., because the user is leaving
 the client application) SHOULD send an HTTP DELETE to the MCP endpoint with the
 Mcp-Session-Idheader, to explicitly terminate the session.- The server MAY respond to this request with HTTP 405 Method Not Allowed,
 indicating that the server does not allow clients to terminate sessions.
 
- The server MAY respond to this request with HTTP 405 Method Not Allowed,
Sequence Diagram
sequenceDiagram
    participant Client
    participant Server 
    note over Client, Server: initialization
    Client->>+Server: POST InitializeRequest
    Server->>-Client: InitializeResponse<br>Mcp-Session-Id: 1868a90c...
    Client->>+Server: POST InitializedNotification<br>Mcp-Session-Id: 1868a90c...
    Server->>-Client: 202 Accepted
    note over Client, Server: client requests
    Client->>+Server: POST ... request ...<br>Mcp-Session-Id: 1868a90c...
    alt single HTTP response
      Server->>Client: ... response ...
    else server opens SSE stream
      loop while connection remains open
          Server-)Client: ... SSE messages from server ...
      end
      Server-)Client: SSE event: ... response ...
    end
    deactivate Server
    note over Client, Server: client notifications/responses
    Client->>+Server: POST ... notification/response ...<br>Mcp-Session-Id: 1868a90c...
    Server->>-Client: 202 Accepted
    note over Client, Server: server requests
    Client->>+Server: GET<br>Mcp-Session-Id: 1868a90c...
    loop while connection remains open
        Server-)Client: ... SSE messages from server ...
    end
    deactivate Server
Protocol Version Header
If using HTTP, the client MUST include the MCP-Protocol-Version: <protocol-version> HTTP header on all subsequent requests to the MCP
server, allowing the MCP server to respond based on the MCP protocol version.
For example: MCP-Protocol-Version: 2025-06-18
The protocol version sent by the client SHOULD be the one negotiated during
initialization.
For backwards compatibility, if the server does not receive an MCP-Protocol-Version
header, and has no other way to identify the version - for example, by relying on the
protocol version negotiated during initialization - the server SHOULD assume protocol
version 2025-03-26.
If the server receives a request with an invalid or unsupported
MCP-Protocol-Version, it MUST respond with 400 Bad Request.
Backwards Compatibility
Clients and servers can maintain backwards compatibility with the deprecated HTTP+SSE
transport (from
protocol version 2024-11-05) as follows:
Servers wanting to support older clients should:
- Continue to host both the SSE and POST endpoints of the old transport, alongside the
 new “MCP endpoint” defined for the Streamable HTTP transport.- It is also possible to combine the old POST endpoint and the new MCP endpoint, but
 this may introduce unneeded complexity.
 
- It is also possible to combine the old POST endpoint and the new MCP endpoint, but
Clients wanting to support older servers should:
- Accept an MCP server URL from the user, which may point to either a server using the
 old transport or the new transport.
- Attempt to POST an InitializeRequestto the server URL, with anAcceptheader as
 defined above:- If it succeeds, the client can assume this is a server supporting the new Streamable
 HTTP transport.
- If it fails with an HTTP 4xx status code (e.g., 405 Method Not Allowed or 404 Not
 Found):- Issue a GET request to the server URL, expecting that this will open an SSE stream
 and return anendpointevent as the first event.
- When the endpointevent arrives, the client can assume this is a server running
 the old HTTP+SSE transport, and should use that transport for all subsequent
 communication.
 
- Issue a GET request to the server URL, expecting that this will open an SSE stream
 
- If it succeeds, the client can assume this is a server supporting the new Streamable
Custom Transports
Clients and servers MAY implement additional custom transport mechanisms to suit
their specific needs. The protocol is transport-agnostic and can be implemented over any
communication channel that supports bidirectional message exchange.
Implementers who choose to support custom transports MUST ensure they preserve the
JSON-RPC message format and lifecycle requirements defined by MCP. Custom transports
SHOULD document their specific connection establishment and message exchange patterns
to aid interoperability.
总结
本质上,Streamable HTTP vs HTTP with SSE 的分别,是简化了 Client 端与 Server 端的实现。从双 endpoint 双连接,到单 endpoint 可多连接。
Streamable HTTP 在服务端返回的 InitializeResult 报文中,加入了 Mcp-Session-Id。而在 HTTP with SSE 中,一般放在 url 的 query 中
client 用 GET /mcp  并带上 Mcp-Session-Id 可以建立一个服务端推送通知的信道。
Prompt: 关于 AI 的 MCP 协议,2025-06-18 版本的 Streamable HTTP 与 2024-11-05 版本的 HTTP with SSE 有什么本质区别。
Ref
https://thenewstack.io/how-mcp-uses-streamable-http-for-real-time-ai-tool-interaction/
https://www.reddit.com/r/mcp/comments/1k4f9rz/mcp_sdk_now_supports_streamable_http/
