MCP HTTP/SSE OAuth: SDK silently fails to open browser after "MCP OAuth redirect to authorization" (3.2.11 → latest)

Where does the bug appear (feature/product)?

Somewhere else…

Describe the Bug

Summary

After updating to Cursor 3.3.30, OAuth for a custom remote MCP server no longer completes. Cursor connects to the MCP SSE transport and successfully fetches OAuth discovery metadata, but it never performs Dynamic Client Registration and never opens the browser to /oauth/authorize.
This worked 5/9/26 before the latest Cursor update and is now failing on 5/11/26.

Environment

  • Cursor: 3.3.30
  • OS: macOS / Darwin arm64
  • MCP transport: Remote SSE endpoint
  • OAuth flow: Authorization Code + PKCE
  • Client registration: OAuth 2.0 Dynamic Client Registration
  • Redirect URI: cursor://anysphere.cursor-mcp/oauth/callback

Expected Behavior

When adding the MCP server, Cursor should:

  1. Connect to the MCP server.
  2. Receive a 401 for protected MCP requests.
  3. Fetch /.well-known/oauth-protected-resource.
  4. Fetch /.well-known/oauth-authorization-server.
  5. Call the advertised registration_endpoint.
  6. Open browser to the advertised authorization_endpoint.
  7. Complete OAuth via PKCE callback.
  8. Reconnect with Bearer token and list tools.

Actual Behavior

Cursor does steps 1-4, then stops. It never calls:

  • POST /api/oauth/register
  • GET /oauth/authorize
    No browser window opens. The MCP server remains connected over SSE, pings work, but tools never appear because authorization never completes.
    Cursor Output previously showed:

MCP OAuth provider initialized Error connecting to streamableHttp server, falling back to SSE: Streamable HTTP error: Error POSTing to endpoint: Method Not Allowed Successfully connected to sse server Saving PKCE code verifier MCP OAuth redirect to authorization Stored server URL for OAuth flow OAuth provider needs auth callback during connection Client error: Unauthorized Unauthorized
After deleting/re-adding the MCP connection and restarting Cursor, the Cursor output panel showed no new useful logs, but server logs still show the same pattern: OAuth discovery succeeds, then no registration or authorization request occurs.

Relevant Server Logs
Cursor probes Streamable HTTP, then falls back to SSE successfully:

Started POST "/mcp/sse" Started GET "/mcp/sse" Successfully connected / SSE client registered
Cursor initializes MCP successfully:

Request body: {“method”:“initialize”, … “protocolVersion”:“2025-11-25” …}
Server response: {protocolVersion: “2024-11-05”, capabilities: {resources: …, tools: …}}
Request body: {“method”:“notifications/initialized”,“jsonrpc”:“2.0”}
Client initialized, beginning normal operation
Then Cursor sends protected MCP requests without a token. The server returns 401 before FastMCP handles the JSON-RPC body:

Started POST "/mcp/messages?client_id=..." Account Load SELECT "accounts".* FROM "accounts" ORDER BY "accounts"."id" ASC LIMIT 1 Immediately after each 401, Cursor fetches OAuth metadata:

Started GET "/.well-known/oauth-protected-resource" Completed 200 OK Started GET "/.well-known/oauth-authorization-server" Completed 200 OK
But Cursor never requests:

POST /api/oauth/register
GET /oauth/authorize
POST /oauth/token
OAuth Metadata Shape
Protected resource metadata returns (example.com is a placeholder for the real endpoints):

{
“resource”: “``https://example.com``”,
“authorization_servers”: [“``https://example.com``”],
“scopes_supported”: [“read”, “write”]
}
Authorization server metadata returns:

{
“issuer”: “``https://example.com``”,
“authorization_endpoint”: “``https://example.com/oauth/authorize``”,
“token_endpoint”: “``https://example.com/oauth/token``”,
“registration_endpoint”: “``https://example.com/api/oauth/register``”,
“code_challenge_methods_supported”: [“S256”],
“scopes_supported”: [“read”, “write”],
“response_types_supported”: [“code”],
“grant_types_supported”: [“authorization_code”, “refresh_token”],
“token_endpoint_auth_methods_supported”: [“none”]
}

### Steps to Reproduce
Configure a remote MCP SSE server URL in Cursor.
The server requires OAuth for protected MCP requests and advertises RFC 9728 protected resource metadata.
The auth server metadata includes registration_endpoint, authorization_endpoint, token_endpoint, and PKCE S256 support.
Add the MCP server in Cursor 3.3.30.
Observe server logs.

### Expected Behavior
Cursor calls POST /api/oauth/register, then opens browser to /oauth/authorize.

Actual: Cursor fetches both well-known metadata endpoints repeatedly, but never calls the registration endpoint or authorization endpoint. No browser window opens.

### Operating System
MacOS

### Version Information
Version: 3.3.30
VSCode Version: 1.105.1

### Additional Information
This appears to fail between “authorization server metadata loaded” and “client registration / authorization started.”

It may be related to newer MCP 2025-11-25 OAuth behavior. Cursor advertises protocol version 2025-11-25 during MCP initialize. If Cursor now prioritizes Client ID Metadata Documents or static client registration, it still appears not to fall back to the advertised Dynamic Client Registration endpoint.

### Does this stop you from using Cursor
No - Cursor works, but with this issue

Correction / follow-up to the OP — after another day of debugging with my team, the root cause isn’t where I thought. Sharing the corrected diagnosis so this is searchable for anyone hitting the same wall.

Summary
When Cursor’s MCP HTTP/SSE client attempts OAuth 2.0 + PKCE against a custom MCP server, the bundled SDK successfully:

Discovers OAuth metadata (/.well-known/oauth-protected-resource, /.well-known/oauth-authorization-server)
Performs dynamic client registration (POST /register) ✓
Builds the authorize URL with code_challenge/code_challenge_method=S256/state ✓
…and then silently fails to open the URL in the user’s browser. No toast, no banner, no error dialog. The MCP panel just shows “no tools, prompts, or resources.” This is the same bug previously reported in:

This is not a 3.3.30 regression. Reproduced on:

Cursor 3.2.11 (coworker’s machine, macOS)
Cursor 3.3.x latest (mine, macOS)
…against the same MCP server, with identical log signatures, so the title of this thread was misleading and I’ve updated it. DCR is also not the failing step — it succeeds (we see Persisting new OAuth client registration in Cursor’s log and a matching POST /register 200 in our server logs).

Reproducing log signature
~/Library/Application Support/Cursor/logs//window/exthost/anysphere.cursor-mcp/MCP user-.log:

[info] Successfully connected to sse server
[info] No stored client information found
[info] saveClientInformation() entered
[info] Persisting new OAuth client registration ← DCR succeeds
[info] Using redirect URL
[info] Saving PKCE code verifier
[info] MCP OAuth redirect to authorization ← URL is computed
[info] OAuth provider needs auth callback during connection
[error] Client error: Unauthorized Unauthorized ← but no browser ever opens
Notice the gap between “MCP OAuth redirect to authorization” and the Client error — that’s where provider.redirectToAuthorization(url) should be calling vscode.env.openExternal(url) or equivalent. There’s no log entry showing it’s even attempted, much less failing.

Evidence the server side is fine
Running mcp-remote against the same MCP server completes the OAuth flow successfully:

npx -p mcp-remote@latest mcp-remote https:///mcp/sse 8787
mcp-remote performs the same DCR + PKCE handshake, then calls Node’s open package to launch the browser. Server returns 200 OK on /oauth/authorize, user approves, browser redirects to http://localhost:8787/oauth/callback?code=...&state=``… So RFC 7591 DCR, RFC 8414 metadata, RFC 9728 protected-resource discovery, and the PKCE handshake are all implemented correctly server-side — the break is exclusively in Cursor’s redirectToAuthorization step.

Minimal reproduction
Stand up any MCP server with OAuth + PKCE + DCR (we used Doorkeeper-backed Rails; the mcp-remote example servers also work).
~/.cursor/mcp.json:
{
“mcpServers”: {
“example”: {
“url”: “https:///mcp/sse”,
“transport”: {“type”: “sse”}
}
}
}
Quit Cursor (Cmd-Q), reopen.
No browser tab opens. MCP entry shows “no tools”. Log file shows the signature above.
Workaround for users blocked today
Switch the entry from native HTTP/SSE to a stdio proxy:

{
“mcpServers”: {
“example”: {
“command”: “npx”,
“args”: [“-y”, “mcp-remote@latest”, “https:///mcp/sse”, “8787”]
}
}
}
mcp-remote opens the browser itself (via Node’s open, bypassing Cursor’s broken SDK path). Important: pin the callback port (8787 above) to one your server’s redirect_uri allowlist accepts, otherwise DCR returns invalid_redirect_uri. Also be aware that if multiple Cursor windows are open they’ll race on that port — close all but one during initial auth.

Thanks for the thorough follow-up, Ashton. We’ve reproduced this independently and confirmed it’s not a 3.3.30 regression.

This is a known bug that our team is tracking. Your mcp-remote stdio proxy workaround is the right approach for now.

We’ll follow up here when a fix ships.

Any update on this?

No fix has shipped yet - this is still being tracked by our team.

The workaround from earlier in the thread still applies: use an mcp-remote stdio proxy instead of the native HTTP/SSE transport. That bypasses Cursor’s broken browser-open step:

{
"mcpServers": {
"your-server": {
"command": "npx",
"args": ["-y", "mcp-remote@latest", "https://your-server-url/mcp/sse", "8787"]
}
}
}

We’ll update this thread when a fix ships.