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

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.