agentscope-ai/agentscope · error · ValueError

The MCP client '{client.name}' is stateful, but not connecte

Error message

The MCP client '{client.name}' is stateful, but not connected.

What it means

Toolkit.__init__ validates that every stateful MCP client inside its tool groups has an active connection before the toolkit is used. Stateful clients keep sessions open, so a disconnected one would fail on first tool call; the error is raised up front instead.

Source

Thrown at src/agentscope/tool/_toolkit.py:148

                tools=tools or [],
                skills_or_loaders=skills_or_loaders or [],
                mcps=mcps or [],
            ),
        ] + (tool_groups or [])

        # Check name conflict for tool groups
        if len(set(_.name for _ in self.tool_groups)) != len(
            self.tool_groups,
        ):
            raise ValueError(
                "Tool groups must not contain duplicate tool groups.",
            )

        # The stateful MCP clients should be initialized already
        for group in self.tool_groups:
            for client in group.mcps:
                if client.is_stateful and not client.is_connected:
                    raise ValueError(
                        f"The MCP client '{client.name}' is stateful, but "
                        f"not connected.",
                    )

        self.meta_tool_response_template = meta_tool_response_template
        self.skill_instruction_template = skill_instruction_template

        self.builtin_meta_tool = RegisteredTool(
            tool=ResetTools(
                # An inference value for groups so that it can generate the
                # corresponding input schema.
                groups=self.tool_groups,
                response_template=meta_tool_response_template,
            ),
        )

        self.builtin_skill_viewer = RegisteredTool(
            tool=SkillViewer(

View on GitHub (pinned to e90f1c7592)

Solutions

  1. Call `await client.connect()` on every stateful MCP client before constructing the Toolkit
  2. Ensure connect() completed (await it, don't fire-and-forget) if connections are made in async setup
  3. If the client doesn't need a live session, use a stateless MCP client configuration instead

Example fix

# before
client = MCPClient(...)
toolkit = Toolkit(tool_groups=[ToolGroup(name='g', mcps=[client])])
# after
client = MCPClient(...)
await client.connect()
toolkit = Toolkit(tool_groups=[ToolGroup(name='g', mcps=[client])])
Defensive patterns

Strategy: validation

Validate before calling

for g in tool_groups:
    for c in g.mcps:
        if c.is_stateful and not c.is_connected:
            await c.connect()
toolkit = Toolkit(tool_groups=tool_groups)

Try / catch

try:
    toolkit = Toolkit(tool_groups=groups)
except ValueError as e:
    if 'not connected' in str(e):
        for c in all_mcps:
            await c.connect()
        toolkit = Toolkit(tool_groups=groups)

Prevention

When it happens

Trigger: Passing a ToolGroup whose mcps include a stateful MCP client (is_stateful=True) that has not had await client.connect() called yet, or whose connection was closed before Toolkit creation.

Common situations: Forgetting to connect MCP clients before building the agent/toolkit; reconnecting flows where connect() is skipped after a disconnect; ordering bugs where Toolkit is constructed before async setup completes.

Related errors


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