Skip to content

Migrate MCP transport from SSE to Streamable HTTP (spec 2026-07-28) #1750

Open

Description

@pm-dun86

Summary

Current MCP transport implementation uses the deprecated HTTP+SSE transport (2024-11-05 era) via mcp SDK 1.x, pinned <2 because of the decorator API (@mcp_server.list_tools()/@mcp_server.call_tool()) removed in SDK 2.x. Migrate to Streamable HTTP per the latest spec (2026-07-28).

Current state

  • src/codegraphcontext/api/mcp_sse.py: Server from mcp SDK 1.x, SseServerTransport("/api/v1/mcp/messages"), two endpoints (GET /api/v1/mcp/sse, POST /api/v1/mcp/messages), custom _SendTracker/_AlreadySentResponse shims to bridge SDK's raw ASGI writes with FastAPI.
  • src/codegraphcontext/api/app.py: wires both routes behind require_api_key.
  • src/codegraphcontext/server.py: separate hand-rolled stdio JSON-RPC loop (MCPServer._run_loop), duplicating tool-list/tool-call dispatch logic independently of the SSE path, advertising protocolVersion: 2025-03-26 manually.
  • pyproject.toml: mcp>=1.0.0,<2 pin with a comment explaining the 2.x decorator API removal blocks the upgrade.

Target state

  • Bump to mcp>=2,<3 (latest 2.2.0 already ships a _streamable_http_modern.py module purpose-built for spec 2026-07-28).
  • Replace mcp_sse.py's SseServerTransport/shims with mcp.server.lowlevel.Server(on_list_tools=..., on_call_tool=...) and its streamable_http_app(streamable_http_path="/api/v1/mcp", host="127.0.0.1", ...), mounted once. The SDK's StreamableHTTPSessionManager auto-classifies each request by MCP-Protocol-Version header and routes legacy Streamable HTTP clients (2025-03-26 through 2025-11-25, session-based) and modern 2026-07-28 clients (per-request, no session) to the correct internal handler — no manual dual-endpoint hosting needed for anything from 2025-03-26 onward.
  • Collapse the two existing routes (/api/v1/mcp/sse GET, /api/v1/mcp/messages POST) into the single mounted endpoint. Auth (require_api_key) needs rewiring onto the new mount (SDK's token_verifier/auth_server_provider params, or a wrapping FastAPI dependency/middleware).
  • Add Origin header validation (spec MUST, DNS-rebinding protection) — SDK's streamable_http_app auto-enables this for localhost, needs confirming/extending for the app's actual host config.
  • The oldest 2024-11-05 HTTP+SSE transport (standalone GET SSE stream + separate POST endpoint, pre-dating any session model) is NOT covered by the new SDK transport manager. Only keep the current literal /sse+/messages routes alive if a real client still needs that exact wire format; otherwise drop them.
  • Unify stdio (server.py) and HTTP tool dispatch where practical — both converge on the same request shape under 2026-07-28 (no session, per-request metadata), removing today's duplicated tool-list/tool-call logic.
  • Update/rewrite tests/unit/api/ for the new single-endpoint POST flow.

Non-goals

  • No changes required to mcp.server.stdio-based transport semantics beyond what naturally falls out of shared dispatch cleanup (stdio isn't touched by the 2026-07-28 transport revision itself).

Activity

  1. github-actions commented on Sep 30, 2026

    @github-actions
    Contributor

    Hi! 👋 Join our CodeGraphContext Discord channel to collaborate: https://discord.gg/dR4QY32uYQ

  2. Shashankss1205 commented on Oct 9, 2026

    @Shashankss1205
    Collaborator

    #1751 plus #1747 were combined locally with preserved awaited get_server calls in both MCP 2 handlers. All 43 API tests passed under MCP 2.3. The PR review records the integration adjustment. This issue remains open for stdio dispatch consolidation and transport acceptance beyond the HTTP migration.

  3. Shashankss1205 commented on Oct 15, 2026

    @Shashankss1205
    Collaborator

    Maintenance review — 15 October 2026

    #1772 integrates #1751 with #1747's awaited gateway binding. All 43 API tests pass under MCP 2.3, including auth/origin and legacy/modern transport checks. Stdio dispatch consolidation remains outside this transport PR.

  4. Shashankss1205 commented on Oct 15, 2026

    @Shashankss1205
    Collaborator

    The transport portion is now merged through #1772 (including #1751's original commits and the #1747 async integration). All CI checks pass, including Python builds, platform E2E and strict parity; all 43 dedicated API tests passed locally under MCP 2.3. New integrations can use /api/v1/mcp; legacy SSE remains supported with auth/Origin checks. Keeping this issue open for the explicitly separate stdio-dispatch consolidation.

  5. Shashankss1205 commented on Oct 15, 2026

    @Shashankss1205
    Collaborator

    Correction to the previous status: GitHub rejected #1772's merge with a stale/conflicting merge state after the batching integration landed. The source merges cleanly with current main locally; I am publishing that explicit merge and will wait for checks on the updated head. The transport work is reviewed, but is not yet merged.

  6. Shashankss1205 commented on Oct 15, 2026

    @Shashankss1205
    Collaborator

    Final verified status: #1772 merged successfully at 2908a70 after every updated-head check passed; original #1751 is now also marked merged. This supersedes the temporary merge-conflict status above. Streamable HTTP and the retained legacy SSE routes are on main, with serving-loop binding and auth/Origin checks covered. The final combined source passes 1,695 unit tests (8 skipped). Keeping #1750 open for the separate stdio-dispatch consolidation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions