BerriAI/litellm · error · HTTPException

missing_client_id

missing_client_id

Error message

No client_id available for this MCP server. Either configure the server with a client_id or supply one in the request.

What it means

Returned (400, error code missing_client_id) by the MCP OAuth authorize endpoint when no client_id can be determined: the server definition has none stored, the request supplied none, and the ephemeral dynamic client registration (DCR) attempt either did not run or returned no client_id. The code resolves stored_or_supplied_client_id first, then the DCR client, and only errors when both are empty.

Source

Thrown at litellm/proxy/management_endpoints/mcp_management_endpoints.py:1856

        _raise_if_not_oauth2(mcp_server)
        # Use the server's stored client_id when the caller doesn't supply one
        stored_or_supplied_client_id: Final = mcp_server.client_id or client_id or ""
        ephemeral_dcr_client: Final = (
            await resolve_ephemeral_dcr_client(
                request=request,
                mcp_server=mcp_server,
                code_challenge=code_challenge,
                code_challenge_method=code_challenge_method,
                redirect_uri=redirect_uri,
            )
            if not stored_or_supplied_client_id
            else None
        )
        resolved_client_id: Final = stored_or_supplied_client_id or (
            ephemeral_dcr_client.client_id if ephemeral_dcr_client else ""
        )
        if not resolved_client_id:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail={
                    "error": "missing_client_id",
                    "message": (
                        "No client_id available for this MCP server. "
                        "Either configure the server with a client_id or supply one in the request."
                    ),
                },
            )
        return await authorize_with_server(
            request=request,
            mcp_server=mcp_server,
            client_id=resolved_client_id,
            redirect_uri=redirect_uri,
            state=state,
            code_challenge=code_challenge,
            code_challenge_method=code_challenge_method,
            response_type=response_type,

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Set client_id (and client_secret) on the MCP server definition in the proxy, then retry the authorize call.
  2. Or pass client_id explicitly in the authorize request.
  3. If you expect DCR to work, verify the upstream MCP provider actually supports dynamic client registration and check proxy logs for the DCR attempt failing.

Example fix

# before: server registered without OAuth app credentials
payload = {"server_id": "gh", "server_name": "gh", "transport": "http", "url": "https://mcp.github.com/mcp", "auth_type": "oauth"}

# after: include the OAuth client credentials on the server definition
payload = {
    "server_id": "gh", "server_name": "gh", "transport": "http",
    "url": "https://mcp.github.com/mcp", "auth_type": "oauth",
    "oauth2_params": {"client_id": os.environ["GH_CLIENT_ID"], "client_secret": os.environ["GH_CLIENT_SECRET"]},
}
Defensive patterns

Strategy: validation

Validate before calling

server = requests.get(f"{PROXY}/v1/mcp/server/{server_id}", headers=AUTH).json()
has_client_id = bool((server.get("mcp_server", server) or {}).get("client_id"))
if not has_client_id and not request_client_id:
    raise ValueError("configure client_id on the server or pass it in the authorize request")

Type guard

def oauth_ready(server: dict, supplied_client_id: str | None) -> bool:
    return bool(supplied_client_id or server.get("client_id"))

Try / catch

try:
    authorize(server_id)
except HTTPError as e:
    if e.response.status_code == 400 and e.response.json().get("error", {}).get("message", "").find("client_id") >= 0:
        raise ValueError("set oauth client_id/client_secret on the MCP server definition")
    raise

Prevention

When it happens

Trigger: GET/POST /server/oauth/{server_id}/authorize for an OAuth server created without client_id/client_secret while the request also omits client_id; upstream MCP provider does not support (or fails) dynamic client registration; DCR succeeded but returned an empty client_id.

Common situations: Copying an OAuth server template but leaving the credentials out; provider (e.g. internal SSO) has no DCR endpoint; migrating config between environments and dropping the auth fields.

Related errors


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