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
- Set client_id (and client_secret) on the MCP server definition in the proxy, then retry the authorize call.
- Or pass client_id explicitly in the authorize request.
- 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
- Register OAuth MCP servers with their client_id/client_secret from day one.
- Confirm the provider supports dynamic client registration before relying on DCR.
- Pass client_id in the authorize request when the provider has no DCR.
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
- User does not have permission to create temporary mcp server
- Error caching temporary mcp server: {e}
- MCP server {server_id} not found
- Access denied to MCP server {server_id}
- xAI OAuth token response missing refresh_token
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/f5b434a25fdddb5c.
Report an issue: GitHub.