Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -690,7 +690,7 @@ async with Client(server) as client:
result = await client.call_tool("my_tool", {"x": 1})
```

`Client` accepts the same callback parameters the old helper did (`sampling_callback`, `list_roots_callback`, `logging_callback`, `message_handler`, `elicitation_callback`, `client_info`) plus `raise_exceptions` to surface server-side errors.
`Client` accepts the same callback parameters the old helper did (`sampling_callback`, `list_roots_callback`, `logging_callback`, `message_callback`, `elicitation_callback`, `client_info`) plus `raise_exceptions` to surface server-side errors.

If you need direct access to the underlying `ClientSession` and memory streams (e.g., for low-level transport testing), `create_client_server_memory_streams` is still available in `mcp.shared.memory`:

Expand Down
4 changes: 2 additions & 2 deletions src/mcp/client/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
logger = logging.getLogger("client")


async def message_handler(
async def message_callback(
message: RequestResponder[types.ServerRequest, types.ClientResult] | types.ServerNotification | Exception,
) -> None:
if isinstance(message, Exception):
Expand All @@ -40,7 +40,7 @@ async def run_session(
async with ClientSession(
read_stream,
write_stream,
message_handler=message_handler,
message_callback=message_callback,
client_info=client_info,
) as session:
logger.info("Initializing session")
Expand Down
5 changes: 2 additions & 3 deletions src/mcp/client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,7 @@ async def main():
logging_callback: LoggingFnT | None = None
"""Callback for handling logging notifications."""

# TODO(Marcelo): Why do we have both "callback" and "handler"?
message_handler: MessageHandlerFnT | None = None
message_callback: MessageHandlerFnT | None = None
"""Callback for handling raw messages."""

client_info: Implementation | None = None
Expand Down Expand Up @@ -123,7 +122,7 @@ async def __aenter__(self) -> Client:
sampling_callback=self.sampling_callback,
list_roots_callback=self.list_roots_callback,
logging_callback=self.logging_callback,
message_handler=self.message_handler,
message_callback=self.message_callback,
client_info=self.client_info,
elicitation_callback=self.elicitation_callback,
)
Expand Down
10 changes: 5 additions & 5 deletions src/mcp/client/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ async def __call__(
) -> None: ... # pragma: no branch


async def _default_message_handler(
async def _default_message_callback(
message: RequestResponder[types.ServerRequest, types.ClientResult] | types.ServerNotification | Exception,
) -> None:
await anyio.lowlevel.checkpoint()
Expand Down Expand Up @@ -116,7 +116,7 @@ def __init__(
elicitation_callback: ElicitationFnT | None = None,
list_roots_callback: ListRootsFnT | None = None,
logging_callback: LoggingFnT | None = None,
message_handler: MessageHandlerFnT | None = None,
message_callback: MessageHandlerFnT | None = None,
client_info: types.Implementation | None = None,
*,
sampling_capabilities: types.SamplingCapability | None = None,
Expand All @@ -129,7 +129,7 @@ def __init__(
self._elicitation_callback = elicitation_callback or _default_elicitation_callback
self._list_roots_callback = list_roots_callback or _default_list_roots_callback
self._logging_callback = logging_callback or _default_logging_callback
self._message_handler = message_handler or _default_message_handler
self._message_callback = message_callback or _default_message_callback
self._tool_output_schemas: dict[str, dict[str, Any] | None] = {}
self._initialize_result: types.InitializeResult | None = None
self._experimental_features: ExperimentalClientFeatures | None = None
Expand Down Expand Up @@ -462,8 +462,8 @@ async def _handle_incoming(
self,
req: RequestResponder[types.ServerRequest, types.ClientResult] | types.ServerNotification | Exception,
) -> None:
"""Handle incoming messages by forwarding to the message handler."""
await self._message_handler(req)
"""Handle incoming messages by forwarding to the message callback."""
await self._message_callback(req)

async def _received_notification(self, notification: types.ServerNotification) -> None:
"""Handle notifications from the server."""
Expand Down
4 changes: 2 additions & 2 deletions src/mcp/client/session_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ class ClientSessionParameters:
elicitation_callback: ElicitationFnT | None = None
list_roots_callback: ListRootsFnT | None = None
logging_callback: LoggingFnT | None = None
message_handler: MessageHandlerFnT | None = None
message_callback: MessageHandlerFnT | None = None
client_info: types.Implementation | None = None


Expand Down Expand Up @@ -308,7 +308,7 @@ async def _establish_session(
elicitation_callback=session_params.elicitation_callback,
list_roots_callback=session_params.list_roots_callback,
logging_callback=session_params.logging_callback,
message_handler=session_params.message_handler,
message_callback=session_params.message_callback,
client_info=session_params.client_info,
)
)
Expand Down
4 changes: 2 additions & 2 deletions tests/client/test_logging_callback.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ async def test_tool_with_log_dict(
return True

# Create a message handler to catch exceptions
async def message_handler(
async def message_callback(
message: RequestResponder[types.ServerRequest, types.ClientResult] | types.ServerNotification | Exception,
) -> None:
if isinstance(message, Exception): # pragma: no cover
Expand All @@ -63,7 +63,7 @@ async def message_handler(
async with Client(
server,
logging_callback=logging_collector,
message_handler=message_handler,
message_callback=message_callback,
) as client:
# First verify our test tool works
result = await client.call_tool("test_tool", {})
Expand Down
4 changes: 2 additions & 2 deletions tests/client/test_notification_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ async def test_non_compliant_notification_response() -> None:
"""
returned_exception = None

async def message_handler( # pragma: no cover
async def message_callback( # pragma: no cover
message: RequestResponder[types.ServerRequest, types.ClientResult] | types.ServerNotification | Exception,
) -> None:
nonlocal returned_exception
Expand All @@ -90,7 +90,7 @@ async def message_handler( # pragma: no cover

async with httpx.AsyncClient(transport=httpx.ASGITransport(app=_create_non_sdk_server_app())) as client:
async with streamable_http_client("http://localhost/mcp", http_client=client) as (read_stream, write_stream):
async with ClientSession(read_stream, write_stream, message_handler=message_handler) as session:
async with ClientSession(read_stream, write_stream, message_callback=message_callback) as session:
await session.initialize()

# The test server returns a 204 instead of the expected 202
Expand Down
4 changes: 2 additions & 2 deletions tests/client/test_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ async def mock_server():
)

# Create a message handler to catch exceptions
async def message_handler( # pragma: no cover
async def message_callback( # pragma: no cover
message: RequestResponder[types.ServerRequest, types.ClientResult] | types.ServerNotification | Exception,
) -> None:
if isinstance(message, Exception):
Expand All @@ -87,7 +87,7 @@ async def message_handler( # pragma: no cover
ClientSession(
server_to_client_receive,
client_to_server_send,
message_handler=message_handler,
message_callback=message_callback,
) as session,
anyio.create_task_group() as tg,
client_to_server_send,
Expand Down
2 changes: 1 addition & 1 deletion tests/client/test_session_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ async def test_client_session_group_establish_session_parameterized(
elicitation_callback=None,
list_roots_callback=None,
logging_callback=None,
message_handler=None,
message_callback=None,
client_info=None,
)
mock_raw_session_cm.__aenter__.assert_awaited_once()
Expand Down
26 changes: 13 additions & 13 deletions tests/experimental/tasks/client/test_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ async def client_streams() -> AsyncIterator[ClientTestStreams]:
await client_to_server_receive.aclose()


async def _default_message_handler(
async def _default_message_callback(
message: RequestResponder[ServerRequest, ClientResult] | ServerNotification | Exception,
) -> None:
"""Default message handler that ignores messages (tests handle them explicitly)."""
Expand Down Expand Up @@ -141,7 +141,7 @@ async def run_client() -> None:
async with ClientSession(
client_streams.client_receive,
client_streams.client_send,
message_handler=_default_message_handler,
message_callback=_default_message_callback,
experimental_task_handlers=task_handlers,
):
client_ready.set()
Expand Down Expand Up @@ -200,7 +200,7 @@ async def run_client() -> None:
async with ClientSession(
client_streams.client_receive,
client_streams.client_send,
message_handler=_default_message_handler,
message_callback=_default_message_callback,
experimental_task_handlers=task_handlers,
):
client_ready.set()
Expand Down Expand Up @@ -258,7 +258,7 @@ async def run_client() -> None:
async with ClientSession(
client_streams.client_receive,
client_streams.client_send,
message_handler=_default_message_handler,
message_callback=_default_message_callback,
experimental_task_handlers=task_handlers,
):
client_ready.set()
Expand Down Expand Up @@ -321,7 +321,7 @@ async def run_client() -> None:
async with ClientSession(
client_streams.client_receive,
client_streams.client_send,
message_handler=_default_message_handler,
message_callback=_default_message_callback,
experimental_task_handlers=task_handlers,
):
client_ready.set()
Expand Down Expand Up @@ -422,7 +422,7 @@ async def run_client() -> None:
async with ClientSession(
client_streams.client_receive,
client_streams.client_send,
message_handler=_default_message_handler,
message_callback=_default_message_callback,
experimental_task_handlers=task_handlers,
):
client_ready.set()
Expand Down Expand Up @@ -562,7 +562,7 @@ async def run_client() -> None:
async with ClientSession(
client_streams.client_receive,
client_streams.client_send,
message_handler=_default_message_handler,
message_callback=_default_message_callback,
experimental_task_handlers=task_handlers,
):
client_ready.set()
Expand Down Expand Up @@ -649,7 +649,7 @@ async def run_client() -> None:
async with ClientSession(
client_streams.client_receive,
client_streams.client_send,
message_handler=_default_message_handler,
message_callback=_default_message_callback,
):
client_ready.set()
await anyio.sleep_forever()
Expand Down Expand Up @@ -688,7 +688,7 @@ async def run_client() -> None:
async with ClientSession(
client_streams.client_receive,
client_streams.client_send,
message_handler=_default_message_handler,
message_callback=_default_message_callback,
):
client_ready.set()
await anyio.sleep_forever()
Expand Down Expand Up @@ -724,7 +724,7 @@ async def run_client() -> None:
async with ClientSession(
client_streams.client_receive,
client_streams.client_send,
message_handler=_default_message_handler,
message_callback=_default_message_callback,
):
client_ready.set()
await anyio.sleep_forever()
Expand Down Expand Up @@ -760,7 +760,7 @@ async def run_client() -> None:
async with ClientSession(
client_streams.client_receive,
client_streams.client_send,
message_handler=_default_message_handler,
message_callback=_default_message_callback,
):
client_ready.set()
await anyio.sleep_forever()
Expand Down Expand Up @@ -797,7 +797,7 @@ async def run_client() -> None:
async with ClientSession(
client_streams.client_receive,
client_streams.client_send,
message_handler=_default_message_handler,
message_callback=_default_message_callback,
):
client_ready.set()
await anyio.sleep_forever()
Expand Down Expand Up @@ -843,7 +843,7 @@ async def run_client() -> None:
async with ClientSession(
client_streams.client_receive,
client_streams.client_send,
message_handler=_default_message_handler,
message_callback=_default_message_callback,
):
client_ready.set()
await anyio.sleep_forever()
Expand Down
4 changes: 2 additions & 2 deletions tests/experimental/tasks/server/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ async def test_default_task_handlers_via_enable_tasks() -> None:
server_to_client_send, server_to_client_receive = anyio.create_memory_object_stream[SessionMessage](10)
client_to_server_send, client_to_server_receive = anyio.create_memory_object_stream[SessionMessage](10)

async def message_handler(
async def message_callback(
message: RequestResponder[ServerRequest, ClientResult] | ServerNotification | Exception,
) -> None: ... # pragma: no branch

Expand Down Expand Up @@ -351,7 +351,7 @@ async def run_server() -> None:
async with ClientSession(
server_to_client_receive,
client_to_server_send,
message_handler=message_handler,
message_callback=message_callback,
) as client_session:
await client_session.initialize()

Expand Down
8 changes: 4 additions & 4 deletions tests/server/mcpserver/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,12 +184,12 @@ async def test_tool_progress() -> None:
"""Test tool progress reporting."""
collector = NotificationCollector()

async def message_handler(message: RequestResponder[ServerRequest, ClientResult] | ServerNotification | Exception):
async def message_callback(message: RequestResponder[ServerRequest, ClientResult] | ServerNotification | Exception):
await collector.handle_generic_notification(message)
if isinstance(message, Exception): # pragma: no cover
raise message

async with Client(tool_progress.mcp, message_handler=message_handler) as client:
async with Client(tool_progress.mcp, message_callback=message_callback) as client:
# Test progress callback
progress_updates = []

Expand Down Expand Up @@ -263,12 +263,12 @@ async def test_notifications() -> None:
"""Test notifications and logging functionality."""
collector = NotificationCollector()

async def message_handler(message: RequestResponder[ServerRequest, ClientResult] | ServerNotification | Exception):
async def message_callback(message: RequestResponder[ServerRequest, ClientResult] | ServerNotification | Exception):
await collector.handle_generic_notification(message)
if isinstance(message, Exception): # pragma: no cover
raise message

async with Client(notifications.mcp, message_handler=message_handler) as client:
async with Client(notifications.mcp, message_callback=message_callback) as client:
# Call tool that generates notifications
tool_result = await client.call_tool("process_data", {"data": "test_data"})
assert len(tool_result.content) == 1
Expand Down
4 changes: 2 additions & 2 deletions tests/server/test_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ async def test_server_session_initialize():
client_to_server_send, client_to_server_receive = anyio.create_memory_object_stream[SessionMessage](1)

# Create a message handler to catch exceptions
async def message_handler( # pragma: no cover
async def message_callback( # pragma: no cover
message: RequestResponder[types.ServerRequest, types.ClientResult] | types.ServerNotification | Exception,
) -> None:
if isinstance(message, Exception):
Expand Down Expand Up @@ -63,7 +63,7 @@ async def run_server():
ClientSession(
server_to_client_receive,
client_to_server_send,
message_handler=message_handler,
message_callback=message_callback,
) as client_session,
anyio.create_task_group() as tg,
):
Expand Down
2 changes: 1 addition & 1 deletion tests/shared/test_progress_notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ async def handle_client_message(
ClientSession(
server_to_client_receive,
client_to_server_send,
message_handler=handle_client_message,
message_callback=handle_client_message,
) as client_session,
anyio.create_task_group() as tg,
):
Expand Down
6 changes: 3 additions & 3 deletions tests/shared/test_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ async def mock_server():


@pytest.mark.anyio
async def test_null_id_error_surfaced_via_message_handler():
async def test_null_id_error_surfaced_via_message_callback():
"""Test that a JSONRPCError with id=None is surfaced to the message handler.

Per JSON-RPC 2.0, error responses use id=null when the request id could not
Expand Down Expand Up @@ -338,7 +338,7 @@ async def mock_server():
ClientSession(
read_stream=client_read,
write_stream=client_write,
message_handler=capture_errors,
message_callback=capture_errors,
) as _client_session,
):
tg.start_soon(mock_server)
Expand Down Expand Up @@ -399,7 +399,7 @@ async def make_request(client_session: ClientSession):
ClientSession(
read_stream=client_read,
write_stream=client_write,
message_handler=capture_errors,
message_callback=capture_errors,
) as client_session,
):
tg.start_soon(mock_server)
Expand Down
Loading
Loading