Skills.

The client says “connected”, tools/list answers, and every account-scoped tool returns 401 forever. There is no error to search for — this article is the missing error message.

The symptom (all of these, same cause)

The cause: the 401 that never arrives during login

The MCP authorization spec makes the client start the flow reactively: it only discovers the authorization server and begins OAuth when it gets back

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://<host>/.well-known/oauth-protected-resource"

A server that answers initialize and tools/list without requiring auth (200) and only challenges 401 on account-scoped calls never trips that trigger during a login probe. The probe sees “connected” and stops — the client exits with no URL, no consent step and no token.

That is a server-side design choice (public tool surface, private account tools), not a broken server and not a broken client: what fails is the interaction between the two.

Diagnosis: 4 commands, in this order

  1. Does the server challenge you?Call a tool that needs an account and look for 401 + WWW-Authenticate with resource_metadata=. A 200 means the tool is public: pick another (profile / library / credits / orders). curl -sS -i -m 20 -X POST "$MCP_URL" -H 'Content-Type: application/json' \ -H 'Accept: application/json, text/event-stream' \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/call", "params":{"name":"<account_scoped_tool>","arguments":{}}}' | head -30
  2. Which authorization server does it advertise?Look for authorization_servers[] and scopes_supported[]. curl -sS -m 20 "$MCP_URL_ORIGIN/.well-known/oauth-protected-resource"
  3. Does the server accept a client created on the fly?Look for registration_endpoint (you do not have to register a client by hand), authorization_endpoint, token_endpoint, code_challenge_methods_supported: S256 and token_endpoint_auth_methods_supported: none (public client + PKCE). curl -sS -m 20 "$AUTH_SERVER/.well-known/oauth-authorization-server"
  4. Did a token land on disk?Registration is not authentication. Only the *.client.json means OAuth did not complete. ls -la "$TOKEN_DIR" # ~/.config/<client>/mcp-tokens/, ~/.mcp/tokens/

How to read it: (1) 401 with WWW-Authenticate = the server is correctly configured, the client just never asked; (3) with registration_endpoint = the flow is automatic and there is no client to register by hand — whatever the client's error message suggests.

The fix: force one 401 while the OAuth provider is live

The pitfalls that cost the most time

How to report it (a shape that leaves no doubt)

CAUSE: <one sentence: which step of the flow never happened>
EVIDENCE: <the 401 + WWW-Authenticate line, the registration_endpoint line, the token file path>
FIX APPLIED: <A | B | C + what changed>
VERIFIED: <the exact account-scoped call and its returned text, or "NOT VERIFIED: <why>">
NEXT: <single next action>

The last line matters most: VERIFIED with the raw output, or the admission that it could not be checked. “Connected” is not evidence.

Start now

The MCP OAuth Debug skill ships the full diagnosis, the one-page checklist and the reference implementation of fix B (scripts/force-oauth-challenge.py), for any MCP client and any OAuth-protected server.

See the MCP OAuth Debug skill See all skills

Need it solved inside your project? Guided setup from R$ 1.500, with the first cycle run together.

← all skills

Get the next article

Sent when I publish, together with the free skill used here. No spam, one-click unsubscribe.

Payment processed by Stripe — no card data touches this server. Instant delivery once confirmed. Prices in BRL (Brazilian real) — you are charged in BRL. Terms, delivery and refund.