Skip to main content
All posts

Migrate Your Claude Connector from SSE to Streamable HTTP (August 2026)

Abe Wheeler
Claude ConnectorsClaude Connector FrameworkClaude Connector TestingMCP AppsMCP App FrameworkMCP App TestingStreamable HTTPMCP 2026-07-28
Migrate your Claude Connector from legacy HTTP+SSE to dual-era Streamable HTTP.

Migrate your Claude Connector from legacy HTTP+SSE to dual-era Streamable HTTP.

If your Claude Connector still exposes GET /sse and a separate message endpoint, migrate it. Claude still accepts the old HTTP+SSE transport, but its current connector documentation says that transport is being deprecated in favor of Streamable HTTP.

The target changed in July 2026. Streamable HTTP was first introduced in MCP 2025-03-26, then MCP 2026-07-28 removed the initialization handshake, transport sessions, standalone GET stream, and DELETE session termination. A safe migration now needs to account for two Streamable HTTP eras while Claude and other hosts update.

TL;DR: Move new traffic to one /mcp endpoint and use a current MCP SDK that serves both 2025 and 2026 protocol eras. Keep legacy /sse routes only for measured fallback traffic. Do not copy the old MCP-Session-Id design into the modern path. Validate Origin, preserve OAuth challenges, let the SDK validate the 2026 routing headers, disable proxy buffering for SSE responses, and test each protocol era independently before removing old routes.

There Are Three Remote Transport Shapes

The phrase “SSE migration” can hide three different wire contracts:

Transport shapeProtocol eraEndpoint methodsBootstrapServer state
HTTP+SSE2024-11-05GET /sse plus a separate POST routeEndpoint event over SSEOne long-lived connection
Streamable HTTP with sessions2025-03-26 through 2025-11-25POST, optional GET, optional DELETE on /mcpinitialize and notifications/initializedOptional MCP-Session-Id
Stateless Streamable HTTP2026-07-28POST /mcpOptional server/discover, then self-contained requestsNo protocol session

All three can carry SSE, but SSE has a different job in each one. In HTTP+SSE, the long-lived stream is the transport. In 2025 Streamable HTTP, POST responses and a standalone GET can use SSE. In 2026 Streamable HTTP, a POST response may use SSE for progress and its final result, while subscriptions/listen uses a long-lived response stream for change notifications.

That distinction matters at your CDN, load balancer, application router, and test harness. A route that accepts text/event-stream is not enough to prove that the server speaks the right MCP transport.

What Claude Supports Today

Claude’s custom connector documentation says:

  • Claude supports Streamable HTTP and legacy HTTP+SSE.
  • HTTP+SSE is being deprecated in favor of Streamable HTTP.
  • Claude.ai and Claude Desktop allow about 150,000 characters in a tool result.
  • Claude.ai and Claude Desktop use a five-minute tool timeout.
  • Resource subscriptions, Sampling, and advanced draft capabilities are not currently supported.

The same page lists the 2025 MCP authorization revisions but does not promise the 2026-07-28 core wire format. The Claude API MCP connector also uses the mcp-client-2025-11-20 beta interface and supports tools over public Streamable HTTP or SSE servers.

The practical conclusion is narrow: migrate away from HTTP+SSE, but do not make your Claude production endpoint 2026-only yet. Serve 2025-era Streamable HTTP for current Claude traffic and add 2026-era support on the same endpoint for clients that negotiate it.

What MCP 2026-07-28 Changed

The current Streamable HTTP specification uses one POST endpoint. Each JSON-RPC request or notification gets its own HTTP request.

The modern request carries routing and identity data on every call:

POST /mcp HTTP/1.1
Content-Type: application/json
Accept: application/json, text/event-stream
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: search_tickets
Authorization: Bearer <token>
{
  "jsonrpc": "2.0",
  "id": 42,
  "method": "tools/call",
  "params": {
    "name": "search_tickets",
    "arguments": { "status": "open" },
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientInfo": {
        "name": "connector-test",
        "version": "1.0.0"
      },
      "io.modelcontextprotocol/clientCapabilities": {}
    }
  }
}

The server must reject a mismatch between the headers and body. Mcp-Method mirrors the JSON-RPC method. Mcp-Name carries the tool name, prompt name, or resource URI for methods that address a named item. These headers let a gateway route, meter, and authorize traffic without parsing the JSON body, but the server still needs to compare them with the body.

