PrefectHQ/fastmcp · error · KeyError

Unknown tool: {name!r}. If servers changed their tools, call

Error message

Unknown tool: {name!r}. If servers changed their tools, call list_tools() to refresh the catalog.

What it means

ClientGroup.resolve_tool raises this KeyError when the tool catalog has already been loaded (self._catalog_loaded is True) but the requested public name is not in the cached routes. The group intentionally does not re-query servers on every call: only an explicit list_tools() refreshes the catalog, so a name that was not present at last discovery is rejected immediately. The message tells you the remedy — call list_tools() to refresh.

Source

Thrown at fastmcp_slim/fastmcp/client/group.py:202

        self._tool_routes = routes
        self._catalog_loaded = True
        return tools

    async def resolve_tool(self, name: str) -> ToolRoute:
        """Resolve a public tool name to its client and upstream identity.

        A known route only requires its own client to be connected; one dead
        server does not couple failures onto calls routed to healthy servers.
        Loading the catalog (the first resolution, or after a refresh) still
        requires every client, since discovery queries them all.
        """
        route = self._tool_routes.get(name)
        if route is not None:
            self._require_route_connected(route)
            return route
        if self._catalog_loaded:
            raise KeyError(
                f"Unknown tool: {name!r}. If servers changed their tools,"
                " call list_tools() to refresh the catalog."
            )

        async with self._route_lock:
            route = self._tool_routes.get(name)
            if route is not None:
                return route
            if not self._catalog_loaded:
                # Lazy cold-start discovery may serve a cached listing; only an
                # explicit list_tools() call promises a refreshed catalog.
                await self.list_tools(cache_mode="use")
                route = self._tool_routes.get(name)

        if route is None:
            raise KeyError(
                f"Unknown tool: {name!r}. If servers changed their tools,"
                " call list_tools() to refresh the catalog."

View on GitHub (pinned to 1f02114297)

Solutions

  1. Call `await group.list_tools()` to refresh the catalog from all servers, then retry the call.
  2. Use the namespaced public name: prefix the tool with its server name as shown by list_tools() (e.g. `weather_get_forecast`).
  3. Catch KeyError, call list_tools() once, and retry the resolution to tolerate servers that added tools mid-session.
  4. Verify the exact names with `tools = await group.list_tools(); print([t.name for t in tools])` before hardcoding calls.

Example fix

# before
result = await group.call_tool("get_forecast", {"city": "SF"})  # KeyError: Unknown tool

# after
tools = await group.list_tools()  # refresh + get namespaced names
result = await group.call_tool("weather_get_forecast", {"city": "SF"})
Defensive patterns

Strategy: try-catch

Validate before calling

available = {t.name for t in await group.list_tools()}
if name not in available:
    raise LookupError(f"{name!r} not offered by group; available: {sorted(available)}")

Try / catch

try:
    result = await group.call_tool(name, args)
except KeyError as e:
    await group.list_tools()  # refresh catalog
    result = await group.call_tool(name, args)  # retry once; may still KeyError if truly absent

Prevention

When it happens

Trigger: Calling group.call_tool(name) / call_tool_mcp(name) with a name that (a) was never listed — e.g. a typo, or forgetting the required `{server_name}_` namespace prefix — or (b) the upstream server started advertising after your last list_tools() call, so the stale catalog does not contain it.

Common situations: Calling the upstream tool name (e.g. `get_forecast`) instead of the namespaced one (`weather_get_forecast`); a server deployed new tools after the group connected; agent code caching tool lists across group restarts; tests calling tools before any list_tools() refresh following a server change.

Related errors


AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29). Data as JSON: /api/errors/742798d02461e435. Report an issue: GitHub.