Skip to main content
MCP49 min readSep 5, 2026

SSE vs Streamable HTTP: What's the Difference in MCP?

Omar Hussein
Omar Hussein

Sep 5, 2026

Quick Answer

Use Streamable HTTP for a new remote Model Context Protocol (MCP) server. Use stdio when an MCP client launches a local server process. Keep legacy HTTP+SSE only when older clients still require it.

SSE itself is not deprecated. MCP deprecated a specific two-endpoint transport called HTTP+SSE. Current Streamable HTTP still uses Server-Sent Events when a response needs progress updates or incremental messages. A simple request can return one JSON object instead.

The current MCP revision, 2026-07-28, sends every client request as a POST to one MCP endpoint. It removed the standalone GET stream and the Mcp-Session-Id protocol session. Both features existed in earlier Streamable HTTP revisions, so advice written for 2025 can describe a different wire protocol.

Key Takeaways

  • SSE is a UTF-8 event-stream format. Streamable HTTP is an MCP transport that can use that format.
  • MCP deprecated its legacy HTTP+SSE transport, not the underlying Server-Sent Events web standard.
  • Legacy HTTP+SSE uses a long-lived GET stream and a separate POST endpoint.
  • Current Streamable HTTP uses one POST endpoint and returns either JSON or request-scoped SSE.
  • MCP revision 2026-07-28 removed protocol-level sessions, the standalone GET stream, SSE event IDs, and Last-Event-ID resumption.
  • stdio and Streamable HTTP are the two standard transport bindings in the current MCP specification.
  • New local MCP servers normally use stdio. New independently hosted remote servers normally use Streamable HTTP.
  • Production deployments must test buffering, idle timeouts, cancellation, authentication, and version fallback.
  • The current Proxidize MCP server uses stdio. Proxidize's forward proxies serve a separate outbound web-access role.

Last updated: September 3, 2026. Verified against MCP specification revision 2026-07-28.

MCP transports carry JSON-RPC messages between an AI application's MCP client and an MCP server. They do not define the tools, resources, or prompts exposed by that server.

This distinction matters because “SSE” has described several different things in MCP discussions. It can mean the general Server-Sent Events format, the original HTTP+SSE transport, or an SSE response inside Streamable HTTP.

For a broader introduction, read what MCP is and how Model Context Protocol works. This guide focuses on transport behavior, version differences, migration, and production deployment.

How Do SSE and Streamable HTTP Compare in MCP?

SSE and Streamable HTTP differ because legacy MCP split traffic across two endpoints, while current MCP uses one POST endpoint.

The first correction is terminological. The accurate comparison is legacy HTTP+SSE versus Streamable HTTP. SSE remains available inside Streamable HTTP as the response format text/event-stream.

The current MCP Streamable HTTP specification defines one endpoint that accepts POST. Each JSON-RPC request receives either one application/json object or an SSE stream scoped to that request.

QuestionLegacy HTTP+SSECurrent Streamable HTTP
What is it?Deprecated MCP remote transportCurrent MCP remote transport
Which revision introduced it?`2024-11-05``2025-03-26`; redesigned in `2026-07-28`
How many endpoint roles?Two: SSE GET and message POSTOne MCP endpoint accepting POST
How does the client send a message?POST to the URI advertised by the SSE endpointOne POST for each JSON-RPC request
How does the server return a result?Through the shared SSE connectionJSON or SSE on that request's response
Is SSE required for every result?Yes, for server-to-client messagesNo
Is a standalone GET stream used?YesNo in revision `2026-07-28`
Are protocol sessions used?Connection-oriented designNo in revision `2026-07-28`
How does streaming work?Server messages travel over the shared SSE channelA request can return request-scoped `text/event-stream`
Should a new server adopt it?NoYes, for remote deployment

Three decisions cover most projects:

  1. Use stdio when the AI client should launch and own a local server process.
  2. Use Streamable HTTP when the MCP server runs as an independent network service.
  3. Support legacy HTTP+SSE only while measured compatibility requirements justify it.

Streamable HTTP does not guarantee that every request is short. A tool can keep its POST response open as an SSE stream. An explicit subscriptions/listen request can also create a long-lived stream.

The improvement is control. Streaming is attached to the request that needs it instead of being the mandatory return path for the entire connection.

In short: MCP replaced a two-channel remote transport with a single-endpoint request model. Current Streamable HTTP can still use SSE, but it does so on a request response. Use Streamable HTTP for new remote servers, stdio for local child processes, and HTTP+SSE only for old-client compatibility.

Why Is “SSE vs Streamable HTTP” Not a Perfect Comparison?

SSE is an event-stream format, while Streamable HTTP is an MCP transport that can select SSE when incremental delivery helps.

Server-Sent Events defines how a server formats incremental events over an HTTP response. Streamable HTTP defines a broader MCP binding. That binding covers endpoints, HTTP methods, JSON-RPC framing, request metadata, response choices, cancellation, and compatibility.

This produces a category mismatch similar to comparing JSON with a REST API. JSON can appear inside the API, but it is not the complete API architecture.

TermWhat it namesRelationship to MCP
Server-Sent EventsAn event-stream format over HTTPCan carry JSON-RPC messages from server to client
`text/event-stream`The SSE media typeOne permitted current Streamable HTTP response type
HTTP+SSEThe original MCP remote transportDeprecated; used separate GET and POST endpoint roles
Streamable HTTPThe current MCP remote bindingUses POST requests and either JSON or SSE responses
HTTP streamingA general technique for sending a response incrementallyBroader than MCP and broader than SSE
stdioNewline-delimited messages over standard streamsCurrent standard binding for client-launched processes

The WHATWG HTML Living Standard defines event streams and the browser EventSource interface. The MCP specification defines how MCP messages use a transport.

MCP clients are not necessarily browser EventSource objects. Official SDKs can parse SSE inside Node.js, Python, Go, C#, or other runtimes. The relevant commonality is the event-stream wire format, not a requirement to use the browser API.

Wording also matters when discussing deprecation. “MCP deprecated SSE” is too broad. The accurate statement is that MCP deprecated the HTTP+SSE transport from revision 2024-11-05.

Current Streamable HTTP explicitly retains SSE. Therefore, removing every SSE parser from a client would make that client noncompliant with current remote transport behavior.

In short: SSE and Streamable HTTP sit at different levels. SSE formats a streaming HTTP response. Streamable HTTP defines how an MCP client and server exchange requests and responses. Compare legacy HTTP+SSE with Streamable HTTP, while recognizing that the latter still includes SSE.

What Is Server-Sent Events (SSE)?