The modern transport also changes these behaviors:

  • No initialize or notifications/initialized exchange.
  • No MCP-Session-Id.
  • No standalone GET /mcp stream.
  • No DELETE /mcp session termination.
  • No resumable SSE through Last-Event-ID.
  • Client notifications return 202 Accepted with no body.
  • Closing a request’s SSE response cancels that request.
  • server/discover lets a client inspect versions and capabilities before its first business request.
  • Multi Round-Trip Requests return input_required when a tool needs client input.
  • subscriptions/listen replaces the old standalone GET stream for change notifications.

Use the official SDK for this logic. Hand-written version negotiation, header encoding, response status mapping, and multi-round-trip retries create a large compatibility surface for little benefit.

Set the Migration Goal Before Editing Code

Choose one of these targets:

TargetWhen it fitsTradeoff
2025-era Streamable HTTP onlyShort bridge for current hostsRequires another migration for modern clients
Dual-era Streamable HTTPMost production Claude ConnectorsOne endpoint works with current and modern clients
Dual-era plus HTTP+SSE fallbackExisting old clients still send /sse trafficMore routes, tests, and proxy rules during rollout
2026-only Streamable HTTPControlled clients you ownCurrent Claude support is not documented

For a public Claude Connector, dual-era Streamable HTTP is the best default. Add HTTP+SSE fallback only when logs show a real old client population.

Inventory these dependencies before the change:

  • Every public connector URL and redirect.
  • OAuth metadata and callback URLs tied to the old path.
  • WAF, CORS, CDN, and reverse-proxy method rules.
  • Session maps, sticky routing, and shared session storage.
  • Tool code that reads state from a transport session.
  • Server-to-client requests such as elicitation or Sampling.
  • Resource subscriptions and list-change notifications.
  • Client versions and user agents seen in production logs.
  • Stream timeouts and response buffering at every hop.

This inventory tells you whether you can replace HTTP+SSE in one release or need a measured compatibility window.

TypeScript: Move to the Dual-Era Server API

The MCP TypeScript SDK v2 adds createMcpHandler, which serves modern Streamable HTTP and stateless 2025-era clients from one server factory. It replaces the v1 pattern where application code constructs a StreamableHTTPServerTransport and connects one server instance to it.

import { createMcpHandler, McpServer } from '@modelcontextprotocol/server';
import * as z from 'zod/v4';

const handler = createMcpHandler(() => {
  const server = new McpServer({
    name: 'support-connector',
    version: '2.0.0',
  });

  server.registerTool(
    'search_tickets',
    {
      description: 'Search support tickets by status',
      inputSchema: z.object({
        status: z.enum(['open', 'closed']),
      }),
    },
    async ({ status }) => ({
      content: [{ type: 'text', text: `Found tickets with status ${status}.` }],
    })
  );

  return server;
});

export default handler;

The factory creates an MCP server for each request, so keep it cheap. Create database pools, HTTP clients, and caches once at module scope, then close over them. The handler has no transport session to preserve for modern requests.

On Cloudflare Workers, Deno, or Bun, the web-standard handler can be the export. Node frameworks use the official Node adapter. Use the framework’s MCP application factory when one exists because those factories configure localhost Host and Origin checks by default.

The handler does not authenticate callers for you. Verify the bearer token before invoking it and pass the resulting authorization context into the handler. Keep OAuth protected-resource metadata and WWW-Authenticate behavior outside the transport factory.

Python: Upgrade the Same Streamable HTTP App

The MCP Python SDK v2 also serves both eras from one streamable_http_app(). A minimal FastMCP server stays compact:

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("support-connector")


@mcp.tool()
def search_tickets(status: str) -> str:
    """Search support tickets by status."""
    return f"Found tickets with status {status}."


app = mcp.streamable_http_app()

In the Python SDK, stateless_http=True controls how 2025-era clients are served. It does not switch the modern protocol on or off. Modern requests are already sessionless, and the same application can answer both eras.

If a tool calls ctx.elicit() or another client request, test it carefully after upgrading. A 2026 client has no backchannel for a server-pushed request. The modern replacement returns an input request, then the client retries the original call with inputResponses. The Python v2 SDK supports era-portable resolvers so one tool can work with a 2025 session and a 2026 multi-round-trip request.

Replace Hidden Session State With Handles

MCP 2026-07-28 removes protocol sessions, but your application can still run a stateful workflow. Make that state explicit:

{
  "content": [{ "type": "text", "text": "Created refund review." }],
  "structuredContent": {
    "reviewId": "review_7f31",
    "status": "pending"
  }
}

The next tool takes reviewId as an input. Store the workflow in a database or durable store keyed by that handle. Authorize every access against the current user instead of treating possession of the handle as permission.

This pattern gives you normal horizontal scaling because any replica can handle the next request. It also makes state visible in schemas, logs, traces, and tests.

