What happened?
When connecting to an OAuth-protected MCP server that returns a WWW-Authenticate header containing resource_metadata, the 401-triggered OAuth flow always fails with ResourceMismatchError. This affects any MCP server that serves resources under a path (e.g., gateways, multi-tenant setups).
The error manifests as:
Failed to handle automatic OAuth for server '<name>'
With the underlying cause being a ResourceMismatchError thrown during metadata validation.
Root Cause
In packages/core/src/tools/mcp-client.ts (line 679-680), handleAutomaticOAuth() parses the resource_metadata URL from the WWW-Authenticate header and passes it to discoverOAuthConfig():
const resourceMetadataUri = OAuthUtils.parseWWWAuthenticateHeader(wwwAuthenticate);
if (resourceMetadataUri) {
oauthConfig = await OAuthUtils.discoverOAuthConfig(resourceMetadataUri);
}
discoverOAuthConfig() expects a server URL and constructs .well-known paths from it (per RFC 9728 section 3.1). But resourceMetadataUri is already a .well-known URL (e.g., https://example.com/.well-known/oauth-protected-resource), so it produces a double-nested path:
https://example.com/.well-known/oauth-protected-resource/.well-known/oauth-protected-resource
This 404s. The root-based fallback within discoverOAuthConfig then accidentally fetches the root metadata, but validation compares resource: "https://example.com" against expectedResource: "https://example.com/.well-known/oauth-protected-resource" (the metadata URI, not the actual server URL), which throws ResourceMismatchError.
When handleAutomaticOAuth returns false, the caller at line 1702 throws immediately with no fallback to the proactive discovery path (line 1706+), which would have succeeded.
Expected Behavior
handleAutomaticOAuth() should use OAuthUtils.discoverOAuthFromWWWAuthenticate() (which already exists at oauth-utils.ts line 332) to directly fetch the resource_metadata URL and validate against the actual server URL:
// Current (buggy):
oauthConfig = await OAuthUtils.discoverOAuthConfig(resourceMetadataUri);
// Suggested fix:
const serverUrl = mcpServerConfig.httpUrl || mcpServerConfig.url!;
oauthConfig = await OAuthUtils.discoverOAuthFromWWWAuthenticate(wwwAuthenticate, serverUrl);
Affected Code
packages/core/src/tools/mcp-client.ts: handleAutomaticOAuth() lines 679-680
packages/core/src/mcp/oauth-utils.ts: discoverOAuthFromWWWAuthenticate() already implements the correct flow but is unused in this code path
Reproduction
- Set up an MCP server behind a path (e.g.,
https://gateway.example.com/ns/server/mcp) that returns:
WWW-Authenticate: Bearer resource_metadata="https://gateway.example.com/.well-known/oauth-protected-resource"
- Configure the MCP server in
~/.gemini/settings.json
- Connect -- observe
Failed to handle automatic OAuth error
Context
Client Information
CLI Version: 0.28.x (current main)
What happened?
When connecting to an OAuth-protected MCP server that returns a
WWW-Authenticateheader containingresource_metadata, the 401-triggered OAuth flow always fails withResourceMismatchError. This affects any MCP server that serves resources under a path (e.g., gateways, multi-tenant setups).The error manifests as:
With the underlying cause being a
ResourceMismatchErrorthrown during metadata validation.Root Cause
In
packages/core/src/tools/mcp-client.ts(line 679-680),handleAutomaticOAuth()parses theresource_metadataURL from theWWW-Authenticateheader and passes it todiscoverOAuthConfig():discoverOAuthConfig()expects a server URL and constructs.well-knownpaths from it (per RFC 9728 section 3.1). ButresourceMetadataUriis already a.well-knownURL (e.g.,https://example.com/.well-known/oauth-protected-resource), so it produces a double-nested path:This 404s. The root-based fallback within
discoverOAuthConfigthen accidentally fetches the root metadata, but validation comparesresource: "https://example.com"againstexpectedResource: "https://example.com/.well-known/oauth-protected-resource"(the metadata URI, not the actual server URL), which throwsResourceMismatchError.When
handleAutomaticOAuthreturns false, the caller at line 1702 throws immediately with no fallback to the proactive discovery path (line 1706+), which would have succeeded.Expected Behavior
handleAutomaticOAuth()should useOAuthUtils.discoverOAuthFromWWWAuthenticate()(which already exists atoauth-utils.tsline 332) to directly fetch theresource_metadataURL and validate against the actual server URL:Affected Code
packages/core/src/tools/mcp-client.ts:handleAutomaticOAuth()lines 679-680packages/core/src/mcp/oauth-utils.ts:discoverOAuthFromWWWAuthenticate()already implements the correct flow but is unused in this code pathReproduction
https://gateway.example.com/ns/server/mcp) that returns:~/.gemini/settings.jsonFailed to handle automatic OAutherrorContext
WWW-Authenticateheaders.Client Information