[BUG] v2.1.196 regression: MCP OAuth sends no scope when none is configured → AADSTS900144 on Microsoft Entra ID

Open 💬 0 comments Opened Jun 30, 2026 by ihosav

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report
  • [x] I am using the latest version of Claude Code

What's Wrong?

After auto-update 2.1.195 → 2.1.196, authenticating an OAuth-protected HTTP MCP server whose authorization server is Microsoft Entra ID fails. The browser lands on Entra's /oauth2/v2.0/authorize page with:

AADSTS900144: The request body must contain the following parameter: 'scope'.

The generated authorize URL contains response_type, client_id, code_challenge, and code_challenge_method — but no scope parameter. No scope is explicitly configured for the server (oauth.scopes unset, no --scope).

This looks like an over-correction of a fix shipped in 2.1.196. The 2.1.196 changelog says:

Fixed MCP OAuth requesting the authorization server's full scopes_supported catalog when no scope is specified, causing invalid_scope failures on GitLab self-hosted and other enterprise IdPs

On the no-scope path the client now appears to send nothing. Entra's v2.0 /authorize endpoint requires a non-empty scope, so it rejects the request before the user can sign in. 2.1.195 sent the full scopes_supported catalog (per the changelog's description of the pre-fix behavior) — which happened to include the required resource scope, so Entra accepted it.

The server's discovery metadata is correct and advertises scopes properly:

  • /.well-known/oauth-protected-resourcescopes_supported: ["api://<resource-guid>/Data.Read"]
  • /.well-known/oauth-authorization-serverscopes_supported: ["openid","profile","email","offline_access","api://<resource-guid>/Data.Read"], with authorization_endpoint pointing at the Entra v2.0 endpoint.

What Should Happen?

With no scope explicitly configured, the client should request a non-empty default rather than nothing — e.g. fall back to the protected-resource metadata's scopes_supported (RFC 9728), or at minimum the standard OIDC scopes. An empty/absent scope is never valid for Entra.

The two enterprise IdPs in play have opposite constraints — GitLab self-hosted rejects the full catalog (#55954), while Entra requires at least one scope — so "send everything" and "send nothing" each break one of them. The resource scope from the protected-resource metadata is the value that satisfies both.

Error Messages/Logs

AADSTS900144: The request body must contain the following parameter: 'scope'.

Authorize URL (sanitized):

https://login.microsoftonline.com/<tenant>/oauth2/v2.0/authorize?response_type=code&client_id=<public-client>&code_challenge=<...>&code_challenge_method=S256

Note the absence of any &scope= parameter.

Steps to Reproduce

  1. On 2.1.195, add an HTTP MCP server fronted by Microsoft Entra ID (its RFC 8414 auth-server metadata points at Entra v2.0 endpoints; its protected-resource metadata advertises an api://<guid>/Data.Read scope). Authenticate via /mcp → succeeds.
  2. Update to 2.1.196.
  3. claude mcp logout <server> (or let the access token expire), then /mcp → server → Authenticate.
  4. Browser shows AADSTS900144; the generated authorize URL carries no scope.

Inferred workaround (from the changelog wording — the regression only triggers "when no scope is specified"): set oauth.scopes explicitly, e.g. ["openid","offline_access","api://<guid>/Data.Read"].

Is this a regression?

Yes.

Last Working Version

2.1.195

Claude Code Version

2.1.196 (native install, Windows 11)

---

Related: #55954 (the "requests every scope" bug this 2.1.196 change fixed — opposite direction), #72384 (docs for unset oauth.scopes), #52871 (other Entra-specific OAuth breakage).

View original on GitHub ↗