For multi-round-trip input, the server may return an opaque requestState that the client echoes on retry. If replicas use signed or encrypted request state, share and rotate the sealing keys across instances. Do not rely on a process-local key in a multi-region deployment.

Keep HTTP+SSE Only as a Measured Fallback

If production logs still show clients opening /sse, keep the old endpoints beside /mcp for one release window:

GET  /sse       -> legacy HTTP+SSE handler
POST /messages  -> legacy HTTP+SSE message handler
POST /mcp       -> dual-era Streamable HTTP handler
GET  /mcp       -> 2025-era Streamable HTTP handler or 405
DELETE /mcp     -> 2025-era session termination or 405

Do not make /sse and /mcp aliases. They have different bootstraps, response rules, and state models. Separate routes make access logs useful and let you remove the old pair without touching the new endpoint.

Track at least the route, protocol version, client identity, response code, latency, and transport era. Remove the HTTP+SSE routes only after a full release cycle with no expected traffic. Keep a rollback that restores the routes without rolling back tool schemas or OAuth metadata.

Update the Gateway and Proxy

Most migration failures happen before the MCP handler runs.

Methods and routing

Allow POST /mcp for all Streamable HTTP clients. A dual-era endpoint may also need GET and DELETE for 2025 traffic. Modern GET and DELETE requests should receive 405 Method Not Allowed.

Expose MCP-Protocol-Version, Mcp-Method, and Mcp-Name to logs and policy rules. Do not let a gateway rewrite them. The SDK should reject a header and body mismatch with 400 Bad Request.

Response types

Clients send Accept: application/json, text/event-stream because the server can return a JSON response or an SSE response for the same method. Test both. A tool that emits progress may stream while a fast read returns JSON.

For SSE responses, disable proxy buffering. The current specification recommends X-Accel-Buffering: no and periodic SSE comment lines for quiet long-lived subscription streams. Configure CDN and load-balancer idle timeouts above the application’s heartbeat interval.

Origin and Host validation

Validate Origin on incoming Streamable HTTP requests and return 403 for a disallowed origin. Bind local servers to 127.0.0.1, then validate Host too so an attacker-controlled DNS name cannot reach the loopback service through a browser.

Do not use Access-Control-Allow-Origin: * with credentials. Allow only the web origins that actually call the endpoint, and expose any legacy session headers only while old browser clients need them.

OAuth

Apply authentication consistently to every supported method and era. An unauthenticated request should receive 401 Unauthorized with the correct WWW-Authenticate challenge and resource metadata URL. An insufficient-scope request should receive the appropriate scope challenge instead of a successful MCP result containing an auth error.

Keep tokens out of query strings and logs. Validate the token audience against the MCP resource, and make sure a connector path change does not leave protected-resource metadata pointing at /sse or /messages.

Test Each Era as a Separate Contract

A single successful Claude conversation does not prove the migration. Run protocol tests that pin each supported era.

TestHTTP+SSE fallbackStreamable HTTP 2025Streamable HTTP 2026
Bootstrap succeedsEndpoint eventinitializeserver/discover or direct request
Tool list and call succeedYesYesYes
Session header behaviorConnection-ownedOptional and echoedIgnored, never minted
GET streamRequiredOptional405
DELETE sessionN/AOptional405
JSON responseNoYesYes
Request-scoped SSE responseNoYesYes
Invalid Origin403403403
Missing auth401 challenge401 challenge401 challenge

Add these modern assertions:

  1. MCP-Protocol-Version matches the protocol version in _meta.
  2. Mcp-Method and Mcp-Name match the JSON-RPC body.
  3. Unsupported versions return 400 with the server’s supported versions.
  4. A client notification receives 202 with an empty body.
  5. Closing a streaming response cancels the corresponding work.
  6. A multi-round-trip retry works on a different replica.
  7. Explicit workflow handles survive deploys and regional failover.
  8. subscriptions/listen receives only authorized notification types.

Run the same tests through the production proxy, not only against localhost. That catches buffering, method filters, stripped headers, auth middleware order, body-size limits, and idle timeouts.

Test the Current Claude Path With sunpeak

sunpeak can connect to a Streamable HTTP server and run protocol, inspector, E2E, visual, and live-host tests. Its local Inspector replicates Claude and ChatGPT MCP App runtimes, which lets you test tool results, host bridge behavior, display modes, themes, and app-initiated tool calls without spending host credits on each code change.

For an existing connector:

npx sunpeak test init --server http://127.0.0.1:8000/mcp
npx sunpeak inspect --server http://127.0.0.1:8000/mcp

