Where does the bug appear (feature/product)?
Cursor IDE
Describe the Bug
When connecting to an MCP server that uses OAuth 2.0 with a separate authorization server, the OAuth authorization code exchange fails after the user completes browser authorization. The root cause is that the resource_metadata URL extracted from the initial 401 WWW-Authenticate header is not persisted across the OAuth redirect flow.
Environment
- Cursor version: 2.4.31
- Transport: Streamable HTTP
- MCP server setup: Resource server and authorization server are on different hosts; resource metadata is served at a non-standard path indicated by the
WWW-Authenticateheader
Background: How Resource Metadata Discovery Works
When discovering OAuth Protected Resource Metadata, the client uses the following fallback chain:
- If a
resource_metadataURL is explicitly provided (e.g., from theWWW-Authenticateheader): fetch that URL directly. - If no explicit URL is provided, build well-known URLs based on the MCP server URL. For a server at
https://mcp.example.com/v1/mcp:- Try
https://mcp.example.com/.well-known/oauth-protected-resource/v1/mcp - If 404 and path is not
/, fall back tohttps://mcp.example.com/.well-known/oauth-protected-resource
- Try
- If all attempts fail or return 404, the discovery throws, and the authorization server URL falls back to the MCP server’s root origin (e.g.,
https://mcp.example.com/).
Steps to Reproduce
Configure an MCP server at https://mcp.example.com/v1/mcp with the following setup:
- The server returns 401 with:
WWW-Authenticate: Bearer resource_metadata="https://mcp.example.com/v1/.well-known/oauth-protected-resource" - The resource metadata at that URL declares:
{ "resource": "https://mcp.example.com/v1/mcp", "authorization_servers": ["https://auth.example.com"] } - The standard well-known paths do NOT serve valid resource metadata:
https://mcp.example.com/.well-known/oauth-protected-resource/v1/mcp→ 404https://mcp.example.com/.well-known/oauth-protected-resource→ 404 (or returns metadata for a different resource, or is not available)
Flow:
- Cursor connects to the MCP server, receives 401 with the
resource_metadataURL. - Cursor fetches
https://mcp.example.com/v1/.well-known/oauth-protected-resource→ discoversauthorization_servers: ["https://auth.example.com"]→ correctly redirects the user tohttps://auth.example.comfor authorization. - User completes authorization and is redirected back to Cursor via the
cursor://callback URI. - Cursor handles the callback and attempts to exchange the authorization code. During this step, it needs to re-discover the authorization server, but:
- The
resource_metadataURL from the original 401 header is no longer available. - Standard well-known discovery falls back to:
https://mcp.example.com/.well-known/oauth-protected-resource/v1/mcp→ 404https://mcp.example.com/.well-known/oauth-protected-resource→ 404
- Discovery fails → authorization server falls back to
https://mcp.example.com/instead ofhttps://auth.example.com.
- The
- The token exchange request is sent to the wrong server → fails.
Expected Behavior
The authorization code exchange should use https://auth.example.com (the same authorization server used in step 2) to obtain tokens.
Actual Behavior
The authorization code exchange targets https://mcp.example.com/ (the fallback) because the resource_metadata URL from the initial WWW-Authenticate header was lost between the redirect and the callback.
Root Cause Analysis
During the initial connection, the transport layer extracts the resource_metadata URL from the 401 response and passes it to the auth flow. However, this URL is only held in memory. When the user is redirected to the browser for authorization, only mcp_server_url and mcp_code_verifier are persisted. The resource_metadata URL is not.
When the callback URI handler later invokes the auth flow to exchange the authorization code, it cannot provide the resource_metadata URL, so the resource metadata discovery must rely on the standard well-known fallback chain — which may not succeed for servers that only advertise their resource metadata via the WWW-Authenticate header.
Suggested Fix
Store the authorization_server_url from the resource_metadata URL—along with existing values like mcp_server_url, mcp_code_verifier, and mcp_client_information—when initiating the OAuth redirect, and return it to the authentication flow when handling the callback.
Operating System
MacOS
Version Information
Version: 2.4.31
VSCode Version: 1.105.1
Commit: 3578107fdf149b00059ddad37048220e41681000
Date: 2026-02-08T07:42:24.999Z
Build Type: Stable
Release Track: Default
Electron: 39.2.7
Chromium: 142.0.7444.235
Node.js: 22.21.1
V8: 14.2.231.21-electron.0
OS: Darwin arm64 25.2.0
Does this stop you from using Cursor
Sometimes - I can sometimes use Cursor