PrefectHQ/fastmcp · error · NotFoundError

Unknown tool: {tool_name}

Error message

Unknown tool: {tool_name}

What it means

Inside the CodeMode sandbox, call_tool() resolves the requested tool against the backend catalog via _find_tool(). If no tool matches the given name, NotFoundError('Unknown tool: <name>') is raised, and the sandboxed code sees this as a failed tool call.

Source

Thrown at fastmcp_slim/fastmcp/experimental/transforms/code_mode.py:621

        ) -> Any:
            """Execute tool calls using Python code."""

            call_count = 0

            async def call_tool(tool_name: str, params: dict[str, Any]) -> Any:
                nonlocal call_count
                if max_tool_calls is not None:
                    call_count += 1
                    if call_count > max_tool_calls:
                        raise ToolError(
                            f"Tool call limit exceeded: at most {max_tool_calls} "
                            "call_tool() invocations are allowed per execute()."
                        )

                backend_tools = await transform.get_tool_catalog(ctx)
                tool = transform._find_tool(tool_name, backend_tools)
                if tool is None:
                    raise NotFoundError(f"Unknown tool: {tool_name}")

                result = await ctx.fastmcp.call_tool(tool.name, params)
                return _unwrap_tool_result(result)

            return await transform.sandbox_provider.run(
                code,
                external_functions={"call_tool": call_tool},
            )

        return Tool.from_function(
            fn=execute,
            name=self.execute_tool_name,
            description=self._build_execute_description(),
        )


__all__ = [
    "CodeMode",

View on GitHub (pinned to 1f02114297)

Solutions

  1. Fix the tool name in the generated code to match one in the catalog exactly
  2. Have sandboxed code call the discovery/catalog tool first to list valid names before invoking
  3. Verify the tool exists on the underlying FastMCP server and isn't filtered out by the transform's tool set
  4. Catch NotFoundError inside generated code and fall back to listing tools

Example fix

// before
result = await call_tool("get_wether", {"city": "Paris"})

// after
catalog = await get_tool_catalog()
result = await call_tool("get_weather", {"city": "Paris"})
Defensive patterns

Strategy: try-catch

Validate before calling

catalog = await transform.get_tool_catalog(ctx)
available = {t.name for t in catalog}
assert "get_weather" in available, f"Tool missing; available: {sorted(available)}"

Type guard

def tool_exists(catalog_names: set[str], tool_name: str) -> bool:
    return tool_name in catalog_names

Try / catch

try:
    result = await call_tool("get_weather", params)
except NotFoundError:
    catalog = await get_tool_catalog()
    raise RuntimeError(f"Unknown tool 'get_weather'; valid: {[t.name for t in catalog]}")

Prevention

When it happens

Trigger: Generated code calls call_tool() with a name not present in the transform's tool catalog — a hallucinated/mistyped tool name, a name only available after prefixing/renaming by the transform, or a tool removed from the underlying server between catalog fetches.

Common situations: LLM-written code guessing tool names instead of using the discovery tool's catalog; stale catalogs after server tool changes; name mismatches because discovery lists transformed names while code uses original server names.

Related errors


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