Be precise about the version boundary. sunpeak 0.20.x uses the v1 TypeScript SDK and tests the 2025-era wire format. stateless: true in sunpeak/mcp removes session tracking for that older wire format, but it does not add server/discover, the modern request envelope, or Mcp-Method routing.

Use sunpeak to cover the current Claude and ChatGPT paths and the rendered MCP App. Add a current official TypeScript, Python, Go, or C# SDK client to CI for 2026-07-28 conformance. Then connect the deployed URL in Claude under Customize > Connectors and run one live smoke test for every high-risk read, write, and OAuth flow.

Migration Checklist

Before removing the old routes, confirm:

  • /mcp serves current Claude Streamable HTTP traffic.
  • A modern client negotiates or pins 2026-07-28 successfully.
  • HTTP+SSE traffic is measured and has a removal date.
  • Modern requests never depend on MCP-Session-Id.
  • Application state uses explicit, authorized handles.
  • Multi-round-trip request state works across replicas.
  • Gateway logs include protocol version, method, name, status, and latency.
  • Origin, Host, CORS, and OAuth checks run before the MCP handler.
  • JSON and SSE responses both pass through the production proxy.
  • Streaming responses are not buffered and cancellation stops work.
  • 2025 GET and DELETE behavior is isolated from modern POST behavior.
  • Rollback can restore old routes without reverting tool contracts.
  • Protocol tests, sunpeak host tests, and live Claude smoke tests pass.

The endpoint change is the easy part. The work is separating old connection state from application state, serving both Streamable HTTP eras while hosts update, and proving that your proxy and auth layers preserve the protocol. Once those contracts are covered in CI, removing /sse becomes a routine cleanup instead of a production gamble.

Get Started

Documentation →
npx sunpeak new

Further Reading

Frequently Asked Questions

Is SSE deprecated for Claude Connectors?

The legacy HTTP+SSE transport is deprecated. Claude still supports it, but Claude documents Streamable HTTP as the production transport and says HTTP+SSE is being deprecated. SSE itself is not gone: Streamable HTTP may return a request-scoped text/event-stream response, and MCP 2026-07-28 uses an SSE response for subscriptions/listen.

What is the difference between HTTP+SSE and Streamable HTTP?

HTTP+SSE uses a long-lived GET /sse connection plus a separate POST endpoint for client messages. Streamable HTTP uses one MCP endpoint. In MCP 2025 revisions that endpoint supports POST, GET, and optional sessions. In MCP 2026-07-28 every request is a self-contained POST, with optional SSE only on that request response or a subscriptions/listen response.

Does Claude support MCP 2026-07-28?

Claude documents Streamable HTTP support, but its custom connector documentation currently lists 2025-03-26, 2025-06-18, and 2025-11-25 authorization specifications and does not promise the 2026-07-28 core wire format. Deploy a dual-era server that accepts Claude's current traffic and modern 2026 clients instead of making the production endpoint modern-only.

What happened to MCP-Session-Id in MCP 2026-07-28?

MCP 2026-07-28 removed protocol sessions and MCP-Session-Id. Each request carries its protocol version, client identity, and capabilities. A server that needs application state should return an explicit handle, such as cartId or workflowId, and accept it on later tool calls. Keep session handling only for older Streamable HTTP clients.

Does a modern Streamable HTTP server need GET and DELETE handlers?

A modern MCP 2026-07-28 endpoint requires POST. GET and DELETE belong to 2025-era Streamable HTTP and should return 405 for modern-only traffic. A dual-era deployment may still route GET and DELETE to its legacy handler while using POST for both eras.

Can one MCP server support old and new Streamable HTTP clients?

Yes. The current official TypeScript and Python MCP SDKs can serve the 2025 and 2026 eras from one endpoint. A modern client probes server/discover and a 2025 client uses initialize. Keep legacy HTTP+SSE on separate routes only while measured client traffic still needs it.

How should I test a Claude Connector transport migration?

Test legacy HTTP+SSE, 2025-era Streamable HTTP, and 2026-era Streamable HTTP as separate contracts. Verify methods, headers, status codes, JSON and SSE responses, Origin validation, OAuth challenges, proxy buffering, cancellation, and explicit state handles. Then run tool and MCP App tests in Claude and every other supported host.

Does sunpeak stateless mode enable MCP 2026-07-28?

No. sunpeak 0.20.x uses the MCP TypeScript SDK v1 wire format. Its stateless option removes server-side session tracking for 2025-era requests, which helps serverless deployment, but it does not add server/discover or the 2026-07-28 request envelope. Use sunpeak for current Claude and ChatGPT host tests, and add a current official SDK client for the modern wire contract.