Debugging "unable to connect": a failure map
Where MCP OAuth connections actually break, ordered by how often they happen, with the test that isolates each one.
Updated
On this page
“Unable to connect” is one error message covering at least seven distinct failures. Work down this list; it’s ordered by frequency, and each entry has a test that gives you a definite answer.
1. Hostname not publicly resolvable
The most common failure for self-hosted servers, and invisible in your logs because no request ever arrives.
- Tailscale Funnel (
*.ts.net), split-horizon DNS, and LAN-only names all fail the connector’s DNS pre-flight even when the URL opens fine in your own browser. - Test:
dig +short yourdomain.com @1.1.1.1; no answer means no connector. - Fix: a real domain with a public record. A $10 domain pointed at the same box beats any tunnel hack.
2. Certificate not from a public CA
Self-signed certs and internal CAs fail the TLS pre-flight.
- Test:
curl -sI https://yourdomain.com/mcp -o /dev/null -w '%{http_code}\n'from a machine outside your network, no-kflag. - Fix: Caddy or a Cloudflare-proxied record; both give you a publicly trusted cert with zero maintenance.
3. Wrong response to the unauthenticated probe
claude.ai’s first MCP call carries no token on purpose. Your server must
return 401 with a WWW-Authenticate header naming the resource metadata
URL, or for a no-auth server just answer the request.
- Test:
curl -si -X POST https://yourdomain.com/mcp | head -5 - A
403, a redirect to a login page, or an HTML error page all kill discovery.
4. Metadata documents missing or inconsistent
/.well-known/oauth-protected-resourceresourcefield must cover the MCP URL: the exact endpoint URL or its origin both pass; anything that doesn’t prefix-match it fails./.well-known/oauth-authorization-servermust listS256undercode_challenge_methods_supportedand advertise aregistration_endpoint.- Test: curl both and read them. Field-by-field expectations are in the connector checklist.
5. Dynamic client registration rejected
claude.ai POSTs to your registration_endpoint and needs a client_id
back. Providers with DCR disabled (Auth0 default) or absent return 403
or 404 here.
- Test: the
/registercurl in the checklist. - Fix: a proxy that answers
/registeritself, the Auth0 proxy guide shows the pattern.
6. Token audience mismatch
The browser flow completes, consent succeeds, and then every tool call gets
401. Almost always: your server validates aud against a value the token
doesn’t carry, because the /authorize redirect didn’t pass audience (or
RFC 8707 resource) to the provider.
- Test: decode the access token at the server (
jwt.ioorjq -R 'split(".")[1] | @base64d | fromjson') and compareaudwith what your validator expects.
7. Streamable HTTP transport mismatches
Older servers speaking only SSE, or servers that reject
Accept: application/json, text/event-stream, connect and then fail on the
initialize round-trip.
- Test:
You want ancurl -s https://yourdomain.com/mcp -X POST \ -H 'content-type: application/json' \ -H 'accept: application/json, text/event-stream' \ -H 'authorization: Bearer YOUR_TOKEN' \ -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"0"}}}'initializeresult, JSON or SSE-framed.
Still stuck after all seven? The MCP Inspector
(npx @modelcontextprotocol/inspector) runs the same handshake with a full
request log on screen, the fastest way to see which step diverges.
Next steps
Once the diverging step is fixed, re-run the four-curl self-test in the connector checklist before touching the connector dialog again; it’s faster than another round trip through claude.ai. If the failure traced back to your authorization server rather than your MCP server, the provider walkthroughs show a known-good configuration to diff against: Auth0, Stytch, Supabase, Hydra. To hand the diagnosis to an agent, copy the debug prompt from the prompt library.
Put it into practice
Diagnose a failing claude.ai connector
A systematic run of the seven checks that isolate where an MCP OAuth connection breaks.
Preview prompt
My remote MCP server at https://MY_DOMAIN/mcp shows "unable to connect" when I add it as a claude.ai custom connector. Run these checks in order, report the result of each, and stop at the first failure with a diagnosis and fix:
1. DNS: dig +short MY_DOMAIN @1.1.1.1, which must return a public A/AAAA/CNAME answer. (Tailscale *.ts.net names and LAN-only DNS fail claude.ai's pre-flight even if the URL works in my browser.)
2. TLS: curl -sI https://MY_DOMAIN/mcp without -k; the certificate must chain to a public CA.
3. Unauthenticated probe: curl -si -X POST https://MY_DOMAIN/mcp | head -5; expect 401 with a WWW-Authenticate header naming the resource metadata URL (or a valid MCP response if the server is intentionally no-auth). 403, 404, redirects, or HTML mean discovery dies here.
4. Protected resource metadata: curl https://MY_DOMAIN/.well-known/oauth-protected-resource; the "resource" field must exactly equal https://MY_DOMAIN/mcp or its origin https://MY_DOMAIN (a prefix of the MCP URL); anything else fails.
5. Authorization server metadata: curl https://MY_DOMAIN/.well-known/oauth-authorization-server; must include authorization_endpoint, token_endpoint, registration_endpoint, and "S256" in code_challenge_methods_supported.
6. DCR: POST to the registration_endpoint with {"redirect_uris":["https://claude.ai/api/mcp/auth_callback"],"client_name":"probe"}; expect a JSON body containing client_id.
7. Handshake: POST an MCP initialize request to /mcp with accept: application/json, text/event-stream (use a token from the flow if auth is on); expect an initialize result, JSON or SSE-framed.
For whichever step fails, explain what claude.ai's discovery expected at that step, what my server returned instead, and the minimal change to fix it. If all seven pass, run npx @modelcontextprotocol/inspector against the endpoint and compare its handshake log with the checks above.Use this site from your agent
Add this URL as a connector in Claude, ChatGPT, or Grok. No sign-in required.
https://quickoauth.com/mcp