{"record":{"id":"f79b5e599a14fc2f","repo":"agentscope-ai/agentscope","slug":"the-mcp-client-client-name-is-stateful-but-no","errorCode":null,"errorMessage":"The MCP client '{client.name}' is stateful, but not connected.","messagePattern":"The MCP client '(.+?)' is stateful, but not connected\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/agentscope/tool/_toolkit.py","lineNumber":148,"sourceCode":"                tools=tools or [],\n                skills_or_loaders=skills_or_loaders or [],\n                mcps=mcps or [],\n            ),\n        ] + (tool_groups or [])\n\n        # Check name conflict for tool groups\n        if len(set(_.name for _ in self.tool_groups)) != len(\n            self.tool_groups,\n        ):\n            raise ValueError(\n                \"Tool groups must not contain duplicate tool groups.\",\n            )\n\n        # The stateful MCP clients should be initialized already\n        for group in self.tool_groups:\n            for client in group.mcps:\n                if client.is_stateful and not client.is_connected:\n                    raise ValueError(\n                        f\"The MCP client '{client.name}' is stateful, but \"\n                        f\"not connected.\",\n                    )\n\n        self.meta_tool_response_template = meta_tool_response_template\n        self.skill_instruction_template = skill_instruction_template\n\n        self.builtin_meta_tool = RegisteredTool(\n            tool=ResetTools(\n                # An inference value for groups so that it can generate the\n                # corresponding input schema.\n                groups=self.tool_groups,\n                response_template=meta_tool_response_template,\n            ),\n        )\n\n        self.builtin_skill_viewer = RegisteredTool(\n            tool=SkillViewer(","sourceCodeStart":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/agentscope-ai/agentscope/blob/e90f1c7592896cc95f6e5ee506194f533378247d/src/agentscope/tool/_toolkit.py#L130-L166","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Call `await client.connect()` on every stateful MCP client before constructing the Toolkit","Ensure connect() completed (await it, don't fire-and-forget) if connections are made in async setup","If the client doesn't need a live session, use a stateless MCP client configuration instead"],"exampleFix":"# before\nclient = MCPClient(...)\ntoolkit = Toolkit(tool_groups=[ToolGroup(name='g', mcps=[client])])\n# after\nclient = MCPClient(...)\nawait client.connect()\ntoolkit = Toolkit(tool_groups=[ToolGroup(name='g', mcps=[client])])","handlingStrategy":"validation","validationCode":"for g in tool_groups:\n    for c in g.mcps:\n        if c.is_stateful and not c.is_connected:\n            await c.connect()\ntoolkit = Toolkit(tool_groups=tool_groups)","typeGuard":null,"tryCatchPattern":"try:\n    toolkit = Toolkit(tool_groups=groups)\nexcept ValueError as e:\n    if 'not connected' in str(e):\n        for c in all_mcps:\n            await c.connect()\n        toolkit = Toolkit(tool_groups=groups)","preventionTips":["Always await connect() in async setup before building the Toolkit","Centralize MCP client creation + connection in one factory function"],"tags":["mcp","connection","toolkit","async"],"backgroundTag":"client-not-connected","analyzedSha":"e90f1c7592896cc95f6e5ee506194f533378247d","analyzedAt":"2026-08-28T18:24:12.087Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}