The Shift to Streamable HTTP: Future-Proofing MCP in .NET 9
The Shift to Streamable HTTP: Future-Proofing MCP in .NET 9
If you are building Model Context Protocol (MCP) servers, the ground beneath you just shifted.
In mid-2025, the MCP specification officially deprecated the HTTP+SSE (Server-Sent Events) transport. The new standard is Streamable HTTP. If you are deploying new agents or upgrading your .NET infrastructure, you need to leave SSE behind.
Here is why the shift happened, how to configure it in .NET 9, and exactly how to fix the inevitable backend hygiene issues you will hit when pushing this traffic through Azure API Management (APIM).
Why SSE Was Deprecated
Server-Sent Events were always a temporary bridge.
SSE is strictly unidirectional (server-to-client). To achieve two-way communication, MCP had to bolt on a secondary HTTP POST endpoint just to receive client messages, while holding the SSE connection open for server responses. It was clunky, hard to route, and notoriously difficult to load balance in enterprise architectures.
Streamable HTTP fixes this. It uses a single, persistent HTTP request/response stream. It's cleaner, requires fewer endpoints, and aligns much better with modern proxy and gateway infrastructure.
Adapting .NET 9 for Streamable HTTP
If you are building your MCP server in .NET 9 (like the SampleMcpServer in our reference architecture), you must ensure your endpoints are configured to handle persistent streams rather than standard discrete requests.
You drop the secondary POST endpoint entirely. Your server now listens on a single endpoint, accepting a stream and returning a continuous HTTP response stream.
APIM Backend Hygiene: The Missing Attribute
Moving to Streamable HTTP exposes a major trap in Azure API Management.
APIM is designed to buffer responses. It wants to receive the entire payload from your backend, inspect it, apply policies, and then hand it to the client.
With Streamable HTTP, the backend never closes the connection.
If you leave the default APIM behavior in place, your MCP client will just sit there, hanging indefinitely. It looks like a timeout, but it's actually APIM silently buffering an endless stream. You will see no errors. No logs.
You have to tell APIM to get out of the way.
You do this by applying a specific "hygiene" policy fragment to your backend configuration. You must set the forward-request policy to disable response buffering.
<forward-request buffer-response="false" />
This single attribute is mandatory for Streamable HTTP to function behind APIM.
Watch Your Policies
Once you disable buffering, you have to be careful about what else you put in your policy chain.
If you attempt to read context.Response.Body anywhere in your MCP-scoped policies, APIM will immediately fall back to buffering the response, breaking your stream all over again.
Keep your inbound policies tight—handle your Entra JWT validation (validate-entra-token) and rate limiting (rate-limit-per-subscription) before the request hits the backend. Let the stream flow back out uninterrupted.
See the code here https://github.com/jackweldonweb/apim-mcp-terraform, check license for usage information.