{"record":{"id":"f52bfb9d8bfe5f36","repo":"BerriAI/litellm","slug":"mcp-server-for-tool-name-is-not-available-ref","errorCode":null,"errorMessage":"MCP server for tool '{name}' is not available; refusing to dispatch without authorization checks. Retry once the server is registered.","messagePattern":"MCP server for tool '(.+?)' is not available; refusing to dispatch without authorization checks\\. Retry once the server is registered\\.","errorType":"http","errorClass":"HTTPException","httpStatus":503,"severity":"warning","filePath":"litellm/proxy/_experimental/mcp_server/server.py","lineNumber":2802,"sourceCode":"                # External auth header supplied; still enforce user-identity check.\n                await _check_byok_credential(mcp_server, user_api_key_auth)\n\n        # Check if tool exists in local registry first (for OpenAPI-based tools)\n        # These tools are registered with their prefixed names\n        #########################################################\n        local_tool: Final = global_mcp_tool_registry.get_tool(name)\n        if local_tool:\n            # OpenAPI-backed tools used to bypass `pre_call_tool_check` —\n            # only the managed path ran allowed/banned-tool checks, key/team\n            # tool permissions, and parameter validation. Run the same checks\n            # before dispatching to the local registry. Refuse the call if\n            # we cannot resolve a server: tools registered via\n            # openapi_to_mcp_generator are always tied to a server, so a\n            # missing mcp_server here means the tool->server mapping has\n            # not finished initializing or the registry entry is orphaned.\n            # Skipping the check would re-open the same authorization gap.\n            if mcp_server is None:\n                raise HTTPException(\n                    status_code=503,\n                    detail=(\n                        f\"MCP server for tool '{name}' is not available; \"\n                        \"refusing to dispatch without authorization checks. \"\n                        \"Retry once the server is registered.\"\n                    ),\n                )\n\n            # `pre_call_tool_check` calls into `proxy_logging_obj` for the\n            # pre-call guardrail hooks, so source it from the canonical\n            # `proxy_server` module the same way `_handle_managed_mcp_tool`\n            # does. `kwargs.get(\"proxy_logging_obj\")` is None on the MCP\n            # entry path and would crash with AttributeError after the\n            # security checks pass.\n            from litellm.proxy.proxy_server import proxy_logging_obj\n\n            hook_result = await global_mcp_server_manager.pre_call_tool_check(\n                name=original_tool_name,","sourceCodeStart":2784,"sourceCodeEnd":2820,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/_experimental/mcp_server/server.py#L2784-L2820","documentation":"Tools generated from OpenAPI specs live in a local registry but must pass the same pre_call_tool_check as managed tools (allowed/banned-tool lists, key/team tool permissions, parameter validation). Those checks need the owning server; if the tool is in the registry but its server cannot be resolved, LiteLLM refuses dispatch with HTTP 503 instead of skipping authorization. The source comment notes this keeps an earlier auth-bypass gap closed: a missing mapping means initialization has not finished or the entry is orphaned.","triggerScenarios":"A tool call racing server registration during proxy startup or config reload; an orphaned registry entry left behind after its server was removed from the registry.","commonSituations":"Clients reconnecting immediately after a proxy restart; hot-reloading MCP config while traffic flows; a partially failed server registration.","solutions":["Retry the call once the server registration completes — the message explicitly says this.","If it persists, restart the proxy or re-add the MCP server so the tool-to-server mapping rebuilds.","If the server was intentionally deleted, remove the orphaned tool entry so clients stop discovering it."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"async def tool_server_ready(client: httpx.AsyncClient, tool_name: str) -> bool:\n    tools = (await client.get(f\"{base}/mcp-rest/tools/list\")).json().get(\"tools\", [])\n    return any(t.get(\"name\") == tool_name for t in tools)","typeGuard":null,"tryCatchPattern":"async def call_with_backoff(call, payload, attempts: int = 5):\n    for i in range(attempts):\n        try:\n            return await call(payload)\n        except httpx.HTTPStatusError as e:\n            if e.response.status_code == 503 and \"refusing to dispatch\" in e.response.text:\n                await asyncio.sleep(min(2 ** i, 10))  # registration race; settles shortly\n                continue\n            raise\n    raise","preventionTips":["Gate client traffic on a post-startup readiness check after proxy restarts or MCP config reloads.","Do not call OpenAPI-generated tools until the owning server's registration completes — check the tool listing first.","Clean up orphaned tools when deleting a server so clients stop discovering dead entries."],"tags":["mcp","openapi","authorization","http-503","race-condition"],"backgroundTag":"mcp-server-not-registered","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-24T22:17:12.610Z"}