Skip to content

Commit 9e88019

Browse files
kxbnbclaude
andcommitted
Store server_info on ClientSession during initialization
Adds `_server_info` attribute to ClientSession that is populated from InitializeResult.server_info after initialize() completes. Also adds a `get_server_info()` accessor method matching get_server_capabilities(). This lets clients access the server's name and version without needing to capture the initialize() return value. Fixes #1018 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 4a2d83a commit 9e88019

File tree

2 files changed

+66
-0
lines changed

2 files changed

+66
-0
lines changed

src/mcp/client/session.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ def __init__(
133133
self._message_handler = message_handler or _default_message_handler
134134
self._tool_output_schemas: dict[str, dict[str, Any] | None] = {}
135135
self._server_capabilities: types.ServerCapabilities | None = None
136+
self._server_info: types.Implementation | None = None
136137
self._experimental_features: ExperimentalClientFeatures | None = None
137138

138139
# Experimental: Task handlers (use defaults if not provided)
@@ -190,6 +191,7 @@ async def initialize(self) -> types.InitializeResult:
190191
raise RuntimeError(f"Unsupported protocol version from the server: {result.protocol_version}")
191192

192193
self._server_capabilities = result.capabilities
194+
self._server_info = result.server_info
193195

194196
await self.send_notification(types.InitializedNotification())
195197

@@ -202,6 +204,13 @@ def get_server_capabilities(self) -> types.ServerCapabilities | None:
202204
"""
203205
return self._server_capabilities
204206

207+
def get_server_info(self) -> types.Implementation | None:
208+
"""Return the server info received during initialization.
209+
210+
Returns None if the session has not been initialized yet.
211+
"""
212+
return self._server_info
213+
205214
@property
206215
def experimental(self) -> ExperimentalClientFeatures:
207216
"""Experimental APIs for tasks and other features.

tests/client/test_session.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,63 @@ async def mock_server():
607607
assert capabilities.tools.list_changed is False
608608

609609

610+
@pytest.mark.anyio
611+
async def test_get_server_info():
612+
"""Test that get_server_info returns None before init and server info after"""
613+
client_to_server_send, client_to_server_receive = anyio.create_memory_object_stream[SessionMessage](1)
614+
server_to_client_send, server_to_client_receive = anyio.create_memory_object_stream[SessionMessage](1)
615+
616+
expected_server_info = Implementation(name="test-server", version="1.2.3")
617+
618+
async def mock_server():
619+
session_message = await client_to_server_receive.receive()
620+
jsonrpc_request = session_message.message
621+
assert isinstance(jsonrpc_request, JSONRPCRequest)
622+
request = client_request_adapter.validate_python(
623+
jsonrpc_request.model_dump(by_alias=True, mode="json", exclude_none=True)
624+
)
625+
assert isinstance(request, InitializeRequest)
626+
627+
result = InitializeResult(
628+
protocol_version=LATEST_PROTOCOL_VERSION,
629+
capabilities=ServerCapabilities(),
630+
server_info=expected_server_info,
631+
)
632+
633+
async with server_to_client_send:
634+
await server_to_client_send.send(
635+
SessionMessage(
636+
JSONRPCResponse(
637+
jsonrpc="2.0",
638+
id=jsonrpc_request.id,
639+
result=result.model_dump(by_alias=True, mode="json", exclude_none=True),
640+
)
641+
)
642+
)
643+
await client_to_server_receive.receive()
644+
645+
async with (
646+
ClientSession(
647+
server_to_client_receive,
648+
client_to_server_send,
649+
) as session,
650+
anyio.create_task_group() as tg,
651+
client_to_server_send,
652+
client_to_server_receive,
653+
server_to_client_send,
654+
server_to_client_receive,
655+
):
656+
assert session.get_server_info() is None
657+
658+
tg.start_soon(mock_server)
659+
await session.initialize()
660+
661+
server_info = session.get_server_info()
662+
assert server_info is not None
663+
assert server_info.name == "test-server"
664+
assert server_info.version == "1.2.3"
665+
666+
610667
@pytest.mark.anyio
611668
@pytest.mark.parametrize(argnames="meta", argvalues=[None, {"toolMeta": "value"}])
612669
async def test_client_tool_call_with_meta(meta: RequestParamsMeta | None):

0 commit comments

Comments
 (0)