Skip to content

[BUG] Claude Desktop and claude.ai fail to connect to custom OAuth-protected MCP server - infinite about:blank loop #11814

@jsbattig

Description

@jsbattig

GitHub Issue: Claude Desktop/Web Unable to Connect to OAuth-Protected Custom MCP Server


Issue Title

[BUG] Claude Desktop and claude.ai fail to connect to custom OAuth-protected MCP server - infinite about:blank loop


Environment

  • Claude Desktop Version: [Latest as of November 2025]
  • Claude Web: claude.ai (tested in browser)
  • OS: macOS
  • MCP Server: Custom FastAPI-based MCP server
  • MCP Protocol Version: 2024-11-05
  • OAuth Version: OAuth 2.1 (RFC 6749, RFC 7636 PKCE)
  • Transport: SSE (Server-Sent Events) over HTTPS

Summary

A fully spec-compliant custom MCP server with OAuth 2.1 authentication fails to connect in both Claude Desktop and claude.ai web interface. The OAuth flow never initiates - instead, Claude opens an about:blank page and immediately prompts to reopen Claude Desktop, creating an infinite loop. The same server works perfectly with Claude Code CLI using --transport http.


Expected Behavior

When adding a custom MCP server URL in Claude Desktop/claude.ai Settings → Connectors:

  1. User enters MCP server base URL
  2. Claude discovers OAuth endpoints via .well-known/oauth-authorization-server
  3. Claude registers itself via dynamic client registration
  4. Browser opens to authorization endpoint
  5. User sees login form
  6. After successful login, redirects to https://claude.ai/api/mcp/auth_callback
  7. Claude exchanges authorization code for access token
  8. Connection establishes successfully
  9. MCP tools become available

Actual Behavior

In Claude Desktop:

  1. User enters MCP server URL in Settings → Connectors
  2. Clicks "Connect"
  3. Browser opens to about:blank (no actual URL)
  4. Dialog appears: "Open Claude?"
  5. User clicks "Open Claude"
  6. Returns to Claude Desktop
  7. Connection fails - can click "Connect" again
  8. Infinite loop - no OAuth flow ever initiates

In claude.ai Web Interface:

  1. User enters MCP server URL in Settings → Connectors
  2. Clicks "Connect"
  3. Browser opens to about:blank or refreshes
  4. Error message appears: "There was an error connecting to [ServerName]. Please check your server URL and make sure your server handles auth correctly."
  5. No OAuth flow initiates
  6. Connection never establishes

Server Implementation Details

Our custom MCP server is fully compliant with:

  • MCP Specification 2024-11-05
  • RFC 8414 (OAuth 2.0 Authorization Server Metadata)
  • RFC 9728 (OAuth 2.0 Protected Resource Metadata)
  • RFC 7636 (PKCE for OAuth 2.0)
  • RFC 6749 (OAuth 2.0 Authorization Framework)

Implemented Endpoints

1. OAuth Discovery (RFC 8414)

Endpoint: GET /.well-known/oauth-authorization-server

Response (200 OK):

{
  "issuer": "https://example-server.com:8383",
  "authorization_endpoint": "https://example-server.com:8383/oauth/authorize",
  "token_endpoint": "https://example-server.com:8383/oauth/token",
  "registration_endpoint": "https://example-server.com:8383/oauth/register",
  "code_challenge_methods_supported": ["S256"],
  "grant_types_supported": ["authorization_code", "refresh_token"],
  "response_types_supported": ["code"]
}

Status: ✅ Working correctly, returns proper metadata

2. MCP SSE Endpoint (RFC 9728 Compliant)

Endpoint: GET /mcp

Unauthenticated Request → Returns 401:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="mcp", resource_metadata="https://example-server.com:8383/.well-known/oauth-authorization-server"
Content-Type: application/json

{"error": "unauthorized", "message": "Bearer token required for MCP access"}

Authenticated Request → Returns SSE stream:

HTTP/1.1 200 OK
Content-Type: text/event-stream

event: endpoint
data: {"protocol":"mcp","version":"2024-11-05","capabilities":{"tools":{}},"user":"username"}

event: ping
data: authenticated

Status: ✅ Working correctly per MCP spec

3. OAuth Registration (RFC 7591 - Dynamic Client Registration)

Endpoint: POST /oauth/register

Request:

{
  "client_name": "Claude",
  "redirect_uris": ["https://claude.ai/api/mcp/auth_callback"]
}

Response (201 Created):

{
  "client_id": "generated_client_id",
  "client_name": "Claude",
  "redirect_uris": ["https://claude.ai/api/mcp/auth_callback"],
  "client_secret_expires_at": 0
}

Status: ✅ Working correctly, tested manually with curl

4. OAuth Authorization (RFC 6749 with PKCE)

Endpoint: GET /oauth/authorize

Parameters Required:

  • client_id - Registered client identifier
  • redirect_uri - Must match registered URI
  • response_type - Must be "code"
  • code_challenge - PKCE challenge (S256 method)
  • state - CSRF protection token

Response: Returns HTML login form

Status: ✅ Working correctly, displays login form when accessed manually

5. OAuth Token Exchange

Endpoint: POST /oauth/token

Request (application/x-www-form-urlencoded):

grant_type=authorization_code
code=<authorization_code>
client_id=<client_id>
code_verifier=<pkce_verifier>
redirect_uri=<redirect_uri>

Response:

{
  "access_token": "generated_token",
  "token_type": "Bearer",
  "expires_in": 28800,
  "refresh_token": "refresh_token"
}

Status: ✅ Working correctly

CORS Configuration

Server includes proper CORS headers:

CORSMiddleware(
    allow_origins=[
        "https://claude.ai",
        "https://claude.com",
        "https://www.anthropic.com",
        "https://api.anthropic.com",
    ],
    allow_credentials=True,
    allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"],
    allow_headers=["*"],
)

TLS/SSL Configuration

  • Valid SSL certificate from trusted CA (No-IP TLS ICA)
  • TLS 1.3 enabled
  • Modern cipher suites
  • Certificate chain validates correctly

Testing Performed

Test 1: Manual OAuth Flow ✅ WORKS

# Step 1: Get OAuth discovery metadata
curl https://example-server.com:8383/.well-known/oauth-authorization-server
# Returns: Correct OAuth endpoints

# Step 2: Register client
curl -X POST https://example-server.com:8383/oauth/register \
  -H "Content-Type: application/json" \
  -d '{"client_name":"TestClient","redirect_uris":["https://claude.ai/api/mcp/auth_callback"]}'
# Returns: client_id and registration details

# Step 3: Test MCP endpoint without auth
curl https://example-server.com:8383/mcp
# Returns: HTTP 401 with WWW-Authenticate header (CORRECT)

# Step 4: Test MCP endpoint with Bearer token
curl -H "Authorization: Bearer <valid_token>" https://example-server.com:8383/mcp
# Returns: HTTP 200 with SSE stream (CORRECT)

Result: All endpoints work correctly via curl

Test 2: Claude Code CLI with HTTP Transport ✅ WORKS

# Configure Claude Code CLI to use HTTP transport with OAuth
claude mcp add --transport http custom-server https://example-server.com:8383

# OAuth flow initiates correctly:
# - Browser opens to authorization endpoint
# - Login form displays
# - After login, redirects to callback
# - Claude Code CLI receives token
# - Connection establishes successfully
# - MCP tools available and functional

Result: OAuth flow works perfectly with Claude Code CLI

Test 3: Claude Desktop ❌ FAILS

Steps:

  1. Open Claude Desktop
  2. Settings → Connectors → Add Connector
  3. Enter URL: https://example-server.com:8383
  4. Click "Connect"

Observed:

  • Browser opens to about:blank (no actual URL in address bar)
  • "Open Claude?" dialog appears immediately
  • No network requests to server (checked server logs)
  • Clicking "Open Claude" returns to app
  • Connection fails, can retry indefinitely

Expected:

  • Browser should open to: https://example-server.com:8383/oauth/authorize?client_id=...&redirect_uri=...&code_challenge=...&state=...

Test 4: claude.ai Web Interface ❌ FAILS

Steps:

  1. Go to https://claude.ai/settings/connectors
  2. Add connector
  3. Enter URL: https://example-server.com:8383
  4. Click "Connect"

Observed:

  • Page refreshes or opens about:blank
  • Error: "There was an error connecting to [ServerName]. Please check your server URL and make sure your server handles auth correctly."
  • No network requests to server (checked server logs)
  • Connection never establishes

Expected:

  • Should discover OAuth endpoints
  • Should register client
  • Should redirect to authorization endpoint

Test 5: MCP Inspector ✅ WORKS

Using the official MCP Inspector tool:

npx @modelcontextprotocol/inspector sse https://example-server.com:8383/mcp

Result:

  • SSE connection establishes (after auth)
  • Can complete OAuth flow via Inspector
  • All MCP methods work correctly

Investigation Results

Server Logs Show No Requests from Claude Desktop/Web

When attempting to connect via Claude Desktop or claude.ai:

  • No requests to /.well-known/oauth-authorization-server
  • No requests to /oauth/register
  • No requests to /oauth/authorize
  • No requests to /mcp endpoint

This indicates Claude is failing before even attempting to contact the server.

Network Analysis

Using browser DevTools and curl:

  • All OAuth endpoints respond correctly
  • No CORS errors
  • No TLS errors
  • All HTTP status codes correct
  • All headers properly formatted

Comparison: Working vs Not Working

Transport Status OAuth Flow Notes
Claude Code CLI (STDIO) ✅ Works N/A (no OAuth) Local subprocess
Claude Code CLI (HTTP) ✅ Works ✅ Full flow OAuth works perfectly
Claude Desktop ❌ Fails ❌ Never starts about:blank loop
claude.ai Web ❌ Fails ❌ Never starts Error message
MCP Inspector ✅ Works ✅ Full flow OAuth works
Manual curl ✅ Works ✅ All endpoints OAuth works

Troubleshooting Steps Attempted

1. Changed MCP Endpoint Authentication ✅ Fixed Spec Compliance

Initial Problem: MCP endpoint returned SSE stream for unauthenticated requests (violated MCP spec)

Fix Applied: Changed to return HTTP 401 with WWW-Authenticate header per RFC 9728

Result: Server now fully spec-compliant, but Claude still fails to connect

2. Verified OAuth Discovery Metadata ✅ Correct

  • Checked all URLs use correct scheme (https)
  • Verified issuer matches actual server URL
  • Confirmed all endpoints are accessible
  • Tested with multiple tools - all work correctly

3. Fixed OAuth Issuer URL Configuration ✅ Correct

Initial Problem: OAuth discovery returned hardcoded localhost:8000 URLs

Fix Applied: Made issuer configurable via CIDX_ISSUER_URL environment variable

Result: Discovery metadata now returns correct production URLs

4. Tested Different URL Formats ❌ No Change

Tried entering:

  • https://example-server.com:8383 (base URL)
  • https://example-server.com:8383/mcp (SSE endpoint)
  • Without port number
  • With trailing slash

Result: All fail with same behavior

5. Verified CORS Configuration ✅ Correct

  • Added all Anthropic domains to CORS allowlist
  • Enabled credentials
  • Allowed all necessary headers
  • OPTIONS preflight requests work correctly

Result: CORS is not the issue

6. Checked SSL/TLS Certificate ✅ Valid

curl -v https://example-server.com:8383/.well-known/oauth-authorization-server 2>&1 | grep certificate
# Certificate validates successfully
# Issued by trusted CA (No-IP TLS ICA)
# Valid until November 2026

Result: Certificate is valid and trusted


Code Implementation

Our server implementation follows the MCP specification exactly. Key code snippets:

MCP Endpoint (401 Response for Unauthenticated)

from fastapi import Response, Header
from typing import Optional, Union
from sse_starlette.sse import EventSourceResponse

@mcp_router.get("/mcp")
async def mcp_sse_endpoint(
    authorization: Optional[str] = Header(None),
) -> Union[Response, EventSourceResponse]:
    """MCP SSE endpoint - returns 401 for unauth per RFC 9728"""

    user = None

    # Validate Bearer token if provided
    if authorization and authorization.startswith("Bearer "):
        token = authorization.split(" ", 1)[1]
        user = validate_token(token)  # Returns User or None

    # Return 401 for unauthenticated requests per MCP spec
    if user is None:
        issuer_url = os.getenv("CIDX_ISSUER_URL")
        return Response(
            status_code=401,
            headers={
                "WWW-Authenticate": f'Bearer realm="mcp", resource_metadata="{issuer_url}/.well-known/oauth-authorization-server"',
                "Content-Type": "application/json",
            },
            content='{"error": "unauthorized", "message": "Bearer token required for MCP access"}',
        )

    # Authenticated: return SSE stream
    return EventSourceResponse(authenticated_sse_generator(user))

OAuth Discovery Endpoint

@app.get("/.well-known/oauth-authorization-server")
async def root_oauth_discovery():
    """OAuth 2.1 discovery endpoint (RFC 8414 compliance)"""
    issuer = os.getenv("CIDX_ISSUER_URL")

    return {
        "issuer": issuer,
        "authorization_endpoint": f"{issuer}/oauth/authorize",
        "token_endpoint": f"{issuer}/oauth/token",
        "registration_endpoint": f"{issuer}/oauth/register",
        "code_challenge_methods_supported": ["S256"],
        "grant_types_supported": ["authorization_code", "refresh_token"],
        "response_types_supported": ["code"]
    }

Similar Issues Found

After extensive research, found these related issues:

  1. Issue [BUG] Claude Desktop doesn't connect to Custom MCPs altogether (not with OAuth 2.1 nor with SSE) #5826: "Claude Desktop doesn't connect to Custom MCPs altogether"

    • Same symptoms: about:blank, loop back to app
    • Multiple users reporting OAuth-based custom servers fail
  2. Issue [BUG] MCP OAuth Integration Fails on Production Deployments with step=start_error #3515: "Claude Desktop MCP OAuth Integration Issue Report"

    • OAuth flow fails with step=start_error
    • Failure occurs in Claude's OAuth proxy, not reaching MCP server
  3. fastmcp Issue [BUG] : Cannot use AWS Bedrock with Claude Code. Getting API Error (429 Too many tokens) #1466: "Claude connector issue with remote MCP and oauth enabled"

    • Third-party MCP framework users experiencing same issue
    • OAuth works with MCP Inspector but not Claude

Hypothesis

Based on all evidence, the issue appears to be in Claude's OAuth proxy/client implementation:

  1. Claude Desktop/Web never attempt to contact the MCP server
  2. The about:blank suggests Claude is failing to construct the authorization URL
  3. Server logs show zero incoming requests
  4. Same server works perfectly with Claude Code CLI and MCP Inspector
  5. All OAuth endpoints work correctly when tested manually

Possible causes:

  • Bug in Claude's OAuth discovery implementation
  • Issue with dynamic client registration flow
  • Problem with Claude's internal OAuth proxy
  • URL validation/sanitization breaking the flow
  • Hardcoded assumptions about MCP server structure

Workaround

Currently, the only way to use our OAuth-protected MCP server with Claude is:

Use Claude Code CLI with HTTP transport:

claude mcp add --transport http server-name https://example-server.com:8383

This works perfectly but is not available in Claude Desktop or claude.ai web interface.


Request

Could the Anthropic team investigate why Claude Desktop and claude.ai fail to connect to OAuth-protected custom MCP servers that work correctly with:

  • Claude Code CLI (HTTP transport)
  • MCP Inspector
  • Manual OAuth testing

Our server is fully spec-compliant (RFC 8414, RFC 9728, RFC 7636, RFC 6749) and works with all testing tools except Claude Desktop/Web.

Is there additional configuration or specific requirements for Claude Desktop/Web that differ from the MCP specification?


Additional Information

  • Willing to provide additional debugging information
  • Can provide access to test server for Anthropic engineers (privately)
  • Can provide complete server implementation code if helpful
  • Available for testing any fixes or workarounds

Attachments

  • Server implementation: FastAPI-based MCP server
  • Testing scripts: Complete OAuth flow validation
  • Network captures: Showing no requests from Claude Desktop/Web
  • Success examples: Claude Code CLI working correctly

Thank you for investigating this issue!

Metadata

Metadata

Assignees

No one assigned

    Labels

    duplicateThis issue or pull request already exists

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions