agentscope-ai/agentscope · error · RuntimeError
MCP '{self.name}' is already connected. Call close() before
Error message
MCP '{self.name}' is already connected. Call close() before reconnecting. What it means
For stateful MCP connections, connect() refuses to run twice without an intervening close(), because the underlying transport/session resources (an AsyncExitStack of one-shot transports) are already allocated. This prevents leaking sessions and duplicated subprocesses/connections.
Source
Thrown at src/agentscope/mcp/_mcp_client.py:230
)
async def connect(self) -> None:
"""Connect to the MCP server (for stateful connections only).
For stateless connections, this method does nothing.
Raises:
RuntimeError: If already connected.
"""
if not self.is_stateful:
logger.debug(
"Stateless MCP '%s' does not require explicit connect.",
self.name,
)
return
if self._is_connected:
raise RuntimeError(
f"MCP '{self.name}' is already connected. "
"Call close() before reconnecting.",
)
# Transports are one-shot context managers. Recreate them before every
# connection so connect() -> close() -> connect() starts a fresh one.
if self._client is None:
if self.mcp_config.type == "http_mcp":
self._client = self._create_http_client()
else:
self._initialize_client()
assert self._client is not None
self._stack = AsyncExitStack()
try:
context = await self._stack.enter_async_context(self._client)
read_stream, write_stream = context[0], context[1]View on GitHub (pinned to e90f1c7592)
Solutions
- Call await client.close() before reconnecting, ideally in a finally block after the first connect
- Guard with if client._is_connected / a wrapper that checks connection state before connect()
- Reuse a single connected client instead of reconnecting per operation
Example fix
// before
await client.connect()
try:
...
except Exception:
await client.connect() # RuntimeError 226
// after
try:
await client.connect()
...
finally:
await client.close()
await client.connect() # fresh one-shot transport, OK Defensive patterns
Strategy: try-catch
Validate before calling
if getattr(client, "_is_connected", False):
await client.close()
await client.connect() Try / catch
try:
await client.connect()
except RuntimeError as e:
if "already connected" in str(e):
await client.close()
await client.connect()
else:
raise Prevention
- Wrap connect/close in a lifecycle manager (async context manager) so pairing is guaranteed
- Use try/finally around the connected region
- Retry loops must close before reconnecting
When it happens
Trigger: Calling await client.connect() a second time on a stateful MCPClient (e.g. in a retry loop or after an exception that left the client connected), typically via agent.add_mcp(...) reconnect logic.
Common situations: Retrying initialization on transient failures without closing first; framework restart/reload handlers that re-run setup code; multiple components each trying to register/connect the same shared MCPClient.
Related errors
- MCP '{self.name}' is not connected. Call connect() first.
- STDIO MCP does not support ephemeral mode. Use 'shared' or '
- Invalid values for MCP {card.name!r}: {e.message}
- MCP {card.name!r} needs a value for: {', '.join(sorted(missi
- MCP {card.name!r} produced an invalid client: {e}
AI-assisted analysis of agentscope-ai/agentscope@e90f1c7592 (2026-08-28).
Data as JSON: /api/errors/5e0a48cd2de288e4.
Report an issue: GitHub.