Skip to content

Commit 13730be

Browse files
committed
Close the transport when connect_to_server rejects a session.
1 parent 9972c21 commit 13730be

2 files changed

Lines changed: 15 additions & 2 deletions

File tree

src/mcp/client/session_group.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,13 @@ async def connect_to_server(
298298
) -> mcp.ClientSession:
299299
"""Connects to a single MCP server."""
300300
server_info, session = await self._establish_session(server_params, session_params or ClientSessionParameters())
301-
return await self.connect_with_session(server_info, session)
301+
try:
302+
return await self.connect_with_session(server_info, session)
303+
except BaseException:
304+
session_stack = self._session_exit_stacks.pop(session, None)
305+
if session_stack is not None:
306+
await session_stack.aclose()
307+
raise
302308

303309
async def _establish_session(
304310
self,

tests/client/test_session_group.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,13 +266,18 @@ async def test_client_session_group_connect_to_server_duplicate_tool_raises_erro
266266
# Keep other lists empty for simplicity
267267
mock_session_new.list_resources.return_value = mock.AsyncMock(resources=[])
268268
mock_session_new.list_prompts.return_value = mock.AsyncMock(prompts=[])
269+
mock_stack_new = mock.AsyncMock(spec=contextlib.AsyncExitStack)
270+
271+
async def _establish(*_args: object, **_kwargs: object):
272+
group._session_exit_stacks[mock_session_new] = mock_stack_new
273+
return mock_server_info_new, mock_session_new
269274

270275
# --- Test Execution and Assertion ---
271276
with pytest.raises(MCPError) as excinfo:
272277
with mock.patch.object(
273278
group,
274279
"_establish_session",
275-
return_value=(mock_server_info_new, mock_session_new),
280+
side_effect=_establish,
276281
):
277282
await group.connect_to_server(StdioServerParameters(command="test"))
278283

@@ -284,6 +289,8 @@ async def test_client_session_group_connect_to_server_duplicate_tool_raises_erro
284289
# Verify the duplicate tool was *not* added again (state should be unchanged)
285290
assert len(group._tools) == 1 # Should still only have the original
286291
assert group._tools[existing_tool_name] is not duplicate_tool # Ensure it's the original mock
292+
mock_stack_new.aclose.assert_awaited()
293+
assert mock_session_new not in group._session_exit_stacks
287294

288295

289296
@pytest.mark.anyio

0 commit comments

Comments
 (0)