Skip to content

Commit b08b173

Browse files
authored
Merge branch 'modelcontextprotocol:main' into feat/docstring-param-descriptions
2 parents 450aa16 + 1012d60 commit b08b173

38 files changed

Lines changed: 2886 additions & 1734 deletions

docs/migration.md

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -634,11 +634,9 @@ server = Server("my-server", on_call_tool=handle_call_tool)
634634

635635
The `mcp.shared.context` module has been removed. `RequestContext` is now split into `ClientRequestContext` (in `mcp.client.context`) and `ServerRequestContext` (in `mcp.server.context`).
636636

637-
The `RequestContext` class has been split to separate shared fields from server-specific fields. The shared `RequestContext` now only takes 1 type parameter (the session type) instead of 3.
638-
639637
**`RequestContext` changes:**
640638

641-
- Type parameters reduced from `RequestContext[SessionT, LifespanContextT, RequestT]` to `RequestContext[SessionT]`
639+
- The `RequestContext[SessionT, LifespanContextT, RequestT]` generic no longer exists; use `ClientRequestContext` or `ServerRequestContext[LifespanContextT, RequestT]`
642640
- Server-specific fields (`lifespan_context`, `request`, `close_sse_stream`, `close_standalone_sse_stream`) moved to new `ServerRequestContext` class in `mcp.server.context`
643641

644642
**Before (v1):**
@@ -1122,9 +1120,9 @@ async def handle_call_tool(ctx: ServerRequestContext, params: CallToolRequestPar
11221120
)
11231121
```
11241122

1125-
### `RequestContext`: request-specific fields are now optional
1123+
### `ServerRequestContext`: request-specific fields are now optional
11261124

1127-
The `RequestContext` class now uses optional fields for request-specific data (`request_id`, `meta`, etc.) so it can be used for both request and notification handlers. In notification handlers, these fields are `None`.
1125+
`ServerRequestContext` now uses optional fields for request-specific data (`request_id`, `meta`, etc.) so it can be used for both request and notification handlers. In notification handlers, these fields are `None`.
11281126

11291127
```python
11301128
from mcp.server import ServerRequestContext
@@ -1164,7 +1162,22 @@ In practice, replace direct `ServerSession` use with `Server.run(read_stream, wr
11641162

11651163
`BaseSession._in_flight` and the `RequestResponder` members that supported it (`cancel()`, the `cancelled` and `in_flight` properties, the `on_complete` constructor argument, and the internal `CancelScope`) have been removed. These existed to let `ServerSession` cancel a handler when a `CancelledNotification` arrived; `ServerSession` no longer drives a receive loop, so they were dead code. Inbound-cancellation handling for the server now lives in `JSONRPCDispatcher`.
11661164

1167-
`BaseSession` is still used by `ClientSession`, which never relied on these members. `RequestResponder.respond()` is unchanged.
1165+
`BaseSession` itself has since been removed entirely; see the next section.
1166+
1167+
### `ClientSession` now runs on `JSONRPCDispatcher`; `BaseSession` removed
1168+
1169+
`ClientSession`'s public surface is unchanged — same constructor, typed methods, manual `initialize()`, and async context-manager lifecycle — but `BaseSession`, the v1 receive loop underneath it, is removed with no shim. The engine now lives in `JSONRPCDispatcher` (`mcp.shared.jsonrpc_dispatcher`). To customize client behavior, use the `ClientSession` constructor callbacks, or pass a pre-built dispatcher via the new keyword-only `dispatcher=` constructor argument (e.g. a `DirectDispatcher` for in-process embedding).
1170+
1171+
Behavior changes:
1172+
1173+
- **Callbacks and notifications now run concurrently.** In v1 the receive loop processed one inbound message at a time, so callbacks ran inline and in order. Now each delivery starts in arrival order but runs as its own task. Server-initiated request callbacks (`sampling`, `elicitation`, `roots`) no longer block other traffic, may themselves send requests without deadlocking, and are interrupted if the server sends `notifications/cancelled` (the request is then answered with an error). Notification callbacks (`logging_callback`, `progress_callback`, `message_handler`) may interleave, and a `progress_callback` may run after the request it reports on has returned; there is no built-in bound on concurrent deliveries. Transport-level errors reach `message_handler` the same way, and a `message_handler` that raises is logged rather than fatal to the session. Callbacks that need strict sequencing must coordinate themselves.
1174+
- **Timeouts**: a timed-out or abandoned request is now followed by `notifications/cancelled`, so the server stops the handler instead of leaving it running.
1175+
- **A raising request callback** is answered with `code=0` and the exception text; v1 flattened every callback exception to `INVALID_PARAMS`. For a specific error response, return `ErrorData` (unchanged) or raise `MCPError`. One carve-out: pydantic's `ValidationError` is still answered with `INVALID_PARAMS`, as in v1.
1176+
- **`send_request` before entering the context manager** raises `RuntimeError` immediately; v1 wrote to the transport and hung until the timeout. After the connection has closed it raises `MCPError` (`CONNECTION_CLOSED`) instead. `send_notification` before entry still works.
1177+
- **`send_notification` no longer takes `related_request_id`, and `send_request` no longer accepts `ServerMessageMetadata`.** No client transport ever serialized these hints; progress and response correlation via `progressToken` and the request id is unaffected.
1178+
- **Client callbacks now receive `mcp.client.ClientRequestContext`** (its `request_id` is always populated); the private `mcp.shared._context.RequestContext` generic is deleted. Annotations spelled `RequestContext[ClientSession]` become `ClientRequestContext`.
1179+
1180+
`mcp.shared.session` is now a compatibility module: `ProgressFnT` is re-exported (its home is `mcp.shared.dispatcher`), and `RequestResponder` remains as a typing-only stub so `MessageHandlerFnT` annotations keep importing. `RequestResponder.respond()` no longer exists.
11681181

11691182
### Experimental Tasks support removed
11701183

src/mcp/client/client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from mcp.client.streamable_http import streamable_http_client
1313
from mcp.server import Server
1414
from mcp.server.mcpserver import MCPServer
15-
from mcp.shared.session import ProgressFnT
15+
from mcp.shared.dispatcher import ProgressFnT
1616
from mcp.types import (
1717
CallToolResult,
1818
CompleteResult,

src/mcp/client/context.py

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,5 @@
11
"""Request context for MCP client handlers."""
22

3-
from mcp.client.session import ClientSession
4-
from mcp.shared._context import RequestContext
3+
from mcp.client.session import ClientRequestContext
54

6-
ClientRequestContext = RequestContext[ClientSession]
7-
"""Context for handling incoming requests in a client session.
8-
9-
This context is passed to client-side callbacks (sampling, elicitation, list_roots) when the server sends requests
10-
to the client.
11-
12-
Attributes:
13-
request_id: The unique identifier for this request.
14-
meta: Optional metadata associated with the request.
15-
session: The client session handling this request.
16-
"""
5+
__all__ = ["ClientRequestContext"]

0 commit comments

Comments
 (0)