BerriAI/litellm · error · HTTPException

User not allowed to call this tool.

Error message

User not allowed to call this tool.

What it means

Server-level authorization on the MCP tool-call path: after resolving which server owns the tool, LiteLLM checks that server's name against the caller's allowed MCP servers (derived from key/team/org mcp_servers grants). If the server is not in the allowed list, the call fails with HTTP 403 "User not allowed to call this tool." — enforced only when a server could be resolved.

Source

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

                            "message": (
                                f"Tool '{name}' belongs to MCP server "
                                f"'{mcp_server.name}' but request specified "
                                f"server_id for '{requested_server.name}'."
                            ),
                        },
                    )
                if mcp_server is None:
                    mcp_server = requested_server
                    server_name = requested_server.name
                    original_tool_name = strip_known_server_prefix(name, requested_server)

        # Only enforce server-level permissions when we can resolve a server
        if server_name:
            if not MCPRequestHandler.is_tool_allowed(
                allowed_mcp_servers=[server.name for server in allowed_mcp_servers],
                server_name=server_name,
            ):
                raise HTTPException(
                    status_code=403,
                    detail="User not allowed to call this tool.",
                )

        standard_logging_mcp_tool_call: Final[StandardLoggingMCPToolCall] = _get_standard_logging_mcp_tool_call(
            name=original_tool_name,  # Use original name for logging
            arguments=arguments,
            server_name=server_name,
            session_id=_mcp_session_id_from_headers(raw_headers),
        )
        litellm_logging_obj: Final[LiteLLMLoggingObj | None] = kwargs.get("litellm_logging_obj", None)
        if litellm_logging_obj:
            litellm_logging_obj.model_call_details["mcp_tool_call_metadata"] = standard_logging_mcp_tool_call
            litellm_logging_obj.model = f"MCP: {name}"
            litellm_logging_obj.model_call_details["model"] = f"MCP: {name}"
        # Resolve the MCP server early so BYOK checks and credential injection
        # apply to ALL dispatch paths (local tool registry AND managed MCP server).
        if mcp_server is None:

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Use a key whose grants include the server that owns the tool.
  2. Admin: add the server (or a wildcard) to the key's or team's mcp_servers scope in the admin UI.
  3. Verify visibility first: GET /mcp-rest/tools/list with the same key shows exactly which servers/tools are permitted.
Defensive patterns

Strategy: validation

Validate before calling

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

if not await tool_visible_to_key(client, name):
    raise PermissionError(f"key cannot access tool {name}; request grant first")

Try / catch

except httpx.HTTPStatusError as e:
    if e.response.status_code == 403 and "not allowed to call this tool" in e.response.text:
        # scope problem, not transient: request access or switch key; do not retry
        raise ToolNotPermitted(name) from e
    raise

Prevention

When it happens

Trigger: A key scoped to specific mcp_servers calls a tool from an ungranted server; an unprefixed tool name resolves to a server outside the caller's grants.

Common situations: An admin narrows key or team scopes after an incident; a new MCP server is registered but never added to the team's grants; users moved between teams keep calling old tools.

Related errors


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