{"record":{"id":"a607c17255284226","repo":"PrefectHQ/fastmcp","slug":"name-is-a-synthetic-search-tool-and-cannot-be","errorCode":null,"errorMessage":"'{name}' is a synthetic search tool and cannot be called via the call_tool proxy","messagePattern":"'(.+?)' is a synthetic search tool and cannot be called via the call_tool proxy","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/server/transforms/search/base.py","lineNumber":241,"sourceCode":"        ...\n\n    def _make_call_tool(self) -> Tool:\n        \"\"\"Create the call_tool proxy that executes discovered tools.\"\"\"\n        transform = self\n\n        async def call_tool(\n            name: Annotated[str, \"The name of the tool to call\"],\n            arguments: Annotated[\n                dict[str, Any] | None, \"Arguments to pass to the tool\"\n            ] = None,\n            ctx: Context = None,  # type: ignore[assignment]  # ty:ignore[invalid-parameter-default]\n        ) -> ToolResult:\n            \"\"\"Call a tool by name with the given arguments.\n\n            Use this to execute tools discovered via search_tools.\n            \"\"\"\n            if name in {transform._call_tool_name, transform._search_tool_name}:\n                raise ValueError(\n                    f\"'{name}' is a synthetic search tool and cannot be called via the call_tool proxy\"\n                )\n            # The name comes from the model, so this proxy is a second way\n            # into the server that no host mediates. It may reach only what\n            # the model was allowed to discover.\n            if not any(\n                tool.name == name for tool in await transform.get_tool_catalog(ctx)\n            ):\n                raise NotFoundError(f\"Unknown tool: {name!r}\")\n            return await ctx.fastmcp.call_tool(name, arguments)\n\n        return Tool.from_function(fn=call_tool, name=self._call_tool_name)\n\n    # ------------------------------------------------------------------\n    # Serialization\n    # ------------------------------------------------------------------\n\n    async def _render_results(self, tools: Sequence[Tool]) -> Any:","sourceCodeStart":223,"sourceCodeEnd":259,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/server/transforms/search/base.py#L223-L259","documentation":"The search_tools transform exposes a call_tool proxy tool for invoking discovered tools, but the synthetic tools it generates (the search tool itself and the proxy) are excluded from that proxy to prevent self-invocation loops. Calling them through the proxy raises ValueError.","triggerScenarios":"Invoking the proxy call_tool with name equal to the search tool's name or the proxy tool's own name (transform._call_tool_name / transform._search_tool_name).","commonSituations":"An LLM passing the search tool's name back into the proxy; programmatic code iterating the tool catalog and blindly calling every name through the proxy.","solutions":["Call the search tool directly, not through the proxy","Only pass names of regular tools discovered via search_tools to the proxy","Filter synthetic names out of any automated dispatch list"],"exampleFix":"// before\nawait call_tool(search_tool_name, args)  # rejected\n// after\nresults = await search_tools(query)  # invoke the search tool itself","handlingStrategy":"validation","validationCode":"synthetic = {transform._call_tool_name, transform._search_tool_name}\nif name in synthetic:\n    raise ValueError(f\"{name!r} must not go through the proxy\")","typeGuard":null,"tryCatchPattern":"try:\n    await call_tool(name, args)\nexcept ValueError as e:\n    logger.warning(\"proxy rejected name: %s\", e)","preventionTips":["Exclude synthetic tool names from automated dispatch","Have LLM callers invoke the search tool directly","Validate names against the real tool catalog before proxy calls"],"tags":["python","search","tools","proxy"],"backgroundTag":"synthetic-tool-proxy-call","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}