fix: close AsyncExitStack on MCP init/tool-discovery failure (#1493)

If session.initialize() or list_tools() raises after the stdio
subprocess or SSE connection is already open, the AsyncExitStack is
never closed — leaking the child process or HTTP connection. Wrap the
setup phase in try/except to aclose() the stack before re-raising.
This commit is contained in:
Paulo Victor Cordeiro
2026-06-03 06:23:46 +01:00
committed by GitHub
parent 8c4ea484a9
commit 1feb2ae7d5

View File

@@ -89,14 +89,18 @@ class McpManager:
)
stack = AsyncExitStack()
transport = await stack.enter_async_context(stdio_client(server_params))
read_stream, write_stream = transport
session = await stack.enter_async_context(ClientSession(read_stream, write_stream))
try:
transport = await stack.enter_async_context(stdio_client(server_params))
read_stream, write_stream = transport
session = await stack.enter_async_context(ClientSession(read_stream, write_stream))
await session.initialize()
await session.initialize()
# Discover tools
tools_result = await session.list_tools()
# Discover tools
tools_result = await session.list_tools()
except Exception:
await stack.aclose()
raise
tools = []
for tool in tools_result.tools:
tools.append({
@@ -142,14 +146,18 @@ class McpManager:
from contextlib import AsyncExitStack
stack = AsyncExitStack()
transport = await stack.enter_async_context(sse_client(url))
read_stream, write_stream = transport
session = await stack.enter_async_context(ClientSession(read_stream, write_stream))
try:
transport = await stack.enter_async_context(sse_client(url))
read_stream, write_stream = transport
session = await stack.enter_async_context(ClientSession(read_stream, write_stream))
await session.initialize()
await session.initialize()
# Discover tools
tools_result = await session.list_tools()
# Discover tools
tools_result = await session.list_tools()
except Exception:
await stack.aclose()
raise
tools = []
for tool in tools_result.tools:
tools.append({