-
Notifications
You must be signed in to change notification settings - Fork 3k
Support different transports in Client #1972
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Code reviewNo issues found. Checked for bugs and CLAUDE.md compliance. |
Code reviewNo issues found. Checked for bugs and CLAUDE.md compliance. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR introduces support for different transports in the Client class, making it more flexible and extensible. The changes enable the Client to work with URL strings, Transport instances, or Server/MCPServer instances, while standardizing the transport interface.
Changes:
- Introduces a
Transportprotocol that standardizes how client transports work - Refactors
Clientclass from manual init to dataclass for better maintainability - Removes the
get_session_idcallback fromstreamable_http_clientto align with Transport protocol (now returns 2-tuple instead of 3-tuple) - Updates
InMemoryTransportto implement the Transport protocol as an async context manager - Updates all tests, examples, and documentation to reflect the 2-tuple return signature
Reviewed changes
Copilot reviewed 25 out of 25 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
src/mcp/client/_transport.py |
New file defining the Transport protocol and TransportStreams type |
src/mcp/client/_memory.py |
Refactored InMemoryTransport to implement Transport protocol via aenter/aexit |
src/mcp/client/client.py |
Converted Client to dataclass, added support for URL strings and Transport instances |
src/mcp/client/streamable_http.py |
Removed get_session_id callback, now returns 2-tuple matching Transport protocol |
src/mcp/client/session_group.py |
Updated to unpack 2-tuple from streamable_http_client |
src/mcp/client/__init__.py |
Added Transport to public exports |
tests/* |
Updated all tests to unpack 2-tuple instead of 3-tuple |
examples/* |
Updated all example clients to use new 2-tuple signature |
docs/migration.md |
Added migration guide for get_session_id callback removal |
README.md, README.v2.md |
Updated code examples to reflect new signature |
.github/actions/conformance/client.py |
Updated conformance tests for new signature |
CLAUDE.md |
Emphasized rule about imports at top of file |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # Transports may return additional values (e.g., streamable_http_client returns a 3-tuple) | ||
| # We only need the first two elements (read_stream, write_stream) |
Copilot
AI
Jan 30, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment mentions that "Transports may return additional values (e.g., streamable_http_client returns a 3-tuple)" but this is no longer accurate. The streamable_http_client now returns a 2-tuple (read_stream, write_stream) as indicated by the TransportStreams type. This comment should be updated or removed.
| # Transports may return additional values (e.g., streamable_http_client returns a 3-tuple) | |
| # We only need the first two elements (read_stream, write_stream) | |
| # Transports return a 2-tuple (read_stream, write_stream) |
| ```python | ||
| from mcp.client import Client, ClientSession | ||
| from mcp.server.mcpserver import MCPServer | ||
| from mcp.client.memory import InMemoryTransport |
Copilot
AI
Jan 30, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The import path in the docstring example is incorrect. It shows from mcp.client.memory import InMemoryTransport but InMemoryTransport is in the _memory module (with underscore). The import should be either from mcp.client._memory import InMemoryTransport or InMemoryTransport should be exported from the public client module. Since InMemoryTransport is not currently exported in src/mcp/client/__init__.py, users should either use it via the underscore import (which suggests it's internal) or it should be added to the public exports.
| from mcp.client.memory import InMemoryTransport | |
| from mcp.client._memory import InMemoryTransport |
| _session: ClientSession | None = None | ||
| _exit_stack: AsyncExitStack | None = None |
Copilot
AI
Jan 30, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The _session and _exit_stack fields are initialized to None in the dataclass but are not marked with field(default=None). While this works because None is the default for Optional types, it's better to be explicit in dataclasses, especially since _transport uses field(init=False). Consider using field(default=None, init=False) for consistency and clarity.
| _session: ClientSession | None = None | |
| _exit_stack: AsyncExitStack | None = None | |
| _session: ClientSession | None = field(default=None, init=False) | |
| _exit_stack: AsyncExitStack | None = field(default=None, init=False) |
| streams = await exit_stack.enter_async_context(self._transport) | ||
| read_stream, write_stream = streams[0], streams[1] |
Copilot
AI
Jan 30, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The unpacking pattern streams = await exit_stack.enter_async_context(self._transport); read_stream, write_stream = streams[0], streams[1] is unnecessarily verbose. Since TransportStreams is defined as a 2-tuple, you can directly unpack: read_stream, write_stream = await exit_stack.enter_async_context(self._transport). This is more Pythonic and clearer.
This pull request updates the MCP client codebase to simplify and standardize the transport interface for client-server communication. The main change is that the
streamable_http_clientand related transports now return only a 2-tuple(read_stream, write_stream), removing the previously returnedget_session_idcallback. The documentation and all usage examples have been updated accordingly. Additionally, a newTransportprotocol is introduced to formalize the transport interface, and the in-memory transport is refactored to support async context management. Minor documentation clarifications and type cleanups are also included.Key changes:
Transport Interface Simplification
The
streamable_http_clientnow returns a 2-tuple(read_stream, write_stream)instead of a 3-tuple withget_session_id. All usages in code, examples, and documentation have been updated to match this new interface. [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17]The
get_session_idcallback is now documented as removed, with migration instructions and alternatives using httpx event hooks provided indocs/migration.md.Transport Protocol and In-Memory Transport Refactor
Introduced a new
Transportprotocol insrc/mcp/client/_transport.pyto standardize the interface for all client transports. [1] [2]Refactored
InMemoryTransportto implement async context management (__aenter__/__aexit__), and updated its usage and documentation for consistency with the new protocol. [1] [2] [3] [4]Documentation and Typing Improvements
Updated
README.v2.md, and all relevant example clients to reflect the new transport interface and provide clear, accurate usage patterns. [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12]Minor documentation clarifications and type annotation cleanups, including a note in
CLAUDE.mdabout import placement and type signature simplifications. [1] [2]These changes improve consistency, usability, and maintainability of the MCP client transport layer and its documentation.