{"record":{"id":"fff0f2fb97850c42","repo":"agentscope-ai/agentscope","slug":"gateway-failed-to-remove-mcp-self-name-r-safe","errorCode":null,"errorMessage":"gateway failed to remove MCP {self.name!r}: {_safe_detail(status, resp_body)}","messagePattern":"gateway failed to remove MCP (.+?): (.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"warning","filePath":"src/agentscope/workspace/_gateway_client.py","lineNumber":296,"sourceCode":"        \"\"\"\n        if not self._is_connected:\n            if ignore_errors:\n                return\n            raise RuntimeError(\n                f\"MCP {self.name!r} is not connected. Call connect() first.\",\n            )\n        assert self._gateway is not None\n        try:\n            status, resp_body = await self._gateway.exec_request(\n                \"DELETE\",\n                f\"/mcps/{self.name}\",\n                params={\n                    \"agent_id\": self._agent_id,\n                    \"session_id\": self._session_id,\n                },\n            )\n            if status >= 400 and not ignore_errors:\n                raise RuntimeError(\n                    f\"gateway failed to remove MCP {self.name!r}: \"\n                    f\"{_safe_detail(status, resp_body)}\",\n                )\n        except Exception:\n            if not ignore_errors:\n                raise\n        self._is_connected = False\n\n    # ── tool discovery ────────────────────────────────────────────\n\n    async def list_raw_tools(self) -> list[mcp.types.Tool]:\n        \"\"\"Fetch upstream tools via ``GET /mcps/{name}/tools``.\n\n        Returns raw :class:`mcp.types.Tool` descriptors (upstream names,\n        no ``mcp__`` prefix) so the inherited :meth:`get_tool` can\n        re-wrap them like a local :class:`MCPClient`. The unfiltered\n        list is cached; the returned list has ``enable_tools`` /\n        ``disable_tools`` applied.","sourceCodeStart":278,"sourceCodeEnd":314,"githubUrl":"https://github.com/agentscope-ai/agentscope/blob/e90f1c7592896cc95f6e5ee506194f533378247d/src/agentscope/workspace/_gateway_client.py#L278-L314","documentation":"Raised by GatewayMCPClient.close() when the gateway HTTP DELETE /mcps/{name} request returns a 4xx/5xx status and ignore_errors=False. The gateway process inside the sandbox failed to deregister the MCP server (e.g. already removed, unknown agent/session id, or gateway internal error). _safe_detail embeds the HTTP status and a truncated response body so the upstream reason is visible.","triggerScenarios":"Calling `await client.close(ignore_errors=False)` on a connected GatewayMCPClient after the gateway has already dropped the MCP (restart, expiry), or with an agent_id/session_id that no longer matches a registered MCP. Any DELETE /mcps/{name} returning status >= 400.","commonSituations":"Gateway restarted or crashed between connect() and close(); session ids recycled across runs; calling close() twice with different id scopes; passing ignore_errors=False in cleanup paths where the gateway state is already stale.","solutions":["Use the default `await client.close()` (ignore_errors=True) in shutdown/cleanup paths — it suppresses 4xx/5xx by design","Check gateway health (`await gateway.health()`) before closing if you must pass ignore_errors=False","Re-list MCPs (`await gateway.list_mcps(agent_id, session_id)`) and only close clients that still appear","Inspect the embedded status/body detail in the message to see the gateway's actual complaint (404 vs 500) and fix the agent_id/session_id accordingly"],"exampleFix":"// before\nawait client.close(ignore_errors=False)\n// after\nawait client.close()  # ignore_errors=True by default; safe for cleanup","handlingStrategy":"try-catch","validationCode":"alive = await gateway.list_mcps(agent_id, session_id)\nregistered = any(c.name == client.name for c in alive)","typeGuard":null,"tryCatchPattern":"try:\n    await client.close(ignore_errors=False)\nexcept RuntimeError as e:\n    logger.warning(\"MCP deregistration failed (continuing): %s\", e)","preventionTips":["Default to close() with ignore_errors=True in all cleanup paths","Treat close as best-effort: the gateway also reaps MCPs when sessions end","Health-check the gateway before strict closes"],"tags":["mcp","gateway","cleanup","http-4xx"],"backgroundTag":"mcp-gateway-request-failed","analyzedSha":"e90f1c7592896cc95f6e5ee506194f533378247d","analyzedAt":"2026-08-28T18:24:12.087Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}