BerriAI/litellm · error · HTTPException
MCPJWTSigner: incoming token is missing required claims: {mi
Error message
MCPJWTSigner: incoming token is missing required claims: {missing}. Configure the IdP to include these claims. What it means
After successfully verifying an incoming token, MCPJWTSigner checks that every entry in required_claims is present and truthy in the verified claims; any missing claim yields HTTPException 403 naming the missing claims. This is an authorization policy check - the token is authentic but lacks required identity attributes.
Source
Thrown at litellm/proxy/guardrails/guardrail_hooks/mcp_jwt_signer/mcp_jwt_signer.py:527
# FR-15: Incoming claim validation
# ------------------------------------------------------------------
def _validate_required_claims(
self,
jwt_claims: Mapping[str, object] | None,
) -> None:
"""
Raise HTTP 403 if any required_claims are absent from the verified
incoming token claims.
"""
if not self.required_claims:
return
from fastapi import HTTPException
missing: Final = [c for c in self.required_claims if not (jwt_claims or {}).get(c)]
if missing:
raise HTTPException(
status_code=403,
detail={
"error": (
f"MCPJWTSigner: incoming token is missing required claims: "
f"{missing}. Configure the IdP to include these claims."
)
},
)
# ------------------------------------------------------------------
# FR-12: End-user identity mapping
# ------------------------------------------------------------------
def _resolve_end_user_identity(
self,
user_api_key_dict: UserAPIKeyAuth,
jwt_claims: Mapping[str, object] | None,
) -> str:View on GitHub (pinned to 77b7c6c40c)
Solutions
- Configure the IdP to include the required claims in access tokens (add claim to token via custom claims/scope mapping)
- Align required_claims with names the IdP actually emits - check casing and spelling against a decoded token
- Trim required_claims to what the token realistically contains, moving strict requirements elsewhere (e.g. scopes)
Example fix
# before - requires a claim the IdP never emits litellm_params: required_claims: [email, org_id] # after - matches the IdP's emitted claims litellm_params: required_claims: [sub, email]
Defensive patterns
Strategy: try-catch
Validate before calling
import jwt as pyjwt
def claims_cover_required(token: str, required: list[str]) -> bool:
claims = pyjwt.decode(token, options={"verify_signature": False})
return all(claims.get(c) for c in required)
assert claims_cover_required(sample_token, required_claims) # validate config against a real token before rollout Try / catch
import openai
try:
resp = client.responses.create(model=deployment, tools=mcp_tools, input=prompt)
except openai.PermissionDeniedError as e:
msg = getattr(e, "body", {}).get("error", "") if isinstance(getattr(e, "body", None), dict) else str(e)
if "missing required claims" in msg:
return guide_user_to_token_with_full_claims()
raise Prevention
- Decode a real token from your IdP and copy required_claims verbatim from its claim names
- Watch casing - claim names are case-sensitive
- Prefer scope-based policies over custom claims when the IdP cannot mint custom attributes
When it happens
Trigger: An MCP request whose verified JWT/opaque-token claims omit one of the configured required_claims - e.g. required_claims: [email, org_id] but the IdP-issued token only contains sub and scope.
Common situations: IdP access tokens that carry only standard claims while the policy expects custom ones (org_id, team); claim names cased differently (OrgID vs org_id); scope-only machine tokens with no user identity claims; required_claims copied from another IdP's claim vocabulary.
Related errors
- forbidden
- access_denied
- User does not have permission to test MCP server connections
- User does not have permission to test MCP server tools. Only
- User not allowed to call this tool.
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/8592503257bc72a4.
Report an issue: GitHub.