{"record":{"id":"e51ca93fef4c3f4d","repo":"unclecode/crawl4ai","slug":"tool-not-found","errorCode":null,"errorMessage":"tool not found","messagePattern":"tool not found","errorType":"http","errorClass":"HTTPException","httpStatus":404,"severity":"error","filePath":"deploy/docker/mcp_bridge.py","lineNumber":149,"sourceCode":"        return None\n\n    # MCP handlers\n    @mcp.list_tools()\n    async def _list_tools() -> List[t.Tool]:\n        out = []\n        for k, (proxy, orig_fn) in tools.items():\n            desc   = getattr(orig_fn, \"__mcp_description__\", None) or inspect.getdoc(orig_fn) or \"\"\n            schema = getattr(orig_fn, \"__mcp_schema__\", None) or _schema(_body_model(orig_fn))\n            out.append(\n                t.Tool(name=k, description=desc, inputSchema=schema)\n            )\n        return out\n             \n\n    @mcp.call_tool()\n    async def _call_tool(name: str, arguments: Dict | None) -> List[t.TextContent]:\n        if name not in tools:\n            raise HTTPException(404, \"tool not found\")\n        \n        proxy, _ = tools[name]\n        try:\n            res = await proxy(**(arguments or {}))\n        except HTTPException as exc:\n            # map server‑side errors into MCP \"text/error\" payloads\n            err = {\"error\": exc.status_code, \"detail\": exc.detail}\n            return [t.TextContent(type = \"text\", text=json.dumps(err, ensure_ascii=False))]\n        return [t.TextContent(type = \"text\", text=json.dumps(res, default=str, ensure_ascii=False))]\n\n    @mcp.list_resources()\n    async def _list_resources() -> List[t.Resource]:\n        return [\n            t.Resource(name=k, description=inspect.getdoc(f) or \"\", mime_type=\"application/json\")\n            for k, f in resources.items()\n        ]\n\n    @mcp.read_resource()","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/unclecode/crawl4ai/blob/7e801521428ee12509994d39151006f64055ebe3/deploy/docker/mcp_bridge.py#L131-L167","documentation":"The MCP bridge's call_tool handler raises HTTPException(404, 'tool not found') when the requested tool name is not in the tools registry built at attach_mcp time. The registry is fixed when the bridge is attached, so names are exactly those advertised by tools/list.","triggerScenarios":"Calling tools/call with a name that has a typo, different casing, or refers to a route/tool registered after attach_mcp ran; using a stale tool list from an earlier process.","commonSituations":"Client caches the tool list across a server restart where routes changed; renamed endpoints; assuming case-insensitive matching.","solutions":["Call tools/list first and use an exact name from the response.","Refresh the client's tool cache after the server restarts or routes change.","Ensure custom tools/routes are registered on the FastAPI app before attach_mcp() is called."],"exampleFix":"# before\ntools/call {\"name\": \"Crawl\", \"arguments\": {...}}\n\n# after\ntools/list  ->  [\"crawl\", ...]\ntools/call {\"name\": \"crawl\", \"arguments\": {...}}","handlingStrategy":"validation","validationCode":"names = [t.name for t in (await session.list_tools()).tools]\nif tool_name not in names:\n    raise ValueError(f\"tool {tool_name!r} not in {names}\")","typeGuard":"def is_known_tool(name, advertised) -> bool:\n    return isinstance(name, str) and name in advertised","tryCatchPattern":"result = await session.call_tool(name, args)\nif is_error_payload(result):\n    err = json.loads(result.content[0].text)\n    if err.get(\"error\") == 404 and \"tool not found\" in err.get(\"detail\", \"\"):\n        advertised = await session.list_tools()\n        raise ToolNameError(f\"{name!r} not in {[t.name for t in advertised.tools]}\")","preventionTips":["Always tools/list before tools/call in new integrations.","Invalidate the client tool cache on server reconnect.","Register all tools before attach_mcp() in the server startup order."],"tags":["mcp","http-404","tool-routing","api"],"backgroundTag":null,"analyzedSha":"7e801521428ee12509994d39151006f64055ebe3","analyzedAt":"2026-08-14T20:46:20.673Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}