"""Shared fixtures for `Dispatcher` contract tests. The `pair_factory` fixture parametrizes contract tests over every `Dispatcher` implementation, so the same behavioral assertions run against `DirectDispatcher` (in-memory) and `JSONRPCDispatcher` (over crossed anyio memory streams). """ from collections.abc import Callable import anyio import pytest from mcp.shared.direct_dispatcher import create_direct_dispatcher_pair from mcp.shared.dispatcher import Dispatcher from mcp.shared.jsonrpc_dispatcher import JSONRPCDispatcher from mcp.shared.message import SessionMessage from mcp.shared.transport_context import TransportContext DispatcherTriple = tuple[Dispatcher[TransportContext], Dispatcher[TransportContext], Callable[[], None]] PairFactory = Callable[..., DispatcherTriple] def direct_pair(*, can_send_request: bool = True) -> DispatcherTriple: client, server = create_direct_dispatcher_pair(can_send_request=can_send_request) def close() -> None: client.close() server.close() return client, server, close def jsonrpc_pair(*, can_send_request: bool = True) -> DispatcherTriple: """Two `JSONRPCDispatcher`s wired over crossed in-memory streams.""" c2s_send, c2s_recv = anyio.create_memory_object_stream[SessionMessage | Exception](32) s2c_send, s2c_recv = anyio.create_memory_object_stream[SessionMessage | Exception](32) def builder(_meta: object) -> TransportContext: return TransportContext(kind="jsonrpc", can_send_request=can_send_request) client: JSONRPCDispatcher[TransportContext] = JSONRPCDispatcher(s2c_recv, c2s_send, transport_builder=builder) server: JSONRPCDispatcher[TransportContext] = JSONRPCDispatcher(c2s_recv, s2c_send, transport_builder=builder) def close() -> None: for s in (c2s_send, c2s_recv, s2c_send, s2c_recv): s.close() return client, server, close @pytest.fixture( params=[ pytest.param(direct_pair, id="direct"), pytest.param(jsonrpc_pair, id="jsonrpc"), ] ) def pair_factory(request: pytest.FixtureRequest) -> PairFactory: return request.param __all__ = ["PairFactory", "direct_pair", "jsonrpc_pair"]