[BUG] claude mcp list/get report "Needs authentication" for an authenticated client rejected by an app-level 403 (re-auth doesn't fix it)

Status Open
Maintainer reply None cached
Activity 0 comments · opened Aug 9, 2026

Summary

claude mcp list / claude mcp get report Needs authentication for a remote HTTP MCP server even when the client already completed a full, successful OAuth (DCR + PKCE) flow and holds a valid, unexpired token. The true condition is an application-level 403 returned by the MCP server for a business-authorization reason unrelated to authentication (in our case: "this OAuth client is authenticated, but not yet approved by an administrator"). Re-authenticating does not change the status, because authentication was never the problem.

This looks related to #78220 (bare 403 misclassified as an OAuth challenge) and the now-closed docs issue #58875 (which confirms that as of v2.1.141, HTTP/SSE servers returning 403 on connect are intentionally shown as needs auth rather than failed). Filing separately because our case is not a WAF/CDN block or a connect-time probe — it is a fully authenticated session, well past initial connect, where a specific tool call gets a 403 with a JSON-RPC error body carrying its own machine-readable code (an app-defined authorization-state code, not an auth error), and the client status still collapses that into the same "Needs authentication" bucket as a bare missing/invalid token.

Repro

  1. Add a remote HTTP MCP server backed by OAuth 2.1 + PKCE + dynamic client registration.
  2. Complete the full sign-in flow in the browser (/mcp → authenticate → consent). The server verifies the bearer token successfully.
  3. The server's own authorization layer separately gates this specific OAuth client behind an app-level allow-list (e.g. "registered but not yet approved by an admin"), and returns a 403 with a JSON body like:

``json
{ "code": "some_app_specific_not_yet_approved_code", "message": "..." }
`
for both
initialize`/tool calls made on that session.

  1. Run claude mcp get <server> or claude mcp list.

Expected

Some status distinguishable from "you are not authenticated" — e.g. Needs approval, Connected (restricted), or at minimum a status that doesn't imply re-running the OAuth flow will fix anything.

Actual

Both commands report:

Needs authentication

identically to what they'd report for a missing or invalid bearer token. There is no way to tell the two apart from the client status alone. Re-authenticating "succeeds" (a fresh token is minted) and the status does not change, because the token was never invalid.

Impact

The client instructs the user to do the one thing that cannot resolve the problem (re-authenticate), and gives no hint that the actual fix is on a different surface entirely (an application-level approval step). The only way we found to see the true state was to bypass the client's status reporting and issue a raw tool call, then read the JSON-RPC error body's own code field directly.

Ask

  • Don't fold every non-2xx response taken during an already-authenticated session into the same Needs authentication bucket the client uses for pre-auth state. If a 403 carries a structured JSON-RPC/HTTP error body (not a bare WAF/HTML block page, which is #78220's case), consider surfacing that body's own error code/message in claude mcp get/claude mcp list rather than overwriting it with a generic auth-shaped status.
  • At minimum, distinguish "never authenticated / token invalid" from "authenticated, but the server rejected this specific client for a non-auth reason" in the status text, so re-authenticating isn't the client's only suggested next step.

Environment

  • Transport: HTTP (Streamable HTTP), OAuth 2.1 + PKCE + DCR
  • Observed via claude mcp get <server> and claude mcp list after a completed browser OAuth consent flow

View original on GitHub ↗