agentscope-ai/agentscope · error · ValueError

Tool {name!r} not found in MCP {self.name!r}.

Error message

Tool {name!r} not found in MCP {self.name!r}.

What it means

Raised by GatewayMCPClient.get_tool(name) when no upstream tool with that exact name exists in the cached tool list (after a list_raw_tools() refresh on cache miss). This is a plain lookup miss: the name doesn't match any raw.name from the MCP server's advertised tools. Note enable_tools/disable_tools filtering does NOT hide tools from get_tool — it searches the unfiltered cache — so a mismatch means the upstream server genuinely doesn't expose that name.

Source

Thrown at src/agentscope/workspace/_gateway_client.py:369

        name: str,
    ) -> GatewayMCPTool:
        """Look up a single tool by upstream name and wrap it.

        Falls back to :meth:`list_raw_tools` on cache miss, then
        searches the unfiltered cache so tools that ``enable_tools`` /
        ``disable_tools`` would have hidden are still resolvable —
        matching :meth:`MCPClient.get_tool`.

        Raises:
            `ValueError`:
                No tool with that upstream name exists on the gateway.
        """
        if self._cached_tools is None:
            await self.list_raw_tools()
        for raw in self._cached_tools or []:
            if raw.name == name:
                return self._wrap_tool(raw)
        raise ValueError(
            f"Tool {name!r} not found in MCP {self.name!r}.",
        )

    # ── helpers ───────────────────────────────────────────────────

    def _wrap_tool(self, tool: mcp.types.Tool) -> GatewayMCPTool:
        """Build a :class:`GatewayMCPTool` bound to this client's
        gateway facade.
        """
        assert self._gateway is not None
        return GatewayMCPTool(
            mcp_name=self.name,
            tool=tool,
            gateway=self._gateway,
            agent_id=self._agent_id,
            session_id=self._session_id,
        )

View on GitHub (pinned to e90f1c7592)

Solutions

  1. Print `await client.list_raw_tools()` (or `[t.name for t in ...]`) and use the exact upstream name shown
  2. Drop any `mcp__<name>__` prefix — get_tool expects the bare upstream tool name
  3. Catch ValueError and skip/fallback when the tool is optional
  4. Pin or verify the upstream MCP server version if tools were renamed

Example fix

// before
tool = await client.get_tool("mcp__fetch__fetch")
// after
tool = await client.get_tool("fetch")  # bare upstream name
Defensive patterns

Strategy: validation

Validate before calling

tools = await client.list_raw_tools()
names = {t.name for t in tools}
if name not in names:
    raise KeyError(f"available: {sorted(names)}")
tool = await client.get_tool(name)

Type guard

def tool_exists(client: GatewayMCPClient, name: str) -> bool:
    return any(t.name == name for t in client._cached_tools or [])

Try / catch

try:
    tool = await client.get_tool(name)
except ValueError:
    tool = None  # optional tool, skip

Prevention

When it happens

Trigger: `await client.get_tool("fetch")` when the MCP server exposes e.g. "web_fetch" or an mcp__-prefixed name; calling get_tool before connect/list succeeded but the MCP exposes zero tools; typos or renamed tools after an upstream MCP server version change.

Common situations: Using the mcp__servername__tool prefixed name instead of the upstream bare name; upstream MCP server upgraded and renamed tools; typo in the tool name; assuming a tool exists without checking list_raw_tools() output.

Related errors


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