BerriAI/litellm · warning · HTTPException

MCP server for tool '{original_tool_name}' is not available;

Error message

MCP server for tool '{original_tool_name}' is not available; refusing to dispatch without authorization checks. Retry once the server is registered.

What it means

The tool-ceiling part of the pre-call check needs an allowed-server object matching the resolved server_name. An unprefixed tool name can pass the earlier server-level check without pinning any server; if none of the caller's allowed servers then matches server_name, LiteLLM fails closed with HTTP 503 rather than dispatching with no server to evaluate the tool limit against. The source comment marks this as reachable only when the prefix was empty.

Source

Thrown at litellm/proxy/_experimental/mcp_server/server.py:2947

                # that the server-level check above compared against the
                # caller's `allowed_mcp_servers` by exact `name`. So the named
                # server is in that list and can carry the tool-level checks,
                # even with the mapping cold. Resolve it from
                # `allowed_mcp_servers` rather than the registry: the registry
                # would happily return a server the caller holds no grant for,
                # and matching anything other than `name` would accept a server
                # the check never validated.
                prefix_server: Final = next(
                    (candidate for candidate in allowed_mcp_servers if candidate.name == server_name),
                    None,
                )
                if prefix_server is None:
                    # A non-empty prefix that passed the server-level check
                    # always matches here, so this arm only fires when the
                    # prefix was empty, which is exactly the case that check
                    # skips. Fail closed rather than dispatch with no server to
                    # evaluate a tool ceiling against.
                    raise HTTPException(
                        status_code=503,
                        detail=(
                            f"MCP server for tool '{original_tool_name}' is not available; "
                            "refusing to dispatch without authorization checks. "
                            "Retry once the server is registered."
                        ),
                    )

                from litellm.proxy.proxy_server import proxy_logging_obj

                hook_result = await global_mcp_server_manager.pre_call_tool_check(
                    name=original_tool_name,
                    arguments=arguments,
                    server_name=server_name,
                    user_api_key_auth=user_api_key_auth,
                    proxy_logging_obj=proxy_logging_obj,
                    server=prefix_server,
                    raw_headers=raw_headers,

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Retry after registration and allowlist state settle.
  2. Call the tool with its server-prefixed name so the server is pinned explicitly.
  3. Ensure the caller's grants (key/team mcp_servers) include the server that owns the tool.
Defensive patterns

Strategy: retry

Validate before calling

async def allowed_server_matches(client: httpx.AsyncClient, server_name: str) -> bool:
    tools = (await client.get(f"{base}/mcp-rest/tools/list")).json().get("tools", [])
    return any(t.get("name", "").startswith(f"{server_name}__") for t in tools)

call_prefixed = f"{server_name}__{bare_tool_name}"  # pins the server, avoids the empty-prefix arm

Try / catch

async def call_with_backoff(call, payload, attempts: int = 5):
    for i in range(attempts):
        try:
            return await call(payload)
        except httpx.HTTPStatusError as e:
            if e.response.status_code == 503 and "refusing to dispatch" in e.response.text:
                await asyncio.sleep(min(2 ** i, 10))  # allowlist/registry race; settles shortly
                continue
            raise
    raise

Prevention

When it happens

Trigger: An unprefixed tool name during the window where the owning server is registered globally but not yet present in the caller's allowed-server list; races between allowlist computation and server registration at startup.

Common situations: Unprefixed calls made right after a server is added or a proxy restarts; the same startup/reload races that produce the sibling 503 on the local-registry path.

Related errors


AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18). Data as JSON: /api/errors/6c5ee14e06d29b5d. Report an issue: GitHub.