agentscope-ai/agentscope · error · RuntimeError

MCP '{self.name}' is not connected. Call connect() first.

Error message

MCP '{self.name}' is not connected. Call connect() first.

What it means

close() on a stateful MCPClient raises if the client is not currently connected. Since stateless MCPs skip this check, this specifically guards stateful sessions from closing an already-closed or never-connected transport stack, which would otherwise be a no-op masking lifecycle bugs.

Source

Thrown at src/agentscope/mcp/_mcp_client.py:280

        """Close the MCP connection (for stateful connections only).

        For stateless connections, this method does nothing.

        Args:
            ignore_errors: Whether to ignore errors during cleanup.

        Raises:
            RuntimeError: If not connected.
        """
        if not self.is_stateful:
            logger.debug(
                "Stateless MCP '%s' does not require explicit close.",
                self.name,
            )
            return

        if not self._is_connected:
            raise RuntimeError(
                f"MCP '{self.name}' is not connected. "
                "Call connect() first.",
            )

        try:
            await self._stack.aclose()
        except Exception as e:
            if not ignore_errors:
                raise e
            logger.warning(
                "Error closing MCP '%s': %s",
                self.name,
                str(e),
            )
        finally:
            self._client = None
            self._stack = None
            self._session = None

View on GitHub (pinned to e90f1c7592)

Solutions

  1. Track connection state and only close when connected, or check _is_connected before calling close()
  2. Wrap close() in try/except RuntimeError for unconditional cleanup paths
  3. Ensure close() is called exactly once, e.g. via a finally block around the connected region

Example fix

// before
finally:
    await client.close()  # raises 227 if connect() failed or already closed

// after
finally:
    if client._is_connected:
        await client.close()
Defensive patterns

Strategy: validation

Validate before calling

if getattr(client, "_is_connected", False):
    await client.close()

Try / catch

try:
    await client.close()
except RuntimeError as e:
    if "not connected" in str(e):
        pass  # already closed; nothing to do
    else:
        raise

Prevention

When it happens

Trigger: await client.close() without a prior successful connect(); or close() called twice (the first close resets _is_connected); or close() after connect() failed midway.

Common situations: Cleanup paths in finally blocks that run even when setup failed; agent shutdown routines that close all MCPs regardless of connection state; double-shutdown in tests.

Related errors


AI-assisted analysis of agentscope-ai/agentscope@e90f1c7592 (2026-08-28). Data as JSON: /api/errors/ce3d8c6c44dcaff7. Report an issue: GitHub.