Skip to content

Commit 429ef3e

Browse files
committed
Deprecate the legacy HTTP+SSE transport
The HTTP+SSE transport was superseded by Streamable HTTP in the 2025-03-26 spec revision and is formally deprecated under SEP-2596. Mark every public entry point with typing_extensions.deprecated so type checkers flag it and a runtime MCPDeprecationWarning fires: sse_client, SseServerParameters, SseServerTransport, MCPServer.sse_app / run_sse_async, and the run(transport="sse") overload. Nested constructions suppress the inner warning so callers see exactly one. Also: mcp run --transport help text drops sse, python -m mcp.client connects with Streamable HTTP, and the url_elicitation client snippet moves to Streamable HTTP. Docs and migration guide updated. No-Verification-Needed: user requested immediate push, verification explicitly waived
1 parent 528e366 commit 429ef3e

26 files changed

Lines changed: 238 additions & 78 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ The [Model Context Protocol](https://modelcontextprotocol.io) lets you build ser
3232

3333
- **Build MCP servers** that expose tools, resources, and prompts to any MCP host
3434
- **Build MCP clients** that connect to any MCP server
35-
- Speak every standard transport: stdio, Streamable HTTP, and SSE
35+
- Speak every standard transport: stdio and Streamable HTTP, plus the deprecated legacy HTTP+SSE
3636

3737
## Requirements
3838

docs/client/session-groups.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Create a `ClientSessionGroup` and call **`connect_to_server`** once per server:
2424
--8<-- "docs_src/session_groups/tutorial003.py"
2525
```
2626

27-
* `connect_to_server` takes transport parameters, not a server object: `StdioServerParameters` (from `mcp`) to launch a subprocess, or `StreamableHttpParameters` / `SseServerParameters` (from `mcp.client.session_group`) for a server already listening on a URL.
27+
* `connect_to_server` takes transport parameters, not a server object: `StdioServerParameters` (from `mcp`) to launch a subprocess, or `StreamableHttpParameters` (from `mcp.client.session_group`) for a server already listening on a URL. `SseServerParameters` is still accepted for a server on the deprecated HTTP+SSE transport, and warns.
2828
* `group.tools` is a `dict[str, Tool]` of every connected server's tools. `group.resources` and `group.prompts` are the same shape.
2929
* `group.call_tool(name, arguments)` looks the name up, finds the session that owns it, and forwards the call. You never say which server.
3030

docs/client/transports.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ Leaving the `async with` block also shuts the subprocess down: close stdin, wait
102102

103103
## SSE
104104

105-
`sse_client(url)`, from `mcp.client.sse`, is the HTTP transport that Streamable HTTP superseded. Wrap it the same way, `Client(sse_client("http://localhost:8000/sse"))`, to talk to a server that still speaks it, and don't build anything new on it.
105+
`sse_client(url)`, from `mcp.client.sse`, is the HTTP transport that Streamable HTTP superseded, and it is now formally deprecated ([SEP-2596](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2596)): calling it emits `MCPDeprecationWarning` (see **[Deprecated features](../deprecated.md)**). Wrap it the same way, `Client(sse_client("http://localhost:8000/sse"))`, to talk to a server that still speaks it, and don't build anything new on it.
106106

107107
## The `Transport` protocol
108108

docs/deprecated.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Deprecated features
22

3-
The 2026-07-28 spec retires five things. The SDK still implements every one of them, and every one of them now carries a **deprecation warning**.
3+
The 2026-07-28 spec retires five things, and the spec's deprecation registry carries a sixth from earlier: the legacy HTTP+SSE transport. The SDK still implements every one of them, and every one of them now carries a **deprecation warning**.
44

55
The table below names each deprecated feature, why it is going away, and the replacement to build on.
66

@@ -13,18 +13,20 @@ The table below names each deprecated feature, why it is going away, and the rep
1313
| **Protocol logging**: `ctx.log()`, `ctx.debug()`, `ctx.info()`, `ctx.warning()`, `ctx.error()`, `ctx.session.send_log_message()`, `client.set_logging_level()` | SEP-2577 retires the capability. Nothing in-protocol replaces it. | Ordinary `import logging` to stderr (see **[Logging](handlers/logging.md)**). |
1414
| **`ping`**: `client.send_ping()` | **Removed** from the protocol, not merely deprecated. There is no `ping` method in 2026-07-28. | Nothing. It only works against a `mode="legacy"` connection. |
1515
| **Client->server progress**: `client.send_progress_notification()` | 2026-07-28 makes progress server->client only. | Nothing to send. Your *server* reports progress with `ctx.report_progress()` (see **[Progress](handlers/progress.md)**). |
16+
| **HTTP+SSE transport**: `sse_client()`, `SseServerParameters`, `mcp.sse_app()`, `mcp.run(transport="sse")`, `SseServerTransport` | Superseded by Streamable HTTP in the 2025-03-26 spec; [SEP-2596](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2596) formally classifies it as deprecated. | Streamable HTTP: `Client(url)` / `streamable_http_client()` on the client, `mcp.run(transport="streamable-http")` / `streamable_http_app()` on the server (see **[Running your server](run/index.md)** and **[Transports](client/transports.md)**). |
1617

17-
Three things fall out of that table:
18+
Four things fall out of that table:
1819

1920
* Roots, sampling, and logging go together. One proposal, **SEP-2577**, deprecates all three capabilities at once.
2021
* Sampling and roots share a deeper problem: they are places a **server** sends a **request** to the **client**. That whole direction is what 2026-07-28 replaces with **[Multi-round-trip requests](handlers/multi-round-trip.md)**. It is the standalone RPC methods (`sampling/createMessage`, `roots/list`, and push-style `elicitation/create`) that are gone; the `CreateMessageRequest` / `ListRootsRequest` / `ElicitRequest` payload types survive, embedded in `InputRequiredResult.input_requests`, and on the client they hit the same callbacks.
2122
* `ping` is the odd one out. The protocol does not deprecate it, it removes it. The SDK method still warns (its message says *removed*, not *deprecated*) and calling it on a modern connection answers with *"Method not found"*.
23+
* The transport is odd in the other direction: it is not part of the 2026-07-28 story at all. Streamable HTTP superseded HTTP+SSE back in 2025-03-26, and it has been the "don't build on it" transport ever since; SEP-2596's feature-lifecycle policy simply put it on the formal register. It is also the only row that is a transport rather than a capability, so it doesn't turn on the negotiated version: the same `streamable_http_app()` serves both eras of client (see **[Serving legacy clients](run/legacy-clients.md)**), and nothing needs SSE.
2224

2325
## Deprecated is advisory
2426

2527
Nothing breaks today.
2628

27-
Every method above keeps working against any session that negotiated **2025-11-25 or earlier**. Pin `mode="legacy"` on the client and you get exactly the pre-2026 behaviour. There are no wire changes and capability negotiation is unchanged.
29+
Every method above keeps working against any session that negotiated **2025-11-25 or earlier**. Pin `mode="legacy"` on the client and you get exactly the pre-2026 behaviour. There are no wire changes and capability negotiation is unchanged. The transport row is simpler still: `sse_client()` and `sse_app()` do exactly what they always did, wire and all; they just warn when you call them.
2830

2931
What changes is that you get a visible warning the first time each one runs:
3032

@@ -82,7 +84,8 @@ That is the whole API. There is no per-method switch, and you don't want one: th
8284
## Recap
8385

8486
* The 2026-07-28 spec deprecates **roots**, server-initiated **sampling**, and protocol **logging** (all [SEP-2577](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577)), restricts **progress** to server-to-client, and removes **`ping`**.
85-
* The replacement column points you onward: **[Multi-round-trip requests](handlers/multi-round-trip.md)** for sampling and roots, **[Logging](handlers/logging.md)** for logging, **[Progress](handlers/progress.md)** for progress. `ping` needs nothing at all.
87+
* The legacy **HTTP+SSE transport** is deprecated too ([SEP-2596](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2596)), superseded by Streamable HTTP since 2025-03-26.
88+
* The replacement column points you onward: **[Multi-round-trip requests](handlers/multi-round-trip.md)** for sampling and roots, **[Logging](handlers/logging.md)** for logging, **[Progress](handlers/progress.md)** for progress, Streamable HTTP for the transport. `ping` needs nothing at all.
8689
* Deprecated is advisory: no wire changes, everything keeps working against pre-2026 sessions, and you get a visible `MCPDeprecationWarning` (a `UserWarning`, so it is on by default).
8790
* Sampling and roots additionally need a back-channel that a 2026-07-28 session does not have. On a modern connection they warn and then they raise.
8891
* `warnings.filterwarnings("ignore", category=MCPDeprecationWarning)` silences the whole category; `"error::mcp.MCPDeprecationWarning"` in pytest turns it into a test failure.

docs/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ This is the official Python SDK for it. With it you can:
1111

1212
* **Build MCP servers** that expose tools, resources, and prompts to any MCP host.
1313
* **Build MCP clients** that connect to any MCP server.
14-
* Speak every standard transport: stdio, Streamable HTTP, and SSE.
14+
* Speak every standard transport: stdio and Streamable HTTP, plus the deprecated legacy HTTP+SSE.
1515

1616
## Requirements
1717

docs/migration.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Every section heading below names the API it affects, so searching this page for
2727
| Lowlevel return value wrapping removed | bare list or dict returns fail result validation instead of being wrapped | [wrapping removed](#lowlevel-server-automatic-return-value-wrapping-removed) |
2828
| Lowlevel tool exceptions no longer become `isError: true` results | clients raise a JSON-RPC error instead of seeing the error text | [tool exceptions](#lowlevel-server-tool-handler-exceptions-no-longer-become-calltoolresultis_errortrue) |
2929
| Roots, Sampling, and Logging deprecated (SEP-2577) | `MCPDeprecationWarning` at call sites | [SEP-2577](#roots-sampling-and-logging-methods-deprecated-sep-2577) |
30+
| HTTP+SSE transport deprecated (SEP-2596) | `MCPDeprecationWarning` from `sse_client`, `sse_app`, `run(transport="sse")` | [SEP-2596](#httpsse-transport-deprecated-sep-2596) |
3031

3132
### Find your area
3233

@@ -41,7 +42,7 @@ Every section heading below names the API it affects, so searching this page for
4142
| maintain OAuth client auth or a protected server | [OAuth and server auth](#oauth-and-server-auth) |
4243
| relied on lenient handling of off-schema traffic, or assert on exact wire bytes | [Stricter protocol validation and wire behavior](#stricter-protocol-validation-and-wire-behavior) |
4344
| test against in-memory server/client pairs | [Testing utilities](#testing-utilities) |
44-
| use roots, sampling, logging, or client-to-server progress | [Deprecations](#deprecations) |
45+
| use roots, sampling, logging, client-to-server progress, or the HTTP+SSE transport | [Deprecations](#deprecations) |
4546
| operate servers that 2026-era clients will also connect to | [Notes for 2026-era connections](#notes-for-2026-era-connections) |
4647

4748
## Suggested migration order
@@ -2792,6 +2793,15 @@ The 2026-07-28 spec restricts `notifications/progress` to the server-to-client d
27922793

27932794
On the server side, prefer the new dispatcher-agnostic `ServerSession.report_progress(progress, total, message)` (and `Context.report_progress()` on `MCPServer`) over the raw `ServerSession.send_progress_notification(progress_token, …)`. `report_progress` encapsulates the "no-op when the caller did not request progress" rule and works on every dispatcher; the raw token-taking form remains for handlers that read `_meta.progressToken` directly.
27942795

2796+
### HTTP+SSE transport deprecated (SEP-2596)
2797+
2798+
The legacy HTTP+SSE transport (a `GET` that opens an event stream, plus a separate `POST` message endpoint) was superseded by Streamable HTTP in protocol revision 2025-03-26, and the spec's feature-lifecycle policy ([SEP-2596](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2596)) now formally classifies it as Deprecated with Streamable HTTP as the migration path. The SDK still ships it, and every entry point now carries `typing_extensions.deprecated` and emits `mcp.MCPDeprecationWarning`:
2799+
2800+
- Client: `mcp.client.sse.sse_client()`, and `SseServerParameters` for `ClientSessionGroup.connect_to_server()`.
2801+
- Server: `MCPServer.sse_app()`, `MCPServer.run_sse_async()`, `mcp.run(transport="sse")`, and the lowlevel `mcp.server.sse.SseServerTransport`.
2802+
2803+
Streamable HTTP is not deprecated: `streamable_http_client()` / `Client(url)` on the client, `streamable_http_app()` / `mcp.run(transport="streamable-http")` on the server. Migrate when you can; a deployment that must keep answering unmigrated SSE clients can keep serving `sse_app()` alongside the Streamable HTTP app and filter the warning as [above](#roots-sampling-and-logging-methods-deprecated-sep-2577). Two adjacent housekeeping changes: `mcp run --transport` now advertises `stdio` and `streamable-http` only, and `python -m mcp.client <url>` connects with Streamable HTTP (it previously used SSE for any `http(s)` URL).
2804+
27952805
## Notes for 2026-era connections
27962806

27972807
Everything below this heading describes behavior that only activates on connections

docs/run/asgi.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ Run the app on its own (`uvicorn server:app`) and you never think about either.
3333
nothing here; **[Deploy & scale](deploy.md)** explains what it actually controls.
3434
**[Running your server](index.md)** covers the options themselves.
3535

36-
`mcp.sse_app()` does the same for the superseded SSE transport.
36+
`mcp.sse_app()` does the same for the deprecated HTTP+SSE transport, and warns when you call it (**[Deprecated features](../deprecated.md)**).
3737

3838
## Localhost only, until you say otherwise
3939

docs/run/index.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,15 @@ The only decision you make is the **transport**: how the bytes between your serv
1010
|---|---|---|
1111
| `stdio` | The host launches your file as a subprocess and speaks over its stdin and stdout. | Local servers. The default. |
1212
| `streamable-http` | A real HTTP server listening on a port. | Anything you deploy. |
13-
| `sse` | The older HTTP transport. | You don't. |
13+
| `sse` | The older HTTP transport. **Deprecated.** | You don't. |
1414

1515
!!! warning
16-
SSE was superseded by Streamable HTTP in the 2025-03-26 protocol revision.
16+
HTTP+SSE was superseded by Streamable HTTP in the 2025-03-26 protocol revision and is
17+
now formally deprecated ([SEP-2596](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2596)).
1718
`mcp.run(transport="sse")` still works, with its own `sse_path=` and `message_path=`
18-
options, but it exists for clients that haven't moved. Don't build anything new on it.
19+
options, but it warns (`MCPDeprecationWarning`) and it exists only for clients that
20+
haven't moved. Don't build anything new on it; **[Deprecated features](../deprecated.md)**
21+
has the full row.
1922

2023
## `mcp.run()`
2124

examples/clients/simple-auth-client/mcp_simple_auth_client/main.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121
from mcp.client._transport import ReadStream, WriteStream
2222
from mcp.client.auth import AuthorizationCodeResult, OAuthClientProvider, TokenStorage
2323
from mcp.client.session import ClientSession
24-
from mcp.client.sse import sse_client
24+
from mcp.client.sse import (
25+
sse_client, # pyright: ignore[reportDeprecated] # deprecated HTTP+SSE, kept for legacy servers
26+
)
2527
from mcp.client.streamable_http import streamable_http_client
2628
from mcp.shared.auth import OAuthClientInformationFull, OAuthClientMetadata, OAuthToken
2729
from mcp.shared.message import SessionMessage
@@ -224,8 +226,8 @@ async def _default_redirect_handler(authorization_url: str) -> None:
224226

225227
# Create transport with auth handler based on transport type
226228
if self.transport_type == "sse":
227-
print("📡 Opening SSE transport connection with auth...")
228-
async with sse_client(
229+
print("📡 Opening SSE transport connection with auth (deprecated transport)...")
230+
async with sse_client( # pyright: ignore[reportDeprecated]
229231
url=self.server_url,
230232
auth=oauth_auth,
231233
timeout=60.0,

examples/servers/simple-auth/mcp_simple_auth/legacy_as_server.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ async def get_time() -> dict[str, Any]:
110110
"--transport",
111111
default="streamable-http",
112112
type=click.Choice(["sse", "streamable-http"]),
113-
help="Transport protocol to use ('sse' or 'streamable-http')",
113+
help="Transport protocol to use ('streamable-http', or the deprecated 'sse')",
114114
)
115115
def main(port: int, transport: Literal["sse", "streamable-http"]) -> int:
116116
"""Run the simple auth MCP server."""
@@ -129,7 +129,8 @@ def main(port: int, transport: Literal["sse", "streamable-http"]) -> int:
129129

130130
mcp_server = create_simple_mcp_server(server_settings, auth_settings)
131131
logger.info(f"🚀 MCP Legacy Server running on {server_url}")
132-
mcp_server.run(transport=transport, host=host, port=port)
132+
# transport may be the deprecated HTTP+SSE transport, kept here for legacy clients
133+
mcp_server.run(transport=transport, host=host, port=port) # pyright: ignore[reportDeprecated]
133134
return 0
134135

135136

0 commit comments

Comments
 (0)