Skip to content

Commit ab46e5d

Browse files
committed
Collapse the dispatcher constructor overloads with a defaulted TypeVar
TransportT now defaults to TransportContext (PEP 696, same pattern as shared/context.py), so omitting transport_builder no longer needs a dedicated overload to pin the type parameter.
1 parent b25ba8f commit ab46e5d

1 file changed

Lines changed: 6 additions & 28 deletions

File tree

src/mcp/shared/jsonrpc_dispatcher.py

Lines changed: 6 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,14 @@
2424
import logging
2525
from collections.abc import Awaitable, Callable, Mapping
2626
from dataclasses import dataclass, field
27-
from typing import Any, Generic, Literal, TypeVar, cast, overload
27+
from typing import Any, Generic, Literal, cast
2828

2929
import anyio
3030
import anyio.abc
3131
from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream
3232
from opentelemetry.trace import SpanKind
3333
from pydantic import ValidationError
34+
from typing_extensions import TypeVar
3435

3536
from mcp.shared._otel import inject_trace_context, otel_span
3637
from mcp.shared._stream_protocols import ReadStream, WriteStream
@@ -70,7 +71,7 @@
7071
cancelled; without a bound, a wedged transport write would turn the shield
7172
into an uncancellable hang (and block shutdown indefinitely)."""
7273

73-
TransportT = TypeVar("TransportT", bound=TransportContext)
74+
TransportT = TypeVar("TransportT", bound=TransportContext, default=TransportContext)
7475

7576
PeerCancelMode = Literal["interrupt", "signal"]
7677
"""How inbound `notifications/cancelled` is applied to a running handler.
@@ -236,29 +237,6 @@ class JSONRPCDispatcher(Dispatcher[TransportT]):
236237
conformance at the class definition rather than at first use.
237238
"""
238239

239-
@overload
240-
def __init__(
241-
self: JSONRPCDispatcher[TransportContext],
242-
read_stream: ReadStream[SessionMessage | Exception],
243-
write_stream: WriteStream[SessionMessage],
244-
*,
245-
peer_cancel_mode: PeerCancelMode = "interrupt",
246-
raise_handler_exceptions: bool = False,
247-
inline_methods: frozenset[str] = frozenset(),
248-
on_stream_exception: Callable[[Exception], Awaitable[None]] | None = None,
249-
) -> None: ...
250-
@overload
251-
def __init__(
252-
self,
253-
read_stream: ReadStream[SessionMessage | Exception],
254-
write_stream: WriteStream[SessionMessage],
255-
*,
256-
transport_builder: Callable[[MessageMetadata], TransportT],
257-
peer_cancel_mode: PeerCancelMode = "interrupt",
258-
raise_handler_exceptions: bool = False,
259-
inline_methods: frozenset[str] = frozenset(),
260-
on_stream_exception: Callable[[Exception], Awaitable[None]] | None = None,
261-
) -> None: ...
262240
def __init__(
263241
self,
264242
read_stream: ReadStream[SessionMessage | Exception],
@@ -272,9 +250,9 @@ def __init__(
272250
) -> None:
273251
self._read_stream = read_stream
274252
self._write_stream = write_stream
275-
# The overloads guarantee that when `transport_builder` is omitted,
276-
# `TransportT` is `TransportContext`, so the default is type-correct;
277-
# pyright can't see across overloads, hence the cast.
253+
# When `transport_builder` is omitted, `TransportT` falls back to its
254+
# default (`TransportContext`), so the default builder is type-correct;
255+
# pyright can't connect the two, hence the cast.
278256
self._transport_builder = cast(
279257
"Callable[[MessageMetadata], TransportT]",
280258
transport_builder or _default_transport_builder,

0 commit comments

Comments
 (0)