Support / Royal MCP / Claude.ai Web: Token Exchange Failed

Claude.ai Web: “Authorization with [site] failed” / mcp_token_exchange_failed

You clicked Authorize on Royal MCP’s consent screen, WordPress issued the code, then claude.ai redirected you back to /settings/connectors?error_code=mcp_token_exchange_failed with the message “Authorization with [your site] failed.” If your Royal MCP Activity Log shows the oauth:authorize SUCCESS entry but no subsequent oauth:token entry — you’re hitting an upstream bug at claude.ai’s web client, not a Royal MCP or hosting issue. This page confirms the diagnosis in 30 seconds and shows you the working alternatives.

This is a claude.ai (Anthropic) client-side bug — not Royal MCP, not your host, not your OAuth setup

If Activity Log confirms the token POST never arrived, no server-side change will fix this. Discovery, permalinks, .well-known/, HTTPS, Cloudflare, your host’s WAF, plugin settings — none of them are the cause. The token exchange happens inside claude.ai’s backend and, on some accounts and some sessions, never leaves their infrastructure. Skip to the working alternatives and don’t spend days on /.well-known/.

The Exact Symptom

What you see in the browser

  • You added Royal MCP as a custom connector in claude.ai and clicked Connect
  • Claude.ai opens Royal MCP’s OAuth consent screen — the site name, your admin account, and the requested scopes all appear correctly
  • You click Authorize
  • The browser redirects back to https://claude.ai/api/mcp/auth_callback?code=… for a split second
  • Then lands on https://claude.ai/settings/connectors?error_code=mcp_token_exchange_failed
  • A toast reads “Authorization with [your site name] failed.” Sometimes accompanied by a reference ID like ofid_1d57ea224b045cb9

What’s misleading: the error suggests something failed on your side. It didn’t. Every step up to and including code issuance completed correctly. The failure is in the step that never happened — claude.ai’s backend was supposed to POST that authorization code to your /token endpoint to exchange it for an access token, and it didn’t.

Confirm the Diagnosis in 30 Seconds

The Royal MCP Activity Log is the definitive check. It records every OAuth event that reaches your server. If a /token POST from claude.ai never arrived, no entry appears — and that proves the failure is on their end.

Open Royal MCP → Activity Log

In WP Admin sidebar: Royal MCP → Activity Log. If you don’t see it, look for the “Logs” or “Events” submenu under Royal MCP — older versions labeled it differently.

Look at the entries around the time you clicked Authorize

You should see an oauth:authorize entry with status SUCCESS — that’s the moment WordPress issued the code and redirected back to claude.ai. The relevant detail line reads something like:

OAuth Server — oauth:authorize — SUCCESS
Request:  POST /authorize, client_id wp_[…]
Response: 302, code_issued, "Authorization code issued;
          redirecting to client callback."

Check for a follow-up oauth:token entry

Immediately after the authorize row, you’d expect an oauth:token row with one of:

  • token_issued — success (your OAuth flow completed and claude.ai should have connected)
  • invalid_client / invalid_grant / invalid_request — the POST arrived but was rejected (server-side issue to investigate)

If you see none of those — nothing after the authorize row at all — that’s the fingerprint of the upstream bug. Claude.ai took the redirect and never came back.

The definitive fingerprint

Activity Log shows: oauth:authorize SUCCESS, code_issued. Nothing after it. No oauth:token entry of any kind. That means the POST to /token never arrived at your server. Nothing you can do server-side will fix this.

If Activity Log DOES show an oauth:token entry with an error

Then you have a different problem — the POST arrived but was rejected. Look at the error code:

  • invalid_client — client_id/secret mismatch, or claude.ai sent auth via HTTP Basic header when we expect client_secret_post. Check static OAuth client setup to test with fresh credentials.
  • invalid_grant — the authorization code was already used, expired, or doesn’t match. Usually resolves on retry.
  • invalid_request — missing required params (typically PKCE). See the PKCE-missing troubleshooting flow.

These are server-side signals worth digging into — but they’re NOT what this page is about. This page is specifically for “POST never arrived” = upstream bug.

Why This Happens

Claude.ai’s custom-connector OAuth flow is split between the browser and their backend. The browser handles the authorize redirect (which is why step 2 — the redirect back to /api/mcp/auth_callback?code=… — always fires visibly). The token exchange then happens server-to-server: claude.ai’s backend POSTs the authorization code to your /token endpoint and receives the access token in response.

On a working flow, that POST fires within milliseconds of your Authorize click. On the affected accounts / regions / sessions, the POST is dropped inside claude.ai’s infrastructure and never leaves their side. Your server receives no request, has nothing to log, has nothing to fail on. From the browser’s perspective, claude.ai just gives up and shows the generic mcp_token_exchange_failed banner.

The pattern is documented across many self-hosted MCP backends — Cloudflare Workers, Salesforce, FastAPI, Clerk OAuth, n8n, FIIP, Microsoft 365 — and multiple Anthropic-owned github issues:

github.com/anthropics/claude-ai-mcp/issues/215
github.com/anthropics/claude-ai-mcp/issues/175
github.com/anthropics/claude-ai-mcp/issues/163
github.com/anthropics/claude-ai-mcp/issues/46
github.com/anthropics/claude-ai-mcp/issues/119
github.com/anthropics/claude-ai-mcp/issues/184
github.com/anthropics/claude-plugins-official/issues/1674

Issue #215 in particular matches this symptom exactly and is closed as “not planned.” The common thread across all of them is: authorize completes, code is issued, then nothing. Claude Desktop’s mcp-remote bridge works against the same servers, which proves the failure is specific to claude.ai’s web client — not to the MCP servers themselves.

Why we can’t fix this on the plugin side

There is no server-side change that induces claude.ai’s backend to send the POST it isn’t sending. We’ve tested every credible hypothesis on our end — schema shape, auth-method advertisement, redirect URI handling, session state, cache-busting headers — and none of them change the outcome. The fix has to come from Anthropic.

Working Alternatives (in Order of Preference)

1. Claude Desktop — recommended

Same Royal MCP endpoint. Not affected by this bug. Two setup options depending on how much OAuth machinery you want in the loop.

Option A — API key header (fastest, skips OAuth entirely)

Generate an API key in WP Admin → Royal MCP → Settings, then add to Claude Desktop’s config as an Authorization: Bearer header (Royal MCP also accepts X-Royal-MCP-API-Key; either works). Full walkthrough: Connect Claude Desktop with an API key. No OAuth, no discovery, no .well-known/ — skips every layer this bug touches.

Option B — OAuth via mcp-remote bridge

If you want the OAuth-per-user semantics of the web flow, Claude Desktop can consume Royal MCP’s HTTP endpoint via the mcp-remote bridge, which handles OAuth in a browser popup on your desktop. The token exchange happens locally — not through claude.ai’s backend — so it isn’t affected by this bug either. See Using Royal MCP with Claude Desktop.

2. Claude Code (CLI)

Same MCP endpoint, same config pattern as Claude Desktop — API key via Authorization: Bearer header. Not affected by the claude.ai web bug. Ideal if you’re a developer already using Claude Code for coding work and want your WordPress tools available in the same session.

3. Try a different host as diagnostic (only if you’re also fighting other issues)

If claude.ai web works for you against a different Royal MCP install (on a different host) but fails on yours, that would be evidence of a host-specific factor. In practice we haven’t seen host correlation for this specific bug — it appears account-scoped or region-scoped on the claude.ai side — but if your OAuth is already brittle on the host for other reasons, moving is worth considering regardless. See OAuth fails on managed hosts.

Note: This Is Different from ChatGPT’s Cosmetic Banner

Some ChatGPT Dev Mode connectors show “action discovery failed” or “unknown error” after Authorize but the connector actually works in-chat — the modal error is cosmetic. That’s a different bug: see Connecting to ChatGPT.

Claude.ai’s mcp_token_exchange_failed, by contrast, is a hard failure. The connector never actually completes; it doesn’t appear in your connector list; there’s no in-chat call to attempt. If Activity Log confirms no /token POST arrived, don’t retry the OAuth flow expecting it to work — move to the alternatives above.

External References

If you want to follow the upstream tracking:

General web search: query mcp_token_exchange_failed and you’ll find the same failure reported against many self-hosted MCP servers, none of which have a server-side resolution.

Still Stuck?

If Activity Log does show a /token entry with an error (not the empty pattern this page describes), or the alternatives above don’t apply to your setup, we can help.

Community Support (free) — wp.org Plugin Forum

Post a new thread at wordpress.org/support/plugin/royal-mcp/. Include:

Premium Support (paid)

For direct one-on-one help with 24-hour SLA, see Premium Support ($149/year).