AI & MCP
SSE and Streamable HTTP: how an MCP server talks
Streamable HTTP replaced HTTP+SSE: one endpoint takes JSON-RPC over POST and may answer with a stream. Here is what this server really does.
Key points
- HTTP+SSE used two endpoints; Streamable HTTP uses one and answers with JSON or SSE.
- Stdio remains the choice for a local server started by the client on the same machine.
- The EneUI endpoint always answers application/json and never emits Mcp-Session-Id.
Streamable HTTP replaced the HTTP+SSE transport: a single endpoint takes JSON-RPC messages over POST and may answer with an SSE stream. Stdio remains the choice for a local server started by the client.
Three transports, two generations
The first revision, 2024-11-05, used two endpoints: a GET for the stream and a POST for the messages. Streamable HTTP, from the 2025-03-26 revision, folds them into one path.
| Transport | Endpoint | When | Status |
|---|---|---|---|
| stdio | stdin and stdout | local process | standard |
| HTTP+SSE | GET /sse and POST /messages | 2024 clients | deprecated |
| Streamable HTTP | POST /mcp | remote server | standard |
What the EneUI endpoint answers
curl -s -i https://ui.eneawork.it/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"ping"}'
The header comes back as application/json, not text/event-stream, and Mcp-Session-Id is absent. There is one response: {"jsonrpc":"2.0","id":1,"result":{}}.
One request, one response
The server keeps no state: every POST is independent, and a notification without an id closes with 202 and an empty body. For a read-only catalogue that is enough, and it crosses any proxy without surprises.
The price of that choice
Without an open stream the server cannot start a message: no sampling, no notice about an updated resource, no resume after a disconnect. All of them are optional features, but whoever wants them must accept SSE.
The same path for browsers and agents
An Accept: text/html drops the GET into the /mcp page; an Accept: */* gets the JSON document with name, version, transport and the 9 tools. Negotiation happens in the header, not on a separate path.
The EneUI catalogue
Answers come from the same origin as the pages: heroes, icons and a real block such as SaaS Pricing with Billing Toggle, 1 file and 4 registry dependencies, checked on 1 November 2026.
The limitation
The endpoint implements neither Mcp-Session-Id nor the streaming GET, so it cannot resume an interrupted response with Last-Event-ID. A client that demands a stream must accept JSON as the complete response.
Where to continue
The OAuth flow that sits beside this transport is in OAuth for MCP servers; the dispatcher is in how to build an MCP server; the comparison with REST APIs is in MCP vs REST. The protocol definition is in what MCP is.
Frequently asked questions
Is Streamable HTTP mandatory in MCP?
No. A server can use stdio alone. Streamable HTTP is the transport for a remote endpoint that several clients reach.
Can I still use HTTP+SSE?
Technically yes, but the transport has been deprecated since the 2025-03-26 revision. A new client is better off speaking Streamable HTTP or stdio.
Why does EneUI answer with JSON instead of SSE?
Because each request produces one response and JSON crosses every proxy. A stream would only help for server-initiated messages, which do not exist here.
What is Mcp-Session-Id?
It is the header a server uses to give the client a session identifier. The EneUI endpoint never emits it: every POST is independent.
Can a browser open /mcp?
Yes, but it receives the HTML page: with Accept text/html the GET falls into the application, while a client asking for JSON gets the discovery document.