BerriAI/litellm · error · HTTPException

User does not have permission to test MCP server tools. Only

Error message

User does not have permission to test MCP server tools. Only PROXY_ADMIN users can perform this action.

What it means

POST /mcp-rest/test/tools/list previews the tools an MCP server would expose before registering it (including generating tools from an OpenAPI spec when spec_path is set). Like /test/connection, it is restricted to PROXY_ADMIN callers because it reaches arbitrary hosts; anyone else gets HTTP 403 with this message.

Source

Thrown at litellm/proxy/_experimental/mcp_server/rest_endpoints.py:1356

            return {"status": "ok"}

        return await _execute_with_mcp_client(
            new_mcp_server_request,
            _test_connection_operation,
            raw_headers=_safe_get_request_headers(request),
        )

    @router.post("/test/tools/list", dependencies=[Depends(user_api_key_auth)])
    async def test_tools_list(
        request: Request,
        new_mcp_server_request: NewMCPServerRequest,
        user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth),
    ):
        """
        Preview tools available from MCP server before adding it
        """
        if LitellmUserRoles.PROXY_ADMIN != user_api_key_dict.user_role:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail={
                    "error": "User does not have permission to test MCP server tools. Only PROXY_ADMIN users can perform this action."
                },
            )

        new_mcp_server_request = _inherit_credentials_from_existing_server(new_mcp_server_request)

        # For OpenAPI spec servers, generate tools from the spec directly
        if new_mcp_server_request.spec_path:
            return await _preview_openapi_tools(new_mcp_server_request.spec_path)

        from litellm.proxy._experimental.mcp_server.auth.user_api_key_auth_mcp import (
            MCPRequestHandler,
        )

        headers: Final = request.headers

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Use a key whose user has the PROXY_ADMIN role for this preview endpoint.
  2. Grant the role to the intended user in the admin UI, then retry.
  3. For non-admin users, register the server via the admin flow and preview tools with GET /mcp-rest/tools/list instead.
Defensive patterns

Strategy: validation

Validate before calling

async def can_preview_tools(client: httpx.AsyncClient) -> bool:
    info = (await client.get(f"{base}/key/info")).json()
    return info.get("key_info", {}).get("user_role") == "proxy_admin"

Type guard

def is_proxy_admin_key(key_info: dict) -> bool:
    return key_info.get("user_role") == "proxy_admin"

Try / catch

except httpx.HTTPStatusError as e:
    if e.response.status_code == 403 and "PROXY_ADMIN" in e.response.text:
        raise PermissionError("test/tools/list requires a PROXY_ADMIN key") from e
    raise

Prevention

When it happens

Trigger: Calling POST /mcp-rest/test/tools/list with a virtual key whose user role is not PROXY_ADMIN; automated onboarding pipelines using team-level keys.

Common situations: Same as the connection test: non-admin automation trying to validate MCP server configs; scripts written against admin credentials later run with restricted keys.

Related errors


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