Skip to content

Commit 6b6a73f

Browse files
committed
further modifications to fix pyright errors
1 parent db68c9b commit 6b6a73f

File tree

4 files changed

+82
-24
lines changed

4 files changed

+82
-24
lines changed

docs/migration.md

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -550,9 +550,14 @@ from mcp.shared._context import SessionT
550550
from mcp.shared._context import SessionT_co
551551
```
552552

553-
#### `AbstractBaseSession` simplified
553+
#### New `AbstractBaseSession` structural interface
554554

555-
`AbstractBaseSession` is now a pure abstract interface with no `__init__` method and no `WireMessageT` type parameter. If you were subclassing it directly, you now need to manage all state in your subclass.
555+
The session hierarchy now uses a new **runtime-checkable Protocol** called `AbstractBaseSession` to define the shared contract for all MCP sessions. This protocol enables structural subtyping, allowing different transport implementations to be used interchangeably without requiring rigid inheritance.
556+
557+
Key characteristics of `AbstractBaseSession`:
558+
1. **Pure Interface**: It is a structural protocol with no implementation state or `__init__` method.
559+
2. **Simplified Type Parameters**: It takes two parameters: `AbstractBaseSession[SendRequestT, SendNotificationT]`. Contravariant variance is used for these parameters to ensure that sessions can be used safely in generic contexts (like `RequestContext`).
560+
3. **BaseSession Implementation**: The concrete implementation logic (state management, response routing) is provided by the `BaseSession` class, which satisfies the protocol.
556561

557562
**Before:**
558563

@@ -575,6 +580,56 @@ class MySession(AbstractBaseSession[...]):
575580
self._my_state = {}
576581
```
577582

583+
#### `SendRequestT` changed to contravariant
584+
585+
The `SendRequestT` TypeVar is now defined as **contravariant** to support its use in the `AbstractBaseSession` Protocol.
586+
587+
**Before:**
588+
589+
```python
590+
SendRequestT = TypeVar("SendRequestT", ClientRequest, ServerRequest)
591+
```
592+
593+
**After:**
594+
595+
```python
596+
SendRequestT = TypeVar("SendRequestT", ClientRequest, ServerRequest, contravariant=True)
597+
```
598+
599+
#### `SendNotificationT` changed to contravariant
600+
601+
The `SendNotificationT` TypeVar is now defined as **contravariant** to support its use in the `AbstractBaseSession` Protocol.
602+
603+
**Before:**
604+
605+
```python
606+
SendNotificationT = TypeVar("SendNotificationT", ClientNotification, ServerNotification)
607+
```
608+
609+
**After:**
610+
611+
```python
612+
SendNotificationT = TypeVar(
613+
"SendNotificationT", ClientNotification, ServerNotification, contravariant=True
614+
)
615+
```
616+
617+
#### `ReceiveResultT` changed to covariant
618+
619+
The `ReceiveResultT` TypeVar is now defined as **covariant** to support its use in the `AbstractBaseSession` Protocol.
620+
621+
**Before:**
622+
623+
```python
624+
ReceiveResultT = TypeVar("ReceiveResultT", bound=BaseModel)
625+
```
626+
627+
**After:**
628+
629+
```python
630+
ReceiveResultT = TypeVar("ReceiveResultT", bound=BaseModel, covariant=True)
631+
```
632+
578633
#### `BaseClientSession` is now a Protocol
579634

580635
`BaseClientSession` is now a `typing.Protocol` (structural subtyping) instead of an abstract base class. It no longer inherits from `AbstractBaseSession` and requires no inheritance to satisfy.

src/mcp/client/base_client_session.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from mcp.shared.session import ProgressFnT
77
from mcp.types._types import RequestParamsMeta
88

9-
ClientSessionT_contra = TypeVar("ClientSessionT_contra", contravariant=True)
9+
ClientSessionT_contra = TypeVar("ClientSessionT_contra", bound="BaseClientSession", contravariant=True)
1010

1111

1212
@runtime_checkable

src/mcp/shared/_context.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
"""Request context for MCP handlers."""
22

33
from dataclasses import dataclass
4-
from typing import Generic
5-
4+
from typing import TYPE_CHECKING, Generic, Any
65
from typing_extensions import TypeVar
76

7+
if TYPE_CHECKING:
8+
from mcp.shared.session import AbstractBaseSession
9+
810
from mcp.types import RequestId, RequestParamsMeta
911

10-
SessionT_co = TypeVar("SessionT_co", covariant=True)
12+
SessionT_co = TypeVar(
13+
"SessionT_co", bound="AbstractBaseSession[Any, Any]", covariant=True
14+
)
1115

1216

1317
@dataclass(kw_only=True)

src/mcp/shared/session.py

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from __future__ import annotations
22

33
import logging
4-
from abc import ABC, abstractmethod
54
from collections.abc import Callable
65
from contextlib import AsyncExitStack
76
from types import TracebackType
@@ -10,7 +9,7 @@
109
import anyio
1110
from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream
1211
from pydantic import BaseModel, TypeAdapter
13-
from typing_extensions import Self
12+
from typing_extensions import Protocol, Self, runtime_checkable
1413

1514
from mcp.shared.exceptions import MCPError
1615
from mcp.shared.message import MessageMetadata, ServerMessageMetadata, SessionMessage
@@ -36,11 +35,13 @@
3635
ServerResult,
3736
)
3837

39-
SendRequestT = TypeVar("SendRequestT", ClientRequest, ServerRequest)
38+
SendRequestT = TypeVar("SendRequestT", ClientRequest, ServerRequest, contravariant=True)
4039
SendResultT = TypeVar("SendResultT", ClientResult, ServerResult)
41-
SendNotificationT = TypeVar("SendNotificationT", ClientNotification, ServerNotification)
40+
SendNotificationT = TypeVar(
41+
"SendNotificationT", ClientNotification, ServerNotification, contravariant=True
42+
)
4243
ReceiveRequestT = TypeVar("ReceiveRequestT", ClientRequest, ServerRequest)
43-
ReceiveResultT = TypeVar("ReceiveResultT", bound=BaseModel)
44+
ReceiveResultT = TypeVar("ReceiveResultT", bound=BaseModel, covariant=True)
4445
ReceiveNotificationT = TypeVar("ReceiveNotificationT", ClientNotification, ServerNotification)
4546

4647
RequestId = str | int
@@ -155,24 +156,20 @@ def cancelled(self) -> bool:
155156
return self._cancel_scope.cancel_called
156157

157158

159+
@runtime_checkable
158160
class AbstractBaseSession(
159-
ABC,
161+
Protocol,
160162
Generic[
161163
SendRequestT,
162164
SendNotificationT,
163-
SendResultT,
164-
ReceiveRequestT,
165-
ReceiveNotificationT,
166165
],
167166
):
168167
"""Pure abstract interface for MCP sessions.
169168
170-
This class defines the contract that all session implementations must satisfy,
171-
without managing any state. Subclasses are responsible for their own initialization
172-
and state management.
169+
This protocol defines the contract that all session implementations must satisfy,
170+
irrespective of the transport used.
173171
"""
174172

175-
@abstractmethod
176173
async def send_request(
177174
self,
178175
request: SendRequestT,
@@ -188,18 +185,16 @@ async def send_request(
188185
189186
Do not use this method to emit notifications! Use send_notification() instead.
190187
"""
191-
raise NotImplementedError
188+
...
192189

193-
@abstractmethod
194190
async def send_notification(
195191
self,
196192
notification: SendNotificationT,
197193
related_request_id: RequestId | None = None,
198194
) -> None:
199195
"""Emits a notification, which is a one-way message that does not expect a response."""
200-
raise NotImplementedError
196+
...
201197

202-
@abstractmethod
203198
async def send_progress_notification(
204199
self,
205200
progress_token: ProgressToken,
@@ -208,13 +203,17 @@ async def send_progress_notification(
208203
message: str | None = None,
209204
) -> None:
210205
"""Sends a progress notification for a request that is currently being processed."""
211-
raise NotImplementedError
206+
...
212207

213208

214209
class BaseSession(
215210
AbstractBaseSession[
216211
SendRequestT,
217212
SendNotificationT,
213+
],
214+
Generic[
215+
SendRequestT,
216+
SendNotificationT,
218217
SendResultT,
219218
ReceiveRequestT,
220219
ReceiveNotificationT,

0 commit comments

Comments
 (0)