You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Document the streamable HTTP transport change in the migration guide
Records the removal of StreamableHTTPServerTransport.connect() (the
transport is now driven per request by the session manager) and the
behaviours clarified alongside it, and refreshes the docstrings that still
described the old serve_loop wiring.
Copy file name to clipboardExpand all lines: docs/migration.md
+37Lines changed: 37 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -721,6 +721,43 @@ When serving streamable HTTP (stateful or `stateless_http=True`), the server's `
721
721
722
722
Lifespans that set up process-wide state (connection pools, caches, background tasks) are unaffected — they now run once instead of per session/request. If your lifespan was acquiring per-connection resources, move that acquisition into the handler body; per-connection cleanup belongs on the connection's `exit_stack` (a public way to reach it from high-level `@mcp.tool()` handlers is planned).
723
723
724
+
### Streamable HTTP: `StreamableHTTPServerTransport` is driven per request, not per stream
725
+
726
+
`StreamableHTTPServerTransport` no longer exposes a `connect()` context manager yielding a
727
+
`(read_stream, write_stream)` pair for you to run a server loop over. Each HTTP request is now
728
+
dispatched to the server's handlers directly: a request's outbound messages ride that request's
729
+
own response stream (backed by the optional `EventStore` for `Last-Event-ID` resumability), the
730
+
client's POSTed answers to server-initiated requests are correlated back by request id, and the
731
+
standalone GET stream is a further per-connection channel. The transport is the per-session
732
+
core; `StreamableHTTPSessionManager` binds one to the `Server` for each session (via the new
733
+
keyword-only `app` / `lifespan_state` constructor arguments) and routes requests to it.
734
+
735
+
Nothing changes if you serve through `streamable_http_app()` / `run(transport="streamable-http")`
736
+
or mount `StreamableHTTPSessionManager` — the wire behaviour (session ids, GET stream, event
737
+
store, `ctx.close_sse_stream()`, `related_request_id` routing) is unchanged. Only code that
738
+
constructed a transport and consumed `transport.connect()` by hand needs to move to the session
739
+
manager:
740
+
741
+
```python
742
+
# Before (v1)
743
+
transport = StreamableHTTPServerTransport(mcp_session_id=session_id, ...)
744
+
asyncwith transport.connect() as (read_stream, write_stream):
- In JSON-response mode a server-to-client request (sampling, elicitation) now raises
754
+
`NoBackChannelError` — a JSON response has no stream to carry the request, and previously the
755
+
call would hang waiting for an answer that could never be delivered.
756
+
- Stateful streamable-HTTP handlers see `TransportContext(kind="streamable-http")` carrying the
757
+
request `headers`; the stream-pair path previously reported `kind="jsonrpc"` with no headers.
758
+
- A GET carrying `Last-Event-ID` on a server without an `EventStore` opens the standalone stream
759
+
as a plain GET would, since there is nothing to replay.
760
+
724
761
### `MCPServer.get_context()` removed
725
762
726
763
`MCPServer.get_context()` has been removed. Context is now injected by the framework and passed explicitly — there is no ambient ContextVar to read from.
0 commit comments