Server-Sent Events is a UTF-8 HTTP event-stream format for sending ordered, incremental messages from a server to a client.

An SSE response uses the media type text/event-stream. The server sends line-oriented fields, and a blank line terminates one event. The WHATWG standard states that event streams are always decoded as UTF-8.

A current-MCP-compatible SSE response can look like this:

bash
SSE fieldGeneral meaningCurrent MCP consideration
`data`Adds data to the event payloadCarries a JSON-RPC message
`event`Names an event typeGeneric SSE field; not required for current MCP message framing
`id`Updates the client's last event IDRemoved from current MCP Streamable HTTP together with message redelivery
`retry`Suggests a reconnection delayGeneric SSE field; current MCP defines no stream resumption protocol
`:` commentCarries no event dataUseful as a keep-alive on long-lived quiet streams

SSE is one-way within a response. The server streams data toward the client after the client opens an HTTP request. A separate request is still needed for the client to send new application messages.

SSE also does not guarantee immediate delivery through every intermediary. A reverse proxy can buffer upstream response bytes. An idle timeout can close a quiet connection. A client can receive several events together if a gateway waits before flushing them.

The WHATWG standard describes automatic reconnection for browser EventSource, including Last-Event-ID. That general behavior must not be copied blindly into MCP. The 2026-07-28 changelog records the removal of both SSE event IDs and Last-Event-ID resumption from Streamable HTTP.

This distinction separates a wire format from the protocol using it. SSE supplies framing tools. MCP decides which fields and lifecycle rules are valid for a particular protocol revision.

In short: SSE sends UTF-8 events over an HTTP response using text/event-stream. Its fields include data, event, id, retry, and comments. MCP uses the format selectively and defines its own cancellation and recovery rules, which can differ from generic browser SSE behavior.

How Did MCP's Legacy HTTP+SSE Transport Work?

Legacy HTTP+SSE used one long-lived GET stream for server messages and a separate POST endpoint for client messages during a session.

MCP revision 2024-11-05 defined HTTP with SSE as one of two standard transports. Its transport specification required two endpoint roles.

bash

The 2024 transport required the POST but did not prescribe its HTTP response status. A displayed 202 Accepted therefore reflects implementation behavior rather than a requirement of the 2024-11-05 transport.

Current Streamable HTTP uses a narrower rule. Its sending-messages requirements require 202 Accepted with no body when a server accepts a JSON-RPC notification POST.

The connection followed four main steps:

  1. The client sent a GET request to the server's SSE endpoint.
  2. The server opened an event stream and sent an endpoint event.
  3. That event told the client which URI should receive future POST messages.
  4. The server sent JSON-RPC responses and notifications as SSE message events.

An illustrative opening event looked like this:

bash

The client then posted JSON-RPC to the advertised URI:

bash

The HTTP response to that POST did not need to carry the JSON-RPC result. The actual result traveled through the already-open SSE channel.

This design created a required association between the inbound POST and one live SSE connection. A single-process server can hold that mapping in memory. A distributed deployment needs a reliable way to send the result to the instance holding the stream.

That requirement can lead to connection affinity, shared routing state, or a message broker. Those components are deployment consequences, not extra requirements named by the 2024 specification.

The design also made SSE central even when a tool returned one small result. Every server message still needed the shared event stream.

In short: Legacy HTTP+SSE split one logical MCP conversation across a GET stream and an advertised POST endpoint. The POST accepted client messages, while the GET stream carried server messages. That coupling made connection routing part of the server's operating model for each connected client.

What Is MCP Streamable HTTP?

MCP Streamable HTTP is the remote binding where each JSON-RPC request uses one POST and receives JSON or request-scoped SSE.

Streamable HTTP first appeared in MCP revision 2025-03-26. The current 2026-07-28 shape exposes one MCP endpoint, such as https://mcp.example.com/mcp, that accepts POST.

bash

The binding has five defining properties:

PropertyCurrent behavior
EndpointOne MCP URL accepting POST
RequestOne JSON-RPC request per POST
ResponseOne JSON object or one SSE stream
MetadataProtocol version and capabilities are required per request; client information is recommended
SessionNo protocol-level session in revision `2026-07-28`

The word “Streamable” means a response can stream. It does not mean every response must stream. A server can return a normal JSON object when one response is enough.

The current binding also does not create a full-duplex WebSocket. The client sends requests through HTTP POST. The server answers within each request's response. Multi-step server-to-client input uses Multi Round-Trip Requests, or MRTR.

Long-lived notifications use the same request-oriented principle. A client sends subscriptions/listen, and the response remains open as an SSE stream. There is no unrelated, always-on GET channel.

This architecture separates transport choice from feature design. Tools, resources, and prompts retain MCP semantics. The transport decides how their JSON-RPC messages cross the process or network boundary.

In short: Streamable HTTP gives remote MCP a normal HTTP request boundary without losing incremental responses. Each POST stands alone, while the server chooses JSON or SSE. Current MCP also uses per-request metadata instead of a hidden transport session across ordinary HTTP infrastructure.

How Did MCP Transport Change From 2024 to 2026?

MCP transport moved from two-endpoint HTTP+SSE to session-based Streamable HTTP, then to stateless, POST-only Streamable HTTP.

The most common MCP transport mistake is treating every page labeled “Streamable HTTP” as equivalent. Three released eras have materially different wire behavior.

Protocol eraRemote transport shapeState and stream behaviorCurrent status
`2024-11-05`HTTP+SSE with separate GET and POST endpoint rolesShared long-lived SSE channelDeprecated
`2025-03-26` to `2025-11-25`One MCP endpoint supporting POST and GETOptional `Mcp-Session-Id`, standalone GET stream, server requests on SSE, resumable streamsSupported only when an implementation serves those revisions
`2026-07-28`One MCP endpoint accepting POSTPer-request metadata, no protocol session, request-scoped SSE without event-ID resumption, explicit subscriptionsCurrent

What changed in 2025?

The March 2025 specification replaced HTTP+SSE with Streamable HTTP. By revision 2025-11-25, every client message used a new POST to one MCP endpoint.

That endpoint also supported GET. A client could open a standalone SSE stream for server-initiated messages. A server could assign Mcp-Session-Id, and a client could terminate that session with DELETE.

The 2025 design also allowed SSE event IDs. A disconnected stream could resume through a GET carrying Last-Event-ID. The archived 2025-11-25 transport specification remains the right source when maintaining that era.

What changed in 2026?

The July 2026 revision removed the initialization handshake, standalone GET stream, protocol session, and SSE event-ID resumption. It added per-request metadata, header-based routing, MRTR, and explicit notification subscriptions.

