Narrow message_handler's parameter to notifications and exceptions (#3168)

This commit is contained in:
Max 2026-07-26 00:24:48 +01:00 • committed by GitHub
commit 814072c94d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 74 additions and 147 deletions

View file

@ -135,7 +135,7 @@ Two more. Neither declares anything.
`logging_callback` receives every `notifications/message` a server sends, as `LoggingMessageNotificationParams` (`level`, `logger`, `data`). Protocol logging is itself deprecated by the 2026-07-28 spec (**[Logging](../handlers/logging.md)** has what to do instead), so this callback exists for the servers that still emit it. `logging_callback` receives every `notifications/message` a server sends, as `LoggingMessageNotificationParams` (`level`, `logger`, `data`). Protocol logging is itself deprecated by the 2026-07-28 spec (**[Logging](../handlers/logging.md)** has what to do instead), so this callback exists for the servers that still emit it.
`message_handler` is the catch-all: every server notification reaches it (as well as its specific callback), and on a stream-backed transport so does every transport-level `Exception`. The one pattern worth knowing is `if isinstance(message, Exception): raise message`, so a broken connection fails loudly instead of vanishing. `message_handler` is the catch-all: every server notification the session surfaces reaches it (as well as its specific callback), and on a stream-backed transport so does every transport-level `Exception`. Two never do: `notifications/cancelled` is applied by the SDK rather than surfaced, and a subscription acknowledgment for a live `listen()` stream is consumed by that stream. Annotate the parameter with `IncomingMessage` (`ServerNotification | Exception`, exported from `mcp.client`). The one pattern worth knowing is `if isinstance(message, Exception): raise message`, so a broken connection fails loudly instead of vanishing.
## Recap ## Recap

View file

@ -1688,7 +1688,9 @@ Behavior changes:
- **`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. - **`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.
- **Client callbacks now receive `mcp.client.ClientRequestContext`** (its `request_id` is always populated); the `mcp.shared.context.RequestContext` generic is deleted. Annotations spelled `RequestContext[ClientSession, Any]` become `ClientRequestContext` (details in [`RequestContext` type parameters simplified](#requestcontext-type-parameters-simplified)). - **Client callbacks now receive `mcp.client.ClientRequestContext`** (its `request_id` is always populated); the `mcp.shared.context.RequestContext` generic is deleted. Annotations spelled `RequestContext[ClientSession, Any]` become `ClientRequestContext` (details in [`RequestContext` type parameters simplified](#requestcontext-type-parameters-simplified)).
`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, and neither do the cancellation-tracking members (`cancel()`, the `cancelled` and `in_flight` properties, the `on_complete` constructor argument) or `BaseSession._in_flight`; inbound cancellation is handled by `JSONRPCDispatcher`. - **`message_handler` no longer receives requests.** Server-initiated requests are answered by the typed callbacks (`sampling_callback`, `elicitation_callback`, `list_roots_callback`), so the handler's parameter is now `IncomingMessage = ServerNotification | Exception`, exported from `mcp.client`. Replace the hand-written v1 union `RequestResponder[ServerRequest, ClientResult] | ServerNotification | Exception` with `IncomingMessage`; `RequestResponder` is gone (below), so the old annotation no longer imports.
The `mcp.shared.session` module is gone. `RequestResponder` is removed — `respond()`, the cancellation-tracking members (`cancel()`, the `cancelled` and `in_flight` properties, the `on_complete` constructor argument) and `BaseSession._in_flight` have no replacement; inbound cancellation is handled by `JSONRPCDispatcher`. `ProgressFnT` now lives only in `mcp.shared.dispatcher`, and `RequestId` in `mcp_types`.
### Experimental Tasks support removed ### Experimental Tasks support removed

View file

@ -146,7 +146,7 @@ Each of these is a section in the **[Migration Guide](migration.md)**:
* The **WebSocket transport**, both sides, and the `mcp[ws]` extra. It was never part of the MCP specification. * The **WebSocket transport**, both sides, and the `mcp[ws]` extra. It was never part of the MCP specification.
* The **experimental Tasks** API (`mcp.*.experimental`). 2026-07-28 moves tasks out of the core protocol and into an official extension ([SEP-2663](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2663)), which this SDK does not implement yet. * The **experimental Tasks** API (`mcp.*.experimental`). 2026-07-28 moves tasks out of the core protocol and into an official extension ([SEP-2663](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2663)), which this SDK does not implement yet.
* `mcp.types`, `mcp.shared.version`, and `mcp.shared.progress` as import paths. * `mcp.types`, `mcp.shared.version`, `mcp.shared.progress`, and `mcp.shared.session` (with the `RequestResponder` stub v1 `message_handler` annotations imported) as import paths.
* The deprecated `streamablehttp_client` spelling, and the `get_session_id` callback from `streamable_http_client` (which now yields exactly two streams). * The deprecated `streamablehttp_client` spelling, and the `get_session_id` callback from `streamable_http_client` (which now yields exactly two streams).
* `McpError`, renamed **`MCPError`** with a direct `(code, message, data)` constructor. * `McpError`, renamed **`MCPError`** with a direct `(code, message, data)` constructor.
* `MCPServer.get_context()`, `mount_path=`, and the lowlevel `Server`'s decorator methods, ContextVar, and handler dicts. * `MCPServer.get_context()`, `mount_path=`, and the lowlevel `Server`'s decorator methods, ContextVar, and handler dicts.

View file

@ -3,7 +3,7 @@
import anyio import anyio
import mcp_types as types import mcp_types as types
from mcp.client import Client from mcp.client import Client, IncomingMessage
from stories._harness import Target, run_client from stories._harness import Target, run_client
@ -13,7 +13,7 @@ async def main(target: Target, *, mode: str = "auto") -> None:
received: list[types.ResourceListChangedNotification] = [] received: list[types.ResourceListChangedNotification] = []
seen = anyio.Event() seen = anyio.Event()
async def on_message(message: object) -> None: async def on_message(message: IncomingMessage) -> None:
if isinstance(message, types.ResourceListChangedNotification): if isinstance(message, types.ResourceListChangedNotification):
received.append(message) received.append(message)
seen.set() seen.set()

View file

@ -4,7 +4,7 @@ import anyio
import mcp_types as types import mcp_types as types
from mcp_types.version import HANDSHAKE_PROTOCOL_VERSIONS from mcp_types.version import HANDSHAKE_PROTOCOL_VERSIONS
from mcp.client import Client, ClientRequestContext from mcp.client import Client, ClientRequestContext, IncomingMessage
from stories._harness import Target, run_client from stories._harness import Target, run_client
@ -18,7 +18,7 @@ async def main(target: Target, *, mode: str = "auto") -> None:
return types.ElicitResult(action="cancel") return types.ElicitResult(action="cancel")
return types.ElicitResult(action="accept", content={"confirm": answer == "confirm"}) return types.ElicitResult(action="accept", content={"confirm": answer == "confirm"})
async def on_message(message: object) -> None: async def on_message(message: IncomingMessage) -> None:
if isinstance(message, types.ResourceListChangedNotification): if isinstance(message, types.ResourceListChangedNotification):
list_changed.set() list_changed.set()

View file

@ -20,7 +20,7 @@ from mcp.client.extension import (
UnexpectedClaimedResult, UnexpectedClaimedResult,
advertise, advertise,
) )
from mcp.client.session import ClientSession from mcp.client.session import ClientSession, IncomingMessage
__all__ = [ __all__ = [
"CacheConfig", "CacheConfig",
@ -32,6 +32,7 @@ __all__ = [
"ClientExtension", "ClientExtension",
"ClientRequestContext", "ClientRequestContext",
"ClientSession", "ClientSession",
"IncomingMessage",
"InMemoryResponseCacheStore", "InMemoryResponseCacheStore",
"InputRequiredRoundsExceededError", "InputRequiredRoundsExceededError",
"NotificationBinding", "NotificationBinding",

View file

@ -9,11 +9,10 @@ import anyio
import mcp_types as types import mcp_types as types
from mcp.client._transport import ReadStream, WriteStream from mcp.client._transport import ReadStream, WriteStream
from mcp.client.session import ClientSession from mcp.client.session import ClientSession, IncomingMessage
from mcp.client.sse import sse_client from mcp.client.sse import sse_client
from mcp.client.stdio import StdioServerParameters, stdio_client from mcp.client.stdio import StdioServerParameters, stdio_client
from mcp.shared.message import SessionMessage from mcp.shared.message import SessionMessage
from mcp.shared.session import RequestResponder
if not sys.warnoptions: if not sys.warnoptions:
warnings.simplefilter("ignore") warnings.simplefilter("ignore")
@ -22,9 +21,7 @@ logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("client") logger = logging.getLogger("client")
async def message_handler( async def message_handler(message: IncomingMessage) -> None:
message: RequestResponder[types.ServerRequest, types.ClientResult] | types.ServerNotification | Exception,
) -> None:
if isinstance(message, Exception): if isinstance(message, Exception):
logger.error("Error: %s", message) logger.error("Error: %s", message)
return return

View file

@ -52,6 +52,7 @@ from mcp.client.session import (
ClientRequestContext, ClientRequestContext,
ClientSession, ClientSession,
ElicitationFnT, ElicitationFnT,
IncomingMessage,
ListRootsFnT, ListRootsFnT,
LoggingFnT, LoggingFnT,
MessageHandlerFnT, MessageHandlerFnT,
@ -68,7 +69,6 @@ from mcp.shared.dispatcher import Dispatcher, ProgressFnT
from mcp.shared.exceptions import MCPDeprecationWarning, MCPError from mcp.shared.exceptions import MCPDeprecationWarning, MCPError
from mcp.shared.extension import validate_extension_identifier from mcp.shared.extension import validate_extension_identifier
from mcp.shared.jsonrpc_dispatcher import JSONRPCDispatcher from mcp.shared.jsonrpc_dispatcher import JSONRPCDispatcher
from mcp.shared.session import RequestResponder
from mcp.shared.subscriptions import event_to_notification from mcp.shared.subscriptions import event_to_notification
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -155,9 +155,7 @@ def _strip_userinfo(url: str) -> str:
def _evicting_message_handler(cache: ClientResponseCache, user_handler: MessageHandlerFnT | None) -> MessageHandlerFnT: def _evicting_message_handler(cache: ClientResponseCache, user_handler: MessageHandlerFnT | None) -> MessageHandlerFnT:
"""Wrap the session message handler with cache eviction on server notifications.""" """Wrap the session message handler with cache eviction on server notifications."""
async def handler( async def handler(message: IncomingMessage) -> None:
message: RequestResponder[types.ServerRequest, types.ClientResult] | types.ServerNotification | Exception,
) -> None:
if isinstance(message, types.ServerNotification): if isinstance(message, types.ServerNotification):
try: try:
await cache.evict_for_notification(message) await cache.evict_for_notification(message)

View file

@ -6,7 +6,7 @@ from dataclasses import dataclass
from functools import reduce from functools import reduce
from operator import or_ from operator import or_
from types import TracebackType from types import TracebackType
from typing import Annotated, Any, Final, Literal, Protocol, cast, overload from typing import Annotated, Any, Final, Literal, Protocol, TypeAlias, cast, overload
import anyio import anyio
import anyio.abc import anyio.abc
@ -53,7 +53,6 @@ from mcp.shared.inbound import (
) )
from mcp.shared.jsonrpc_dispatcher import JSONRPCDispatcher, cancelled_request_id_from_params from mcp.shared.jsonrpc_dispatcher import JSONRPCDispatcher, cancelled_request_id_from_params
from mcp.shared.message import ClientMessageMetadata, SessionMessage from mcp.shared.message import ClientMessageMetadata, SessionMessage
from mcp.shared.session import RequestResponder
from mcp.shared.subscriptions import SUBSCRIPTION_ID_META_KEY, event_from_wire from mcp.shared.subscriptions import SUBSCRIPTION_ID_META_KEY, event_from_wire
from mcp.shared.transport_context import TransportContext from mcp.shared.transport_context import TransportContext
@ -172,16 +171,20 @@ class LoggingFnT(Protocol):
async def __call__(self, params: types.LoggingMessageNotificationParams) -> None: ... # pragma: no branch async def __call__(self, params: types.LoggingMessageNotificationParams) -> None: ... # pragma: no branch
IncomingMessage: TypeAlias = types.ServerNotification | Exception
"""What `message_handler` receives: the server notifications the session surfaces, plus transport-level exceptions.
`notifications/cancelled` is applied by the dispatcher and never surfaced, and a
`notifications/subscriptions/acknowledged` for a live `listen()` stream is consumed by that
stream, so neither reaches the handler.
"""
class MessageHandlerFnT(Protocol): class MessageHandlerFnT(Protocol):
async def __call__( async def __call__(self, message: IncomingMessage) -> None: ... # pragma: no branch
self,
message: RequestResponder[types.ServerRequest, types.ClientResult] | types.ServerNotification | Exception,
) -> None: ... # pragma: no branch
async def _default_message_handler( async def _default_message_handler(message: IncomingMessage) -> None:
message: RequestResponder[types.ServerRequest, types.ClientResult] | types.ServerNotification | Exception,
) -> None:
await anyio.lowlevel.checkpoint() await anyio.lowlevel.checkpoint()
@ -331,8 +334,10 @@ class ClientSession:
`dispatcher=`), enter as an async context manager, then call `dispatcher=`), enter as an async context manager, then call
`initialize()`. The dispatcher owns the receive loop and request `initialize()`. The dispatcher owns the receive loop and request
correlation; this class owns the typed MCP layer and the constructor correlation; this class owns the typed MCP layer and the constructor
callbacks. Transport `Exception` items reach `message_handler` only when callbacks. Transport `Exception` items reach `message_handler` on any
the session builds its own dispatcher from a stream pair. stream-backed dispatcher (`JSONRPCDispatcher`), whether built here from a
stream pair or supplied without a stream-exception hook of its own; an
in-process `DirectDispatcher` carries none.
Extension `result_claims` fold into tools/call parsing at `adopt()`; Extension `result_claims` fold into tools/call parsing at `adopt()`;
`notification_bindings` observe vendor notifications via bounded FIFOs. `notification_bindings` observe vendor notifications via bounded FIFOs.

View file

@ -25,8 +25,8 @@ from mcp.client.sse import sse_client
from mcp.client.stdio import StdioServerParameters from mcp.client.stdio import StdioServerParameters
from mcp.client.streamable_http import streamable_http_client from mcp.client.streamable_http import streamable_http_client
from mcp.shared._httpx_utils import create_mcp_http_client from mcp.shared._httpx_utils import create_mcp_http_client
from mcp.shared.dispatcher import ProgressFnT
from mcp.shared.exceptions import MCPError from mcp.shared.exceptions import MCPError
from mcp.shared.session import ProgressFnT
class SseServerParameters(BaseModel): class SseServerParameters(BaseModel):

View file

@ -1,22 +0,0 @@
"""Compatibility names that outlived the removed v1 session layer (`BaseSession`)."""
from typing import Generic, TypeVar
from mcp_types import RequestParamsMeta
from mcp.shared.dispatcher import ProgressFnT as ProgressFnT
from mcp.shared.message import MessageMetadata
RequestId = str | int
ReceiveRequestT = TypeVar("ReceiveRequestT")
SendResultT = TypeVar("SendResultT")
class RequestResponder(Generic[ReceiveRequestT, SendResultT]):
"""Typing stub for the v1 responder; the SDK never instantiates it."""
request_id: RequestId
request_meta: RequestParamsMeta | None
request: ReceiveRequestT
message_metadata: MessageMetadata

View file

@ -42,7 +42,7 @@ from mcp_types import (
) )
from mcp_types.version import LATEST_MODERN_VERSION from mcp_types.version import LATEST_MODERN_VERSION
from mcp.client import Client from mcp.client import Client, IncomingMessage
from mcp.client._transport import TransportStreams from mcp.client._transport import TransportStreams
from mcp.client.caching import ( from mcp.client.caching import (
CacheConfig, CacheConfig,
@ -57,13 +57,10 @@ from mcp.server.caching import CacheHint
from mcp.shared.exceptions import MCPError from mcp.shared.exceptions import MCPError
from mcp.shared.memory import MessageStream, create_client_server_memory_streams from mcp.shared.memory import MessageStream, create_client_server_memory_streams
from mcp.shared.message import SessionMessage from mcp.shared.message import SessionMessage
from mcp.shared.session import RequestResponder
from tests.interaction._connect import BASE_URL, mounted_app from tests.interaction._connect import BASE_URL, mounted_app
pytestmark = pytest.mark.anyio pytestmark = pytest.mark.anyio
IncomingMessage = RequestResponder[types.ServerRequest, types.ClientResult] | types.ServerNotification | Exception
def _coordinator(client: Client) -> ClientResponseCache: def _coordinator(client: Client) -> ClientResponseCache:
cache = client._response_cache cache = client._response_cache

View file

@ -1,6 +1,5 @@
from typing import Literal from typing import Literal
import mcp_types as types
import pytest import pytest
from mcp_types import ( from mcp_types import (
LoggingMessageNotificationParams, LoggingMessageNotificationParams,
@ -8,8 +7,8 @@ from mcp_types import (
) )
from mcp import Client from mcp import Client
from mcp.client import IncomingMessage
from mcp.server.mcpserver import Context, MCPServer from mcp.server.mcpserver import Context, MCPServer
from mcp.shared.session import RequestResponder
class LoggingCollector: class LoggingCollector:
@ -55,9 +54,7 @@ async def test_logging_callback():
return True return True
# Create a message handler to catch exceptions # Create a message handler to catch exceptions
async def message_handler( async def message_handler(message: IncomingMessage) -> None:
message: RequestResponder[types.ServerRequest, types.ClientResult] | types.ServerNotification | Exception,
) -> None:
if isinstance(message, Exception): # pragma: no cover if isinstance(message, Exception): # pragma: no cover
raise message raise message

View file

@ -16,8 +16,8 @@ from starlette.responses import JSONResponse, Response
from starlette.routing import Route from starlette.routing import Route
from mcp import ClientSession, MCPError from mcp import ClientSession, MCPError
from mcp.client import IncomingMessage
from mcp.client.streamable_http import streamable_http_client from mcp.client.streamable_http import streamable_http_client
from mcp.shared.session import RequestResponder
pytestmark = pytest.mark.anyio pytestmark = pytest.mark.anyio
@ -82,9 +82,7 @@ async def test_non_compliant_notification_response() -> None:
""" """
returned_exception = None returned_exception = None
async def message_handler( # pragma: no cover async def message_handler(message: IncomingMessage) -> None: # pragma: no cover
message: RequestResponder[types.ServerRequest, types.ClientResult] | types.ServerNotification | Exception,
) -> None:
nonlocal returned_exception nonlocal returned_exception
if isinstance(message, Exception): if isinstance(message, Exception):
returned_exception = message returned_exception = message

View file

@ -37,7 +37,7 @@ from mcp_types.version import HANDSHAKE_PROTOCOL_VERSIONS, LATEST_HANDSHAKE_VERS
from pydantic import FileUrl, ValidationError from pydantic import FileUrl, ValidationError
from mcp import MCPError from mcp import MCPError
from mcp.client import ClientRequestContext from mcp.client import ClientRequestContext, IncomingMessage
from mcp.client.client import Client from mcp.client.client import Client
from mcp.client.session import DEFAULT_CLIENT_INFO, ClientSession from mcp.client.session import DEFAULT_CLIENT_INFO, ClientSession
from mcp.client.subscriptions import ToolsListChanged, listen from mcp.client.subscriptions import ToolsListChanged, listen
@ -45,7 +45,6 @@ from mcp.server import Server, ServerRequestContext
from mcp.shared.direct_dispatcher import create_direct_dispatcher_pair from mcp.shared.direct_dispatcher import create_direct_dispatcher_pair
from mcp.shared.dispatcher import CallOptions, DispatchContext, OnNotify, OnNotifyIntercept, OnRequest from mcp.shared.dispatcher import CallOptions, DispatchContext, OnNotify, OnNotifyIntercept, OnRequest
from mcp.shared.message import SessionMessage from mcp.shared.message import SessionMessage
from mcp.shared.session import RequestResponder
from mcp.shared.subscriptions import SUBSCRIPTION_ID_META_KEY from mcp.shared.subscriptions import SUBSCRIPTION_ID_META_KEY
from mcp.shared.transport_context import TransportContext from mcp.shared.transport_context import TransportContext
@ -123,9 +122,7 @@ async def test_client_session_initialize():
) )
# Create a message handler to catch exceptions # Create a message handler to catch exceptions
async def message_handler( # pragma: no cover async def message_handler(message: IncomingMessage) -> None: # pragma: no cover
message: RequestResponder[types.ServerRequest, types.ClientResult] | types.ServerNotification | Exception,
) -> None:
if isinstance(message, Exception): if isinstance(message, Exception):
raise message raise message
@ -1228,10 +1225,8 @@ async def test_raising_notification_callbacks_over_direct_dispatch_cost_only_tha
async def logging_callback(params: types.LoggingMessageNotificationParams) -> None: async def logging_callback(params: types.LoggingMessageNotificationParams) -> None:
raise ValueError("logging callback boom") raise ValueError("logging callback boom")
async def message_handler( async def message_handler(message: IncomingMessage) -> None:
message: RequestResponder[types.ServerRequest, types.ClientResult] | types.ServerNotification | Exception, assert not isinstance(message, Exception)
) -> None:
assert not isinstance(message, RequestResponder | Exception)
teed.append(message) teed.append(message)
raise ValueError("message handler boom") raise ValueError("message handler boom")

View file

@ -40,7 +40,7 @@ flows — with a single subprocess test for stdio.
```text ```text
tests/interaction/ tests/interaction/
_requirements.py the requirements manifest (see below) _requirements.py the requirements manifest (see below)
_helpers.py shared type aliases + the wire-recording transport _helpers.py the wire-recording transport
_connect.py the transport-parametrized connection factories _connect.py the transport-parametrized connection factories
conftest.py the connect fixture (the transport matrix) conftest.py the connect fixture (the transport matrix)
test_coverage.py enforces the manifest ↔ test contract test_coverage.py enforces the manifest ↔ test contract

View file

@ -1,28 +1,16 @@
"""Shared helpers for the interaction suite. """Shared helpers for the interaction suite.
Keep this module small: it exists only for (a) types that every test would otherwise have to Keep this module small: it exists only for the recording transport used by the wire-level
assemble from the SDK's internals to annotate a client callback, and (b) the recording transport tests. Server fixtures and assertion helpers belong in the test that uses them.
used by the wire-level tests. Server fixtures and assertion helpers belong in the test that uses
them.
""" """
from types import TracebackType from types import TracebackType
import anyio import anyio
from mcp_types import ClientResult, ServerNotification, ServerRequest
from typing_extensions import Self from typing_extensions import Self
from mcp.client._transport import ReadStream, Transport, TransportStreams, WriteStream from mcp.client._transport import ReadStream, Transport, TransportStreams, WriteStream
from mcp.shared.message import SessionMessage from mcp.shared.message import SessionMessage
from mcp.shared.session import RequestResponder
# TODO: this union is the parameter type of every client message handler (MessageHandlerFnT),
# but the SDK does not export a name for it -- writing a correctly-typed handler requires
# importing RequestResponder from mcp.shared.session and assembling the union by hand. It
# should be a named, exported alias next to MessageHandlerFnT (like ClientRequestContext is
# for the request callbacks), at which point this alias can be deleted.
IncomingMessage = RequestResponder[ServerRequest, ClientResult] | ServerNotification | Exception
"""Everything a client message handler can receive."""
class _RecordingReadStream: class _RecordingReadStream:

View file

@ -29,13 +29,12 @@ from mcp_types import (
) )
from mcp import MCPError from mcp import MCPError
from mcp.client import ClientRequestContext, ClientSession from mcp.client import ClientRequestContext, ClientSession, IncomingMessage
from mcp.server import Server, ServerRequestContext from mcp.server import Server, ServerRequestContext
from mcp.shared.memory import MessageStream, create_client_server_memory_streams from mcp.shared.memory import MessageStream, create_client_server_memory_streams
from mcp.shared.message import SessionMessage from mcp.shared.message import SessionMessage
from tests._stamp import Unstamp from tests._stamp import Unstamp
from tests.interaction._connect import Connect from tests.interaction._connect import Connect
from tests.interaction._helpers import IncomingMessage
from tests.interaction._requirements import requirement from tests.interaction._requirements import requirement
pytestmark = pytest.mark.anyio pytestmark = pytest.mark.anyio

View file

@ -28,12 +28,11 @@ from mcp_types import (
) )
from mcp import MCPError, UrlElicitationRequiredError from mcp import MCPError, UrlElicitationRequiredError
from mcp.client import ClientRequestContext, ClientSession from mcp.client import ClientRequestContext, ClientSession, IncomingMessage
from mcp.server import Server, ServerRequestContext from mcp.server import Server, ServerRequestContext
from mcp.shared.memory import MessageStream, create_client_server_memory_streams from mcp.shared.memory import MessageStream, create_client_server_memory_streams
from mcp.shared.message import SessionMessage from mcp.shared.message import SessionMessage
from tests.interaction._connect import Connect from tests.interaction._connect import Connect
from tests.interaction._helpers import IncomingMessage
from tests.interaction._requirements import requirement from tests.interaction._requirements import requirement
pytestmark = pytest.mark.anyio pytestmark = pytest.mark.anyio

View file

@ -29,12 +29,11 @@ from mcp_types import (
) )
from mcp import MCPError, UrlElicitationRequiredError from mcp import MCPError, UrlElicitationRequiredError
from mcp.client import ClientRequestContext from mcp.client import ClientRequestContext, IncomingMessage
from mcp.server import Server, ServerRequestContext from mcp.server import Server, ServerRequestContext
from mcp.server.session import ServerSession from mcp.server.session import ServerSession
from tests._stamp import Unstamp from tests._stamp import Unstamp
from tests.interaction._connect import Connect from tests.interaction._connect import Connect
from tests.interaction._helpers import IncomingMessage
from tests.interaction._requirements import requirement from tests.interaction._requirements import requirement
pytestmark = pytest.mark.anyio pytestmark = pytest.mark.anyio

Some files were not shown because too many files have changed in this diff Show more