You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The session hierarchy has been refactored to support pluggable transport implementations. This introduces several breaking changes:
772
772
773
+
#### New `AbstractBaseSession` Protocol
774
+
775
+
A new runtime-checkable Protocol, AbstractBaseSession, establishes a transport-agnostic contract for all MCP sessions. It ensures that client and server sessions share a consistent communication interface regardless of the transport used.
776
+
777
+
**Key characteristics of `AbstractBaseSession`:**
778
+
779
+
To maintain a clean architectural boundary, AbstractBaseSession is a pure interface—it defines what methods must exist but does not manage how they work.
780
+
781
+
***No State Management**: The protocol does not handle internal machinery like task groups, response streams, or buffers.
782
+
783
+
***Implementation Ownership**: The concrete class is now fully responsible for managing its own state and lifecycle for how it sends and receives data.
784
+
785
+
***No Inheritance Needed**: As a structural protocol, you no longer need to call super().**init**() or inherit from a base class to satisfy the contract.
786
+
787
+
**Motivation: Interface vs. Implementation**
788
+
Previously, all custom sessions were required to inherit from BaseSession, which locked them into a specific architecture involving memory streams and JSON-RPC message routing, but now users have the flexibility to implement their own transport logic.
789
+
790
+
BaseSession (Implementation): Remains available for transports that follow the standard pattern of reading and writing JSON-RPC messages over streams. You can continue to inherit from this if you want the SDK to handle message linking and routing for you.
791
+
792
+
AbstractBaseSession (Interface): A new stateless protocol for transports that do not use standard streams or JSON-RPC. It defines the "what" (method signatures) without enforcing the "how" (internal machinery).
793
+
794
+
**Before:**
795
+
796
+
```python
797
+
from mcp.shared.session import BaseSession
798
+
799
+
# Locked into the BaseSession implementation details
800
+
classMyCustomSession(BaseSession[...]):
801
+
def__init__(self, read_stream, write_stream):
802
+
# Mandatory: must use streams and JSON-RPC machinery
803
+
super().__init__(read_stream, write_stream)
804
+
```
805
+
806
+
**After:**
807
+
808
+
```python
809
+
# OPTION A: Continue using BaseSession (for stream-based JSON-RPC)
810
+
classMyStreamSession(BaseSession):
811
+
...
812
+
813
+
# OPTION B: Use AbstractBaseSession (for non-stream/custom transports)
#### Introduction of the `BaseClientSession` Protocol
825
+
826
+
A new runtime-checkable Protocol, BaseClientSession, has been introduced to establish a common interface for all MCP client sessions. This protocol defines the essential methods—such as `send_request`, `send_notification`, and `initialize`, etc. — that a session must implement to be compatible with the SDK's client utilities.
827
+
828
+
The primary goal of this protocol is to ensure that the high-level session logic remains consistent irrespective of the underlying transport. Custom session implementations can now satisfy the SDK's requirements simply by implementing the defined methods. No explicit inheritance is required.
829
+
830
+
```python
831
+
from mcp.client.base_client_session import BaseClientSession
832
+
833
+
classMyCustomTransportSession:
834
+
"""
835
+
A custom session implementation. It doesn't need to inherit from
836
+
BaseClientSession to be compatible.
837
+
"""
838
+
asyncdefinitialize(self) -> InitializeResult:
839
+
...
840
+
841
+
asyncdefsend_request(self, ...) -> Any:
842
+
...
843
+
844
+
# Implementing these methods makes this class a 'BaseClientSession'
845
+
```
846
+
847
+
Because the protocol is `@runtime_checkable`, you can verify that any session object adheres to the required structure using standard Python checks:
848
+
849
+
```python
850
+
defstart_client(session: BaseClientSession):
851
+
# This works for any object implementing the protocol
852
+
ifnotisinstance(session, BaseClientSession):
853
+
raiseTypeError("Session must implement the BaseClientSession protocol")
854
+
```
855
+
773
856
#### `ClientRequestContext` type changed
774
857
775
858
`ClientRequestContext` is now `RequestContext[BaseClientSession]` instead of `RequestContext[ClientSession]`. This means callbacks receive the more general `BaseClientSession` type, which may not have all methods available on `ClientSession`.
In `mcp.shared._context` and `mcp.shared.progress`, the `SessionT` TypeVar has been renamed to `SessionT_co` to follow naming conventions for covariant type variables.
835
-
836
-
**Before:**
837
-
838
-
```python
839
-
from mcp.shared._context import SessionT
840
-
```
841
-
842
-
**After:**
843
-
844
-
```python
845
-
from mcp.shared._context import SessionT_co
846
-
```
847
-
848
-
#### New `AbstractBaseSession` structural interface
849
-
850
-
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.
851
-
852
-
Key characteristics of `AbstractBaseSession`:
853
-
854
-
1.**Pure Interface**: It is a structural protocol with no implementation state or `__init__` method.
855
-
2.**Simplified Type Parameters**: It takes two parameters: `AbstractBaseSession[SendRequestT_contra, SendNotificationT_contra]`. Contravariant variance is used for these parameters to ensure that sessions can be used safely in generic contexts (like `RequestContext`).
856
-
3.**BaseSession Implementation**: The concrete implementation logic (state management, response routing) is provided by the `BaseSession` class, which satisfies the protocol.
857
-
858
-
**Before:**
859
-
860
-
```python
861
-
from mcp.shared.session import AbstractBaseSession
super().__init__() # Would set up _response_streams, _task_group
866
-
```
867
-
868
-
**After:**
915
+
#### Internal TypeVars Renamed and Variance Updated
869
916
870
-
```python
871
-
from mcp.shared.session import AbstractBaseSession
917
+
To support structural subtyping and ensure type safety across the new Protocol hierarchy, several internal TypeVariables have been updated with explicit variance (covariant or contravariant). These have been renamed to follow PEP 484 naming conventions.
872
918
873
-
classMySession(AbstractBaseSession[...]):
874
-
def__init__(self):
875
-
# Manage your own state - no super().__init__() to call
876
-
self._my_state = {}
877
-
```
878
-
879
-
#### `SendRequestT` renamed to `SendRequestT_contra`
880
-
881
-
The `SendRequestT` TypeVar is now defined as **contravariant** to support its use in the `AbstractBaseSession` Protocol and renamed accordingly to follow naming conventions for contravariant type variables.
919
+
| Original Name | Updated Name | Variance | Purpose |
920
+
| --- | --- | --- | --- |
921
+
| SessionT | SessionT_co | Covariant | Allows specialized sessions to be used where a base session is expected. |
922
+
| SendRequestT | SendRequestT_contra | Contravariant | Ensures request types can be safely handled by generic handlers. |
923
+
| SendNotificationT | SendNotificationT_contra | Contravariant | Ensures notification types are handled safely across the hierarchy. |
#### `SendNotificationT` renamed to `SendNotificationT_contra`
896
-
897
-
The `SendNotificationT` TypeVar is now defined as **contravariant** to support its use in the `AbstractBaseSession` Protocol and renamed accordingly to follow naming conventions for contravariant type variables.
#### `ReceiveResultT` renamed to `ReceiveResultT_co`
914
-
915
-
The `ReceiveResultT` TypeVar is now defined as **covariant** to support its use in the `AbstractBaseSession` Protocol and renamed accordingly to follow naming conventions for covariant type variables.
`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.
933
-
934
-
**Before:**
935
-
936
-
```python
937
-
from mcp.client.base_client_session import BaseClientSession
938
-
939
-
classMyClientSession(BaseClientSession):
940
-
asyncdefinitialize(self) -> InitializeResult:
941
-
...
942
-
```
943
-
944
-
**After:**
945
-
946
-
```python
947
-
from mcp.client.base_client_session import BaseClientSession
948
-
949
-
classMyClientSession:
950
-
# Just implement the methods - no inheritance needed
0 commit comments