The official release announcement describes the goal as a stateless protocol core. Any request can reach any compatible instance without shared protocol-session storage.

The current deprecated-features registry also marks Roots, Sampling, and Logging as deprecated. They remain functional during the deprecation window, but new implementations should not adopt them. Their earliest eligible removal is the first revision released on or after July 28, 2027; actual removal may happen later.

The HTTP+SSE transport has been deprecated since 2025-03-26. The registry says new implementations should not adopt it. It also separates earliest eligibility from actual removal, so teams should not invent a fixed removal date.

In short: MCP has used three remote HTTP shapes. The 2024 design used two channels. The 2025 design unified the endpoint but retained sessions and GET streams. The current 2026 design uses self-contained POST requests, optional SSE responses, MRTR, and explicit subscriptions; it also deprecates Roots, Sampling, and Logging.

How Does a Current Streamable HTTP Request Work?

Current Streamable HTTP requests send one JSON-RPC message by POST and receive either one JSON object or a scoped SSE stream.

The client must send an Accept header listing both supported response types. Body _meta must include the protocol version and client capabilities. Clients should also include their identity, while selected body fields are mirrored into HTTP headers.

An illustrative tool call looks like this:

bash

A server with one immediate result can return JSON:

bash

A server that needs incremental delivery can return an SSE response:

bash

The response examples include io.modelcontextprotocol/serverInfo in result _meta. The current result schema says servers should attach this self-reported identity to every result unless specifically configured not to do so. Clients may use it for display or debugging, but not for security or behavioral decisions.

The final JSON-RPC response should terminate that request stream. Independent server requests must not appear on it. Current server-to-client input uses MRTR instead.

The specification uses normative words such as MUST and SHOULD. SDKs normally implement this bookkeeping, but wire-level tests should still verify headers, content types, and close behavior.

In short: One modern POST normally contains the JSON-RPC request, protocol version, client identity, and capabilities. The response is either one JSON object or an SSE sequence ending in the matching result. The choice belongs to the server for that request at runtime, and servers should identify themselves in result metadata.

When Does Streamable HTTP Return JSON Instead of SSE?

Streamable HTTP can return JSON when one response is sufficient; clients must also accept SSE when the server needs incremental delivery.

The current specification does not impose a time threshold for choosing JSON. It defines two valid response types and requires clients to handle both.

Request behaviorSuitable responseReason
One result is ready without useful intermediate messages`application/json`Simplest lifecycle
Work produces meaningful progress notifications`text/event-stream`Delivers progress before completion
A request opts into MCP log notifications`text/event-stream`Carries `notifications/message`; Logging is deprecated
The client requests a long-lived notification subscription`text/event-stream`Keeps the subscription response open
The result is large but not incrementally encoded as MCP messagesImplementation dependentPayload size alone does not mandate SSE

JSON avoids stream-specific concerns when they add no value. Intermediaries can process one finite response, and clients can parse one object. The server still performs ordinary authentication, authorization, and JSON-RPC error handling.

SSE is useful when the server has multiple protocol messages to deliver before the final response. Those messages can include progress when the client supplies a progressToken.

Request-related notifications/message logs are allowed only when request _meta includes io.modelcontextprotocol/logLevel. MCP deprecated Logging in revision 2026-07-28, so new implementations should use OpenTelemetry for observability or stderr with stdio.

The client advertises both media types:

bash

The client should not advertise only JSON and then assume every compliant server must comply with that preference. Current Streamable HTTP requires support for both cases.

Nor should a server open an SSE response merely because “Streamable” appears in the transport name. Long-lived responses consume connection and runtime resources. JSON is the cleaner choice when no intermediate message is needed.

The right decision is semantic. Stream because multiple messages improve the request experience. Return JSON when one response fully represents the result.

In short: JSON is a first-class Streamable HTTP response, not a fallback mode. Use it for one-result requests. Use SSE when the server needs to deliver several request-related messages or maintain an explicit subscription. Clients must be ready for either response on every call; MCP Logging is now deprecated.

When Does Streamable HTTP Use SSE?

Streamable HTTP uses SSE for request-related progress and for explicit long-lived subscriptions to supported change notifications.

Current MCP defines two distinct reasons to keep an HTTP response open. They share SSE framing but have different scopes.

SSE stream typeOpened byWhat it can carryHow it normally ends
Request-scoped responseA tool, resource, prompt, or other request POSTRelated progress or log notifications, then the resultFinal JSON-RPC response
Subscription response`subscriptions/listen` POSTAcknowledgment, requested change notifications, and completionClient cancellation or graceful server completion

A request-scoped stream belongs to one JSON-RPC request. The server may send progress before the result. It must not use that stream for unrelated server requests.

A subscription stream is deliberately long-lived. The client names the change events it wants, and the server acknowledges the supported subset. This replaces the old generic GET listening channel.

Current Streamable HTTP adds four important boundaries:

  1. A final response should end a request-scoped stream.
  2. Closing that response stream signals cancellation of the associated request.
  3. SSE streams cannot resume through Last-Event-ID under the current revision.
  4. Quiet long-lived streams should use comment lines as keep-alives where needed.

The current receiving-messages rules recommend the response header X-Accel-Buffering: no. They also encourage periodic comment lines for long-lived streams.

Those measures address delivery, not replay. A comment can keep a connection active, but it does not create durable history. If a subscription drops, the client must re-establish it and recover application state appropriately.

In short: Current MCP uses SSE for two bounded jobs: incremental messages related to one request, and explicit change subscriptions. It no longer uses one general GET stream for the entire remote session. Stream purpose determines lifecycle, cancellation, and recovery in the protocol.

How Do Stateless MCP Requests Handle State and Server-to-Client Input?

Stateless MCP requests carry metadata each time and use explicit handles or MRTR results instead of hidden transport sessions.

Protocol statelessness does not forbid application state. A tool can create a job, transaction, cursor, or workflow and return an explicit handle. Later calls can pass that handle as a normal argument.

The important change is visibility. State is no longer attached implicitly through Mcp-Session-Id. It becomes part of the application's data contract.

State needCurrent patternExample
Client identity and capabilitiesPer-request `_meta`Client name, version, supported features
Long-running application workExplicit server-minted handle`job_id` returned by a tool
More user or model inputMulti Round-Trip RequestsConfirmation before a write
Change notifications`subscriptions/listen`Tool-list or resource update
Durable recoveryApplication designDatabase record or task extension

The current Multi Round-Trip Requests specification replaces standalone server-initiated JSON-RPC requests. Its basic flow has four steps:

  1. The client sends the original request.
  2. The server returns InputRequiredResult with requested input.
  3. The client gathers that input and retries the original operation.
  4. The server returns a final result when enough input is available.

MRTR still defines sampling/createMessage and roots/list input requests during their deprecation window. Roots and Sampling remain functional, but new implementations should follow the current migration guidance: use explicit tool parameters, resource URIs, or server configuration for files, and call model-provider APIs directly for sampling.

An abbreviated intermediate result can look like this:

json

The client must treat requestState as opaque. The server must treat the returned value as attacker-controlled. If it influences authorization, resource access, or business logic, the server must protect its integrity with a control such as HMAC or AEAD.

To limit replay, the server should bind protected state to the authenticated principal and originating request, then give it a short expiry. Integrity protection may be omitted only when tampering can do nothing worse than make the request fail.

MRTR makes each retry self-contained enough for another instance to process. It also means application developers must design duplicate protection and state validation deliberately.

In short: Current MCP moves state from an implicit transport session into request metadata, explicit tool arguments, and protected MRTR state. The protocol remains stateless while applications can retain durable workflows. That separation improves routing but increases the importance of explicit state design.

How Do Long-Lived MCP Notifications Work Without a GET Stream?

Long-lived MCP notifications use a subscriptions/listen POST whose SSE response carries only the event types a client requested.

Revision 2026-07-28 replaced the old GET listening stream and resources/subscribe RPC with one explicit message pattern. The subscriptions specification defines its filter, acknowledgment, message correlation, and closure.

bash

The request can ask for four current categories:

Filter fieldNotification requested
`toolsListChanged``notifications/tools/list_changed`
`promptsListChanged``notifications/prompts/list_changed`
`resourcesListChanged``notifications/resources/list_changed`
`resourceSubscriptions``notifications/resources/updated` for named URIs

The server's first stream message must be notifications/subscriptions/acknowledged. That message reports the subset the server agreed to honor.

Every later notification carries the subscription ID in _meta. The ID matches the JSON-RPC request ID that opened the subscription. A client can maintain several subscriptions and use those IDs to keep events separate.

Three closure cases matter:

  1. The client closes the HTTP response stream to cancel the subscription.
  2. The server returns a successful result before closing for a graceful shutdown.
  3. The underlying transport drops without a final result.

Current Streamable HTTP does not replay subscription events through Last-Event-ID. A robust client should reconnect, reopen the subscription, and refetch any state whose freshness matters.

That recovery pattern treats notifications as change signals rather than a durable event log. Applications needing guaranteed replay should add their own cursor or queue semantics outside the base transport.

In short: subscriptions/listen restores long-lived server notifications without restoring a generic GET channel. The client explicitly selects event types, the server acknowledges support, and each message carries a subscription ID. Recovery remains an application concern because current streams do not replay missed events.

How Do stdio, Legacy HTTP+SSE, and Streamable HTTP Compare?

stdio fits local child processes, legacy HTTP+SSE serves old remote clients, and Streamable HTTP fits new remote services.

The current MCP specification names two standard bindings: stdio and Streamable HTTP. Legacy HTTP+SSE remains a compatibility concern, not a third recommended choice.

Decision factorstdioLegacy HTTP+SSECurrent Streamable HTTP
DeploymentLocal child processRemote serviceRemote service
Who starts the server?MCP clientService operatorService operator
Message channelStandard input and outputSeparate POST and SSE GET rolesHTTP POST response
Network authenticationUsually environment or local controlsRequired for exposed servicesRequired for protected exposed services
StreamingBidirectional byte streamMandatory SSE return channelOptional request SSE or explicit subscription
Protocol sessionProcess relationshipConnection mappingNone in `2026-07-28`
Horizontal routingNot applicable to one local processRequires connection-aware designAny instance can handle a self-contained request
Main risk boundaryLocal code execution and environment accessRemote auth plus connection stateRemote auth, request policy, and streaming operations
Specification statusCurrentDeprecatedCurrent

stdio uses newline-delimited JSON-RPC over a process's standard streams. The client launches the executable and owns its lifecycle. Diagnostic output belongs on standard error because standard output must contain only valid MCP messages.

Legacy HTTP+SSE runs independently over the network. It remains relevant when a client configuration still names an SSE endpoint. The current TypeScript SDK still exposes SSEClientTransport as a fallback for those servers.

Current Streamable HTTP also runs independently, but each request owns its response. A deployment can still maintain application state, yet the protocol does not hide that state in a session header.

Custom transports remain possible. They should preserve MCP message semantics and document framing, cancellation, and connection behavior. A custom transport also creates an interoperability obligation, so it should solve a real constraint.

In short: Choose between the two current bindings by process boundary. stdio is local and client-launched. Streamable HTTP is remote and service-operated. Treat HTTP+SSE as a migration path only, even though some clients and SDKs retain compatibility classes during a controlled transition.

Which MCP Transport Should Developers Choose?

Developers should choose stdio for client-launched local servers and current Streamable HTTP for independently hosted remote servers.

Transport selection begins with ownership and placement, not with whether a tool might stream.

bash
ScenarioRecommended transportReason
Desktop assistant launches a filesystem toolstdioSimple local process lifecycle
IDE launches an npm MCP packagestdioNo independently hosted endpoint needed
Company hosts one server for many authorized clientsStreamable HTTPShared remote service boundary
SaaS product exposes MCP to customersStreamable HTTPNetwork auth, routing, and observability
Existing client only understands an SSE URLLegacy compatibilityTemporary interoperability need
Embedded runtime already has a reliable byte channelCustom or stdio framingDeployment-specific constraint

Streaming requirements do not change the first decision. stdio already carries multiple messages. Streamable HTTP can return SSE when required.

Security can change the architecture. A local stdio server runs with access available to its process. A remote server creates a network authorization boundary. Neither is automatically safer for every workload.

Client support also matters. Verify the exact SDK and product versions in use. A client that says “Streamable HTTP” may support only a 2025 protocol revision unless it advertises current behavior.

The official TypeScript SDK connection guide follows the same deployment distinction. It documents StdioClientTransport for local process-spawned servers and Streamable HTTP for remote endpoints.

In short: Pick transport from deployment topology. Local, client-owned processes use stdio. Independent network services use current Streamable HTTP. Add legacy HTTP+SSE only when real clients still need it, and record when that compatibility path can be retired through a measured migration plan.

Why Is Current Streamable HTTP Easier to Scale?

Current Streamable HTTP scales cleanly because requests carry their own metadata and do not depend on a protocol session or sticky route.

Revision 2026-07-28 requires the protocol version and client capabilities in every request. Clients should also include their identity. The server can validate and handle that request without retrieving an MCP session first.

Scaling concernSession-based approachCurrent per-request approach
Instance selectionRoute to session owner or share stateRoute to any compatible instance
Client capabilitiesStored from initializationSent in request `_meta`
Protocol versionNegotiated for sessionDeclared per request
Gateway routingOften parses path or bodyCan inspect `Mcp-Method` and `Mcp-Name`
Catalog freshnessRefetch after reconnect or notificationUse `ttlMs`, `cacheScope`, and invalidation notifications
Mid-call client inputServer request over live channelMRTR result and independent retry
Application stateCan be hidden in sessionExplicit handle or durable store

The official 2026-07-28 release states that a request can land on any instance behind a round-robin load balancer. No shared protocol-session store is required.

Header-based routing strengthens that model. Mcp-Method identifies the JSON-RPC method. Mcp-Name identifies a tool, resource, or prompt for selected operations.

A gateway can use those headers for routing, authorization, rate limiting, or metrics without parsing the JSON body. The origin server must still verify that mirrored headers match the body.

Caching is another 2026 scaling change. The current MCP caching specification requires ttlMs and cacheScope on complete results from server/discover, tools/list, prompts/list, resources/list, resources/templates/list, and resources/read.

json

ttlMs is a freshness hint, not a guarantee. cacheScope controls whether a cached result may cross authorization contexts. A server should use public only for non-user-specific data that is safe to share; a relevant change notification invalidates a still-fresh entry.

The result _meta also illustrates server identity. Servers should include io.modelcontextprotocol/serverInfo on every result unless specifically configured not to do so. That identity is self-reported and must not drive security decisions.

Stateless transport does not remove all affinity. An individual SSE response remains connected to the instance serving that HTTP request. A long-lived subscription also occupies one live response.

Application state can still require a database, queue, object store, or explicit handle. A browser automation tool may own a live browser process. A database transaction may belong to one worker.

The improvement is that MCP no longer creates hidden affinity for every operation. Teams add state only where the application actually needs it.

In short: Current Streamable HTTP removes protocol-session routing from ordinary requests. Per-request metadata and mirrored headers support conventional load balancing and policy. Cache hints can reduce unnecessary refetches, while result metadata identifies the server. Live streams and stateful tools still need deliberate runtime design.

When Is Streamable HTTP Still Operationally Difficult?

Streamable HTTP still needs streaming support, timeout control, retry safety, authentication, and compatibility testing in production.

Stateless does not mean effortless. It means the base protocol does not rely on a session. The network and application still have failure modes.

Operational challengeWhy it remainsPractical control
Long response streamsConnections consume runtime and gateway resourcesBound duration and test platform limits
Quiet subscriptionsIntermediaries may enforce idle timeoutsSend SSE comments and align timeouts
Response bufferingEvents may arrive in batchesDisable buffering and verify flush behavior
Ambiguous retryA disconnected write may have completedUse idempotency or operation lookup
Application stateSome tools own jobs, browsers, or transactionsReturn explicit handles and store state deliberately
Mixed client versions2024, 2025, and 2026 traffic differsLog negotiated era and test compatibility
AuthorizationRemote tools can affect real systemsApply least privilege per operation
Stream lossCurrent MCP provides no `Last-Event-ID` replayReconnect, refetch, or add durable application events

Serverless is a qualified fit. A stateless JSON tool call maps cleanly to a function invocation. A long-lived SSE response requires a platform that supports streaming and sufficient request duration.

Backpressure is also bounded by implementation. Holding a POST response open can tie work to the request lifecycle. An internal producer can still outrun the socket unless the server respects stream pressure.

Retries deserve special attention. A lost response does not prove the server failed before performing a side effect. Blindly repeating create_order, rotate_proxy, or delete_record can duplicate an action.

Version compatibility creates another layer. A 2025 Streamable HTTP client can send GET, Mcp-Session-Id, or Last-Event-ID. A current-only server handles those inputs differently.

The balanced conclusion is not that Streamable HTTP removes infrastructure. It gives infrastructure clearer request boundaries. Teams must still engineer the behavior at those boundaries.

In short: Streamable HTTP reduces hidden session complexity, but streams, gateways, side effects, and mixed versions remain operational work. Treat “stateless” as a routing property. It is not, by itself, a guarantee of short requests, replay, idempotency, low cost, or automatic security.

How Do You Migrate From Legacy HTTP+SSE to Streamable HTTP?

Migration requires a modern POST endpoint, updated clients, version-aware fallback, production stream tests, and measured legacy retirement.

Start by identifying the source era. A 2024 HTTP+SSE server needs a transport change. A 2025 Streamable HTTP server already has request POSTs, but it can still rely on GET streams and Mcp-Session-Id.

Starting pointMain migration work
2024 HTTP+SSEReplace the shared SSE return channel with request responses
2025 Streamable HTTPRemove handshake, GET stream, session header, and resumption assumptions
Mixed deploymentServe explicit compatibility paths and measure their use
New remote serverImplement current Streamable HTTP directly

A controlled migration follows twelve steps:

  1. Inventory client and server versions. Record SDK version, protocol revision, endpoint URL, and configured transport.
  2. Find legacy endpoints. Search configuration, documentation, and logs for /sse, advertised message URLs, and SSE transport classes.
  3. Add one current MCP POST endpoint. Use a distinct path such as /mcp when that avoids ambiguity.
  4. Return responses on their request. Send one JSON object or a request-scoped SSE stream.
  5. Add per-request metadata. Include the required protocol version and client capabilities in _meta, plus the recommended client identity.
  6. Add required HTTP headers. Mirror the protocol version, method, and applicable operation name.
  7. Replace server-initiated requests. Use MRTR for Elicitation. MRTR also carries Sampling and Roots during their deprecation window, but new implementations should use direct model-provider APIs and explicit tool, resource, or configuration inputs instead.
  8. Replace generic notifications. Use subscriptions/listen for supported long-lived change notifications.
  9. Remove transport-session dependence. Replace Mcp-Session-Id with explicit application handles when state remains necessary.
  10. Test through production intermediaries. Verify JSON, SSE flushing, quiet periods, disconnects, and authentication.
  11. Run dual support only when needed. Keep old routes isolated and observable during the compatibility window.
  12. Retire legacy traffic from evidence. Remove HTTP+SSE after supported clients stop using it.

An illustrative client configuration change might look like this:

json

Actual keys vary by client. Do not copy one product's configuration syntax into another without checking its current documentation.

The official MCP guidance allows servers to keep old SSE and POST endpoints beside the modern endpoint. That is a transition strategy, not a reason to make new clients choose the old path.

In short: Migrate both the endpoint and the lifecycle. Moving /sse to /mcp is incomplete if code still assumes initialization, session affinity, server-pushed requests, or replay. Measure old-client use, test the real network path, and remove compatibility only after evidence supports it.

How Should Clients Detect Modern and Legacy MCP Servers?

Clients should try a modern request, inspect recognized JSON-RPC errors, and fall back only when the response identifies a legacy server.

Blind fallback is unsafe and difficult to debug. An HTTP 400 can mean the server is modern but the request has a bad version, missing capability, or header mismatch.

The current versioning specification uses three terms:

EraMeaning
ModernRevision `2026-07-28` or later, with per-request metadata
LegacyRevision `2025-11-25` or earlier, with an initialization handshake
Dual-eraClient or server that supports both models

A modern server must implement server/discover. A client may call that method before other operations to learn the server's supported versions, although current MCP does not require a separate discovery round trip.

A dual-era HTTP client can follow this flow:

bash
ResponseLikely interpretationClient action
Successful modern JSON or SSEModern endpointContinue
`400` with `-32022`Modern server rejects requested versionChoose from advertised versions
`400` with `-32020`Modern header validation failedCorrect request
`404` with `-32601` JSON-RPC bodyModern server lacks that methodDo not assume legacy
`400`, `404`, or `405` without recognized modern bodyPossible legacy server or wrong pathContinue controlled fallback
SSE `endpoint` event after GETLegacy HTTP+SSE serverUse advertised POST URI

The current transport specification says clients should inspect a 400 body before falling back. It also describes the additional GET probe for the old HTTP+SSE transport.

Cache an era decision for the relevant server origin when appropriate. Re-probe when configuration changes or the cached assumption fails.

Do not convert authentication failures into transport fallback. A 401 or 403 should enter the authorization path, not trigger an attempt to use an older and potentially weaker transport.

In short: Transport detection is a protocol decision, not “try random URLs until one works.” Send a valid modern request first. Treat recognized modern errors as repair instructions. Fall back only when the status and response body indicate that the server belongs to an older era.

Which HTTP Headers Does Current Streamable HTTP Require?

Current Streamable HTTP requires version and method headers, plus a name header for tool, resource, and prompt operations.

The body remains the source of truth. The transport mirrors selected fields so gateways can route or enforce policy without parsing JSON.

HeaderDirectionRequirementPurpose
`Content-Type: application/json`RequestUsed for JSON-RPC POST bodyDeclares request representation
`Accept: application/json, text/event-stream`RequestRequired by Streamable HTTPAllows either valid response type
`MCP-Protocol-Version`RequestRequired on every current POSTMirrors body protocol version
`Mcp-Method`RequestRequired on every current requestMirrors JSON-RPC `method`
`Mcp-Name`RequestRequired for `tools/call`, `resources/read`, and `prompts/get`Mirrors `params.name` or `params.uri`
`Authorization: Bearer …`RequestRequired when the endpoint is protectedCarries an access token
`Origin`RequestValidate on every incoming connection; reject an invalid present value with `403`Helps prevent DNS rebinding
`X-Accel-Buffering: no`SSE responseRecommended by current MCPRequests immediate proxy forwarding

The MCP-Protocol-Version header must match io.modelcontextprotocol/protocolVersion in request _meta. Mcp-Method and Mcp-Name must match their JSON-RPC fields.

A mismatch requires HTTP 400 Bad Request and JSON-RPC error -32020, named HeaderMismatch. This validation prevents one component from authorizing a header value while the MCP server executes a different body value.

Current Streamable HTTP also supports Mcp-Param-* headers. A tool schema can mark certain primitive parameters with x-mcp-header, allowing gateways to inspect those values.

That feature needs strict handling:

  • Clients must mirror designated values.
  • Servers must compare recognized parameter headers with the body.
  • Header names are case-insensitive.
  • Method and parameter values remain case-sensitive.
  • Unsafe or non-ASCII values use the specification's Base64 sentinel encoding.
  • Intermediaries must forward unrecognized headers rather than inventing their meaning.

Do not place arbitrary secrets in mirrored tool-parameter headers. Headers are commonly logged by infrastructure. Schema authors should expose only values that genuinely support routing or policy.

In short: Current MCP headers make requests visible to HTTP infrastructure, but duplication creates a validation duty. Mirror version, method, and applicable name correctly. Validate header-body agreement on every request, protect authorization data, and use custom parameter headers only for deliberate policy needs.

How Do You Run Streamable HTTP Behind NGINX, Load Balancers, and API Gateways?

Streamable HTTP needs unbuffered SSE, compatible timeouts, forwarded MCP headers, secure routing, and disconnect testing at every hop.

A JSON response can work while streaming remains broken. Production verification must therefore test both response modes through the exact CDN, web application firewall, API gateway, load balancer, ingress, and reverse proxy path.

Hop behaviorFailure symptomRequired review
Buffers upstream responseProgress events arrive togetherDisable buffering for SSE
Uses a short idle timeoutQuiet subscription closesAlign timeout and keep-alive interval
Rejects long POST responsesStream ends before resultConfirm maximum request duration
Drops custom MCP headersServer returns header errorsPreserve and validate headers
Rewrites the MCP path`404` or legacy fallbackDefine one canonical endpoint
Caches responsesStale or cross-client data riskDo not cache request-specific responses
Retries POST automaticallyDuplicate side effectsDisable blind retries for mutations
Delays disconnect propagationCancelled work continuesTest client abort through every hop

NGINX's proxy module documentation says proxy_buffering is on by default. NGINX can disable it through configuration or an X-Accel-Buffering: no response header.

A minimal location might include:

bash

The 300s value is illustrative. Set it from measured request and quiet-subscription behavior. A keep-alive interval must be shorter than every relevant idle timeout.

AWS defines an Application Load Balancer's connection idle timeout as a period with no data sent or received. Other gateways use different names and limits.

Current MCP encourages an SSE comment line during quiet long-lived streams:

bash

The client ignores that line, but the bytes can keep an intermediary from treating the connection as idle.

Headers enable useful policy. A gateway can meter Mcp-Method: tools/call differently from tools/list. It can apply a rule to a named tool through Mcp-Name.

The origin still needs authorization and header-body validation. A gateway decision alone cannot make an unvalidated body safe.

In short: Test Streamable HTTP as a full request path, not just an application handler. Disable SSE buffering, align timeouts, preserve metadata, prevent unsafe POST retries, and verify cancellation through production infrastructure. One successful JSON call does not prove that long-lived streaming works.

How Should MCP Clients Handle Disconnects, Retries, and Cancellation?

MCP clients should treat a current SSE stream closure as cancellation and retry mutations only with explicit duplicate protection.

Disconnect semantics changed between MCP eras. Under 2025 Streamable HTTP, a disconnection did not necessarily cancel work, and streams could resume through Last-Event-ID. Under current Streamable HTTP, closing a request's SSE response is the cancellation signal.

The current cancellation specification requires servers to treat that disconnect as cancellation. Servers should stop work promptly and release associated resources.

EventWhat the client knowsSafe default
JSON response receivedRequest completed with that responseProcess once
SSE final result receivedStreamed request completedClose normally
Client intentionally closes SSECancellation was requestedDo not retry automatically
SSE drops before final resultCompletion is uncertainInspect operation state before retry
Subscription dropsNotifications may have been missedRe-listen and refetch relevant state
Request times out after side effectServer outcome may be unknownUse idempotency or status lookup
`429` or transient `5xx`Retry may be allowedRespect policy and operation semantics

Timeouts should exist for every request. That cancellation specification allows an implementation to reset a timeout after progress, but it recommends a maximum timeout even when progress continues.

Retries need operation awareness. Listing tools is naturally safer to repeat than creating a resource. A rotation or deletion can complete even when its response is lost.

MCP does not supply a universal HTTP idempotency key for every tool call. A tool can accept an operation identifier, return a durable job handle, or expose a lookup method. The right pattern belongs in the tool's contract.

Current streams do not support Last-Event-ID. Sending that header will not restore a request or subscription. A recovery workflow should query authoritative state instead of guessing from the last visible event.

In short: A disconnect is not a generic retry instruction. Current SSE closure cancels its request, while a lost response can leave the side effect uncertain. Use bounded timeouts, explicit idempotency, durable handles, and state lookup before safely repeating a mutating tool.

How Do You Secure a Remote Streamable HTTP MCP Server?

Remote Streamable HTTP MCP servers need Origin validation, authentication, token audience checks, authorization, and input validation.

Transport security protects the connection. Tool authorization protects the operation. A valid HTTP request must still be denied when its identity lacks permission for the named tool or resource.

RiskCurrent control
DNS rebinding against a local serverValidate `Origin`; bind local services to `127.0.0.1`
Unauthenticated remote callsRequire suitable authentication
Token sent to wrong serverValidate resource and audience binding
Token leakageUse the Authorization header, TLS, redacted logs, and secure storage
Header-policy confusionValidate mirrored header values against JSON body
Overpowered tool accessApply least privilege and per-operation authorization
Modified MRTR stateIntegrity-protect `requestState` and bind it to principal and request
Cross-user application handleAuthorize every handle lookup against the caller
Resource exhaustionBound request time, stream count, body size, and concurrency
Unsafe tool output or metadataTreat external content as untrusted and validate it

The current MCP authorization specification makes authorization optional for MCP as a whole. When HTTP authorization is implemented, it defines an OAuth-based flow and protected-resource discovery.

Access tokens belong in the Authorization header on every protected HTTP request. They must not appear in the URI query string. The MCP server must validate that a token was issued for that resource.

Do not accept a token merely because its signature is valid. Validate issuer, audience, expiry, scopes, and the operation being requested. Never pass an MCP access token through to an unrelated downstream API.

Current transport metadata is not authentication. Mcp-Method, Mcp-Name, client information, and the removed Mcp-Session-Id do not prove user identity.

Local servers also need care. Binding a development MCP server to 0.0.0.0 can expose it beyond the developer's machine. A local stdio package can read privileges from its environment, so install and run only trusted code.

In short: Secure remote MCP at several layers. Protect TLS and tokens, validate Origin, bind tokens to the MCP resource, authorize every operation, compare headers with the body, and validate explicit state. Transport compliance alone does not make an exposed tool safe.

Which SSE and Streamable HTTP Mistakes Cause MCP Failures?

SSE and Streamable HTTP failures usually trace to wrong-era endpoints, missing headers, buffering, timeouts, or unsafe retries.

The Five-Signal MCP Transport Test separates those failures by endpoint, method, response, state, and version.

SymptomLikely causeFirst check
GET `/mcp` returns `405`Server implements current POST-only transportConfirm negotiated revision
POST `/sse` returns `404`Client uses a legacy path against a modern serverChange to documented MCP URL
POST returns `400`Missing header, mismatch, capability, or version problemParse JSON-RPC error body
Client waits forever after `202`Legacy client expects shared SSE return pathVerify both old endpoint roles
Progress arrives at completionReverse proxy buffered SSEDisable buffering and inspect headers
Stream closes during quiet periodIdle timeoutAdd comments and align timeout values
GET or DELETE session workflow returns `405`Client assumes 2025 behaviorUse current per-request metadata
Resume loses messagesCurrent server ignores `Last-Event-ID`Re-listen and refetch state
Calls fail only after scaling outHidden session or local application stateTrace instance routing and handles
One mutation happens twiceClient or gateway retried POSTAdd idempotency and stop blind retries
Gateway allows one tool but another executesHeader and body were not comparedEnforce `HeaderMismatch` validation
Local server is reachable from another machineBound to all interfacesBind to loopback and add auth

Five wire signals provide a faster diagnosis:

  1. Endpoint: Does the client have one MCP URL or separate SSE and message URLs?
  2. Method: Is it sending current POST traffic, an older GET, or DELETE for a session?
  3. Response: Is the server returning JSON, request-scoped SSE, or a shared event stream?
  4. State: Does traffic carry an endpoint event, session ID, or per-request _meta?
  5. Version: Does the flow initialize a connection or declare the revision on each request?

Capture headers and status codes without logging tokens or sensitive tool arguments. Include the selected protocol revision, response content type, request ID, method, tool name, duration, and disconnect reason.

In short: Most transport failures become understandable once the wire era is known. First identify endpoint shape, HTTP method, response channel, state mechanism, and version behavior. Then fix the specific mismatch instead of changing unrelated tool code or repeatedly downgrading the connection.

Which MCP Transport Does the Proxidize MCP Server Use?

Proxidize's MCP server uses stdio: an MCP client launches a local Node.js process that manages proxies through the Proxidize API.

As of September 3, 2026, the open-source package runs through npx -y @proxidize/mcp. Claude Code, Claude Desktop, Cursor, Windsurf, or VS Code starts that process through its MCP configuration.

The current Proxidize MCP server source imports StdioServerTransport, connects the server to it, and logs that the server is running on stdio.

bash

This design means users do not choose between SSE and Streamable HTTP when installing the current package. The MCP client owns the local process and communicates through standard input and output.

The official Proxidize MCP server page explains that the server discovers active subscriptions and exposes relevant proxy-management tools. Those tools can rotate IPs, inspect usage, manage access points, and query analytics according to the account's available plans.

The API token belongs in the server environment. It should not be committed into a shared MCP configuration file. Local process transport removes the remote MCP authorization flow, but it does not make the API token or tool permissions harmless.

A future independently hosted version could use Streamable HTTP. That would be a separate deployment decision requiring remote authentication, authorization, tenancy, and operations. It is not how the current open-source package runs.

In short: The current Proxidize MCP server is a practical stdio example. The AI client launches it locally, and the process calls the Proxidize API with an environment token. SSE and Streamable HTTP apply when designing an independently hosted remote MCP service, not this installation path.

How Do MCP Transports and Web Proxies Fit Together?

MCP transports carry agent tool messages; web forward proxies route an application's outbound requests to public destinations.

The two systems can appear in one workflow without performing the same job. MCP is the control and capability interface. A forward proxy is part of the outbound network path.

bash
LayerMain purposeCommon protocolIdentity or control
MCP transportCarry tool, resource, prompt, and notification messagesstdio or Streamable HTTPMCP client, server, and tool authorization
Proxidize APIManage proxy infrastructureHTTPS APIProxidize API token
Forward proxyRoute selected outbound web requestsHTTP, HTTPS proxying, or SOCKS5Proxy credentials, location, and session settings
Public destinationServe the requested website or APIHTTP or HTTPSDestination authorization and site policy

An MCP tool can ask Proxidize to rotate a proxy or inspect usage. That tool call does not automatically route the AI host's other HTTP traffic through the proxy.

The crawler, browser, or data tool must configure the returned proxy endpoint separately. Its public request then travels through the selected exit network.

Proxidize Residential Proxies fit global public-web collection that needs broad country, city, or ISP selection. Proxidize Mobile Proxies fit workflows that specifically need real mobile carrier exits.

Use either product only for legitimate, authorized work. Proxies can support web scraping, AI data collection, SEO monitoring, price monitoring, market research, and brand protection. They do not grant permission to access a target.

The distinction also avoids a naming trap. A reverse proxy in front of an MCP endpoint manages inbound service traffic. A Proxidize forward proxy manages selected outbound traffic. The forward proxy, reverse proxy, API gateway, and egress gateway comparison explains those roles in detail.

In short: MCP transport and proxy transport belong to different connections. MCP carries agent instructions to a tool server. A forward proxy carries the tool's or application's outbound web request. Configure, authenticate, observe, and secure each boundary independently throughout the full stack.

What Should You Remember About SSE and Streamable HTTP?

SSE remains a streaming format inside current MCP, while Streamable HTTP is the standard remote transport for new implementations.

  • SSE remains part of current MCP. MCP deprecated its specific 2024-11-05 HTTP+SSE transport, not the underlying format.
  • One current endpoint accepts POST. Each JSON-RPC request receives JSON or request-scoped SSE; 2025-era sessions and GET streams are gone.
  • stdio remains current. Use it when an MCP client launches and owns a local server process.
  • Remote deployment adds an operations boundary. Test buffering, timeouts, cancellation, retries, authentication, and authorization.
  • Stateless transport is not stateless business logic. Use explicit, authorized handles for jobs or workflows that span requests.
  • Migration should be observable. Keep legacy endpoints only while supported clients generate real traffic.
  • MCP and forward proxies solve different problems. MCP carries tool messages; Proxidize routes selected outbound web requests.

The durable decision rule is simple. Pick stdio for a child process. Pick current Streamable HTTP for a remote service. Treat the word “SSE” as a clue that needs a second question: does it mean a response format or the deprecated two-endpoint MCP transport?

In short: A correct transport choice starts with process boundary and protocol revision. Current remote MCP uses stateless POST requests with optional SSE responses when useful. Local packages use stdio. Legacy HTTP+SSE belongs in a measured compatibility plan, not a new architecture.

FAQ

Got questions?
We've got answers.

Quick answers to the most common questions about this topic.

SSE is not deprecated as a web technology or response format. MCP's legacy HTTP+SSE transport is deprecated. Current Streamable HTTP still permits text/event-stream responses for request-related messages and explicit subscriptions.

Streamable HTTP still uses SSE when one POST needs incremental delivery. The stream can carry related notifications before the final result. A subscriptions/listen POST can also keep an SSE response open for selected change notifications.

Current Streamable HTTP does not support GET in MCP revision 2026-07-28. It defines one MCP endpoint that accepts POST. Earlier 2025 revisions supported GET, so the requested protocol version matters.

Current Streamable HTTP is stateless at the MCP protocol layer. Requests carry their own version and capabilities, and normally include client information. Applications can still maintain state through explicit handles, durable jobs, databases, or other authorized mechanisms.

Streamable HTTP can return one application/json object when no intermediate message is needed. Clients must also support text/event-stream, because the server may select SSE for another request.

No MCP requirement mandates HTTP/2. Streamable HTTP is defined through HTTP methods, headers, media types, and response behavior. Deployments should test the HTTP versions supported by their clients, servers, and intermediaries.

Streamable HTTP supports interaction in both logical directions, but not through one full-duplex connection. The client sends POST requests. The server answers through JSON or SSE. MRTR handles additional client input through later requests.

WebSockets are not a current standard MCP transport binding. The standard bindings are stdio and Streamable HTTP. An implementation can define a custom transport when it preserves MCP message semantics and documents framing and cancellation.

Current MCP requests do not require sticky sessions at the protocol layer. Any compatible instance can handle a self-contained request. One live SSE response remains attached to its serving connection, and application state can create separate routing needs.

MCP revision 2026-07-28 removed Mcp-Session-Id. The header belonged to initialization-based Streamable HTTP revisions through 2025-11-25. Current-only servers should not mint or echo it.

One MCP server can support modern and legacy clients through an explicit dual-era implementation. It can also retain separate HTTP+SSE endpoints during migration. Compatibility should be tested, logged, and eventually retired.

A current-only Streamable HTTP server should return 405 Method Not Allowed for GET or DELETE at the MCP endpoint. The client may be using 2025 session behavior or the wrong endpoint. Check its protocol revision before changing server code.

Ready to launch?

Proxies built for real operations.

For teams that depend on stability, not luck.