OAuth Browser Redirect Not Triggered for HTTP-based MCP Servers

Where does the bug appear (feature/product)?

Cursor IDE

Describe the Bug

Cursor Bug Report: OAuth Browser Redirect Not Triggered for HTTP-based MCP Servers

Summary

Cursor successfully discovers and configures OAuth for HTTP-based MCP servers but fails to automatically open the browser for user authorization. This forces users to manually extract authorization URLs from logs, creating a poor user experience despite the OAuth flow being otherwise functional.

Environment

  • Cursor Version: 2.2.43 (stable channel)
  • OS: macOS 15.1.0 (Darwin 25.1.0)
  • Architecture: ARM64 (Apple M2 Pro)
  • MCP Server Type: HTTP (Streamable HTTP Transport)
  • MCP SDK Version: @modelcontextprotocol/sdk ^1.25.1
  • Transport: url: "http://localhost:3000/mcp" in ~/.cursor/mcp.json

Expected Behavior

When an HTTP-based MCP server requires OAuth authentication:

  1. Cursor discovers OAuth endpoints via 401 response with WWW-Authenticate header
  2. Cursor registers as an OAuth client via Dynamic Client Registration
  3. Cursor generates an authorization URL with PKCE challenge
  4. Cursor automatically opens the system browser to the authorization URL
  5. User logs in and authorizes the application
  6. Browser redirects to cursor://anysphere.cursor-mcp/oauth/callback?code=...
  7. Cursor intercepts the callback and exchanges the code for an access token
  8. Connection completes successfully

Actual Behavior

Steps 1-3 and 5-8 work correctly, but step 4 fails:

  1. :white_check_mark: Cursor discovers OAuth endpoints
  2. :white_check_mark: Cursor registers as an OAuth client
  3. :white_check_mark: Cursor generates authorization URL with PKCE
  4. :cross_mark: Cursor logs “Redirect to authorization requested” but does NOT open the browser
  5. :pause_button: Flow stalls - user must manually find URL in logs
  6. :white_check_mark: (Manual) User copies URL from logs and opens in browser
  7. :white_check_mark: User logs in and authorizes
  8. :white_check_mark: Browser redirects to cursor:// callback
  9. :white_check_mark: Cursor successfully exchanges code for token
  10. :white_check_mark: Connection completes and MCP tools become available

Evidence from Cursor Logs

Log file: ~/Library/Application Support/Cursor/logs/MCP user-{server-name}

Successful OAuth Discovery

[info] No stored tokens found
[info] Using redirect URL {"url":"cursor://anysphere.cursor-mcp/oauth/callback"}
[info] Saving PKCE code verifier {"verifierLen":43}

Authorization URL Generated (but browser NOT opened)

[info] Redirect to authorization requested {"url":"http://localhost:3000/authorize?response_type=code&client_id=client_d8377ad4-c87d-4156-add6-5a2aa65a0dfb&code_challenge=BBk_X7lRfOVl1pC6Y7apQ2SbjTh9x9aIXqKZB46mt84&code_challenge_method=S256&redirect_uri=cursor%3A%2F%2Fanysphere.cursor-mcp%2Foauth%2Fcallback&state=eyJpZCI6InVzZXItc2tldGNodXAtbWNwIn0&resource=http%3A%2F%2Flocalhost%3A3000%2Fmcp"}

:cross_mark: No browser window opens at this point

After Manual Browser Authorization

[info] Received OAuth callback with code
[info] Saving tokens {"accessTokenLen":36,"refreshPresent":false,"expiresIn":3600}
[info] OAuth authorization completed
[info] Successfully connected to streamableHttp server
[info] Found 3 tools, 0 prompts, and 0 resources

Steps to Reproduce

1. Set up an HTTP-based MCP server with OAuth

Server configuration:

  • Implements OAuth 2.0 with PKCE (RFC 7636)
  • Returns 401 with WWW-Authenticate: Bearer realm="mcp", resource_metadata="..." header
  • Provides standard OAuth discovery endpoints:
    • /.well-known/oauth-authorization-server
    • /.well-known/oauth-protected-resource/{resource}
  • Supports Dynamic Client Registration (RFC 7591)
  • Accepts cursor://anysphere.cursor-mcp/oauth/callback as redirect URI

Example server: Available at https://github.com/[your-repo] (or can provide full implementation)

2. Configure Cursor MCP settings

~/.cursor/mcp.json:

{
  "mcpServers": {
    "test-oauth-server": {
      "url": "http://localhost:3000/mcp"
    }
  }
}

3. Start the OAuth-enabled MCP server

npm start

4. Restart Cursor or reload MCP settings

5. Observe the behavior

What happens:

  • Cursor logs show “Redirect to authorization requested”
  • No browser window opens
  • Connection remains in “Unauthorized” state
  • User must manually extract URL from logs

What should happen:

  • Browser window opens automatically to authorization URL
  • User completes login in browser
  • Flow continues seamlessly

Server-Side Verification

The MCP server logs confirm correct OAuth behavior:

[info] → POST /mcp
[warn] ⚠️  NO BEARER TOKEN - Returning 401 with WWW-Authenticate
[warn] WWW-Authenticate header: Bearer realm="mcp", resource_metadata="http://localhost:3000/.well-known/oauth-protected-resource/mcp"
[info] âś… GET /.well-known/oauth-protected-resource/mcp 200
[info] âś… GET /.well-known/oauth-authorization-server 200

The server is correctly implementing the OAuth specification, and Cursor correctly discovers the OAuth endpoints.

Current Workaround

Users must:

  1. Monitor Cursor logs: ~/Library/Application Support/Cursor/logs/MCP user-{server-name}
  2. Find the “Redirect to authorization requested” line
  3. Copy the URL from the log
  4. Manually open it in a browser
  5. Complete the OAuth login flow
  6. Browser redirects back to Cursor successfully

Impact

Severity: Medium-High

  • OAuth HTTP-based MCP servers are effectively unusable without manual intervention
  • Poor user experience compared to stdio-based servers
  • Requires technical knowledge to extract URLs from logs
  • Undermines the benefit of standardized OAuth flow
  • May discourage developers from using HTTP transport for MCP servers

Additional Notes

What Works Correctly

  • :white_check_mark: OAuth discovery via 401 response
  • :white_check_mark: Dynamic Client Registration with cursor:// redirect URI
  • :white_check_mark: PKCE code challenge generation
  • :white_check_mark: Authorization code exchange
  • :white_check_mark: Token storage and usage
  • :white_check_mark: Automatic token refresh handling
  • :white_check_mark: Custom URI scheme callback (cursor://anysphere.cursor-mcp/oauth/callback)

What Doesn’t Work

  • :cross_mark: Automatic browser launch for authorization URL

Comparison to stdio Transport

It’s unclear if stdio-based MCP servers with OAuth have the same issue, as they are less common. However, the expectation is that OAuth flows should work consistently regardless of transport method.

Suggested Fix

In the Cursor MCP client code, when “Redirect to authorization requested” occurs:

// Current behavior (logging only)
logger.info('Redirect to authorization requested', { url: authorizationUrl });

// Suggested behavior (open browser)
logger.info('Redirect to authorization requested', { url: authorizationUrl });
await shell.openExternal(authorizationUrl); // or equivalent browser launch API

Related Issues

  • This may be related to general OAuth support for HTTP-based MCP servers
  • Similar issues might exist with other OAuth flows (refresh token, etc.)

Test Server Available

A fully functional test server implementing this OAuth flow is available for reproduction. It includes:

  • Complete OAuth 2.0 server with PKCE support
  • Dynamic Client Registration
  • Mock user authentication (demo / demo123)
  • Detailed logging for debugging
  • Working MCP tools once authenticated

Please contact for access to the test server or additional debugging information.


Contact

Reporter: [Your Name/GitHub]
Date: December 21, 2025
Cursor Version: 2.2.43 (stable)

Attachments

  1. Complete Cursor log showing OAuth flow
  2. Server-side logs confirming correct OAuth implementation
  3. Network capture of OAuth discovery and registration
  4. Working test server implementation (available on request)

Steps to Reproduce

but step 4 fails:

  1. :white_check_mark: Cursor discovers OAuth endpoints
  2. :white_check_mark: Cursor registers as an OAuth client
  3. :white_check_mark: Cursor generates authorization URL with PKCE
  4. :cross_mark: Cursor logs “Redirect to authorization requested” but does NOT open the browser
  5. :pause_button: Flow stalls - user must manually find URL in logs
  6. :white_check_mark: (Manual) User copies URL from logs and opens in browser
  7. :white_check_mark: User logs in and authorizes
  8. :white_check_mark: Browser redirects to cursor:// callback
  9. :white_check_mark: Cursor successfully exchanges code for token
  10. :white_check_mark: Connection completes and MCP tools become available

Operating System

MacOS

Current Cursor Version (Menu → About Cursor → Copy)

Environment

  • Cursor Version: 2.2.43 (stable channel)
  • OS: macOS 15.1.0 (Darwin 25.1.0)
  • Architecture: ARM64 (Apple M2 Pro)
  • MCP Server Type: HTTP (Streamable HTTP Transport)
  • MCP SDK Version: @modelcontextprotocol/sdk ^1.25.1
  • Transport: url: "http://localhost:3000/mcp" in ~/.cursor/mcp.json

Does this stop you from using Cursor

No - Cursor works, but with this issue

Hey, thanks for the report.

This looks like a new bug specific to HTTP-based MCP servers on macOS. The known OAuth issues we’re tracking are either Linux-related or about the browser opening inside the IDE.

A couple of questions to help us narrow it down:

  1. Do you see any errors in the Developer Tools console (Help > Toggle Developer Tools) at the moment the browser should open?
  2. Can you test with another HTTP MCP server that uses OAuth, to rule out a server-specific issue?
  3. Please try temporarily setting a different default browser and retry.

I’ll escalate this to the team for investigation. Your logs and repro steps are very helpful.

This is my current mcp.json and some logs from cursor and my mcp server.

{
    "mcpServers": {
      "testing-mcp": {
        "url": "https://local.dev.testing.com:3443/mcp"
      }
    }
  }
  

The project has gotten a bit more sophisticated since my post earlier. Some of the urls have changed a bit but the problem remains.

I switched my default browser to Firefox and had the same issue.

One thing I’m wondering, with http earlier today and now https with an untrusted certificate I made, could Cursor be denying the use of that URL?

devtools.txt (13.7 KB)

output-panel.txt (5.7 KB)

1 Like

Server logs …

server.txt (10.4 KB)

1 Like