Skip to content

Commit 52f4f89

Browse files
committed
fix(client): allow ClientSessionGroup to connect servers with no components (#3578)
1 parent f1b6589 commit 52f4f89

2 files changed

Lines changed: 24 additions & 5 deletions

File tree

‎src/mcp/client/session_group.py‎

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -414,11 +414,6 @@ async def _aggregate_components(self, server_info: types.Implementation, session
414414
except MCPError as err: # pragma: no cover
415415
logging.warning(f"Could not fetch tools: {err}")
416416

417-
# Clean up exit stack for session if we couldn't retrieve anything
418-
# from the server.
419-
if not any((prompts_temp, resources_temp, tools_temp)):
420-
del self._session_exit_stacks[session] # pragma: no cover
421-
422417
# Check for duplicates.
423418
matching_prompts = prompts_temp.keys() & self._prompts.keys()
424419
if matching_prompts:

‎tests/client/test_session_group.py‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,3 +402,27 @@ async def test_client_session_group_establish_session_parameterized(
402402
# 3. Assert returned values
403403
assert returned_server_info is mock_initialize_result.server_info
404404
assert returned_session is mock_entered_session
405+
406+
407+
@pytest.mark.anyio
408+
async def test_client_session_group_connect_empty_components_server():
409+
"""Test connecting a server that exposes no components (tools, prompts, or resources)."""
410+
mock_server_info = mock.Mock(spec=types.Implementation)
411+
mock_server_info.name = "EmptyServer"
412+
mock_session = mock.AsyncMock(spec=mcp.ClientSession)
413+
mock_session.list_tools.return_value = mock.AsyncMock(tools=[])
414+
mock_session.list_resources.return_value = mock.AsyncMock(resources=[])
415+
mock_session.list_prompts.return_value = mock.AsyncMock(prompts=[])
416+
417+
group = ClientSessionGroup()
418+
# Should not raise KeyError when aggregating empty components
419+
await group.connect_with_session(mock_server_info, mock_session)
420+
421+
assert mock_session in group._sessions
422+
assert group.tools == {}
423+
assert group.resources == {}
424+
assert group.prompts == {}
425+
426+
# Disconnecting should also succeed cleanly
427+
await group.disconnect_from_server(mock_session)
428+
assert mock_session not in group._sessions

0 commit comments

Comments
 (0)