WordPress Plugins
Free Tools
Pricing Blog Case Studies Switch to Royal Plugin Graveyard Support My Account Cart
Support / Royal MCP / Troubleshooting — Start Here

Royal MCP Troubleshooting — Start Here

Connector won’t connect, OAuth failing, tools missing, or Claude returning “Couldn’t reach the MCP server”? Work through the steps below in order. Step 0 is a 30-second curl probe that tells you whether the problem is at your edge (Cloudflare, ModSecurity, host firewall) or inside WordPress — the answer determines which steps to follow next. Most connection failures resolve in under 15 minutes once you know which side of the line you’re on.

Why Step 0 comes before everything else

A meaningful share of Royal MCP failures are caused by edge-layer blocking — Cloudflare Bot Fight Mode, cPanel ModSecurity, Apache + Imunify360, CF Zero Trust hijacking discovery, etc. — before the request ever reaches WordPress. Nothing inside WordPress can fix an edge-layer block. The 30-second curl probe in Step 0 tells you definitively whether the problem is at the edge or inside WP, so you don’t spend an hour disabling plugins and clearing caches for an issue Cloudflare is causing.

Before You Start

Have these on hand:

What this page is, and isn’t

This is the basic checklist. It assumes Royal MCP is already installed and you’ve tried at least once to connect Claude (or any other MCP client) and it failed. If you’re looking for first-time setup, see the Royal MCP Support hub. If you’re looking for a host-specific advanced fix (SiteGround static files, Cloudflare Transform Rules, cache exclusions), the links at the bottom of this page route you there — but only after the steps below.

Using Claude Code in VS Code or Terminal? Start Here.

If you’re connecting through the Claude Code CLI (the claude command, or the VS Code Claude Code extension — not claude.ai web and not Claude Desktop), the fastest fix for most connection problems takes about 30 seconds and bypasses the 4-step checklist below entirely. The 4 steps are scoped for the OAuth-from-a-browser flow that claude.ai web and Claude Desktop use; Claude Code CLI manages its own MCP server connections with different lifecycle behavior.

The 30-second fix — try this before anything else

In your VS Code terminal (or wherever you launched claude), type /mcp and press Enter. You’ll see a list of every configured MCP server. Look at the royal-mcp row:

  • Green check — connection is alive. Your tools should work. If they don’t, jump to the 4-step checklist below.
  • Red X — arrow down to the row, hit Enter, choose Reconnect. About 80% of "reads worked yesterday, writes are 403 today" reports are stale OAuth tokens. A reconnect grabs a fresh token and the problem disappears.
  • Still red after reconnect — close the terminal completely (not just the Claude Code panel — the whole terminal), reopen it, run /mcp again. Stale process-side state is more common than you’d think.
  • Still red after a full terminal restart — re-run the OAuth flow from scratch: remove the royal-mcp server from your Claude Code config (claude mcp remove royal-mcp), then re-add it (claude mcp add...) so the client re-does Dynamic Client Registration against your site fresh. This is the equivalent of the “Reset OAuth State” step that claude.ai web users do server-side — for the CLI, the equivalent action is client-side.
Why the model dropdown in Royal MCP settings doesn’t matter for Claude Code

The model selector in Royal MCP → Settings is used only by the “Test Connection” button on that admin page — it pokes Anthropic’s API with the model you picked to verify your API key. Claude Code in VS Code uses its own configured model, independently of whatever Royal MCP has selected. A 404 from the Test Connection button doesn’t mean Claude Code is broken — it usually means the model in the dropdown was retired by Anthropic. Switch to “Claude Sonnet 4.6 (Latest, Recommended)” and re-test.

If reads work but writes return 403 or “mcp_request_blocked”

That error string comes from Claude Code, not from Royal MCP. It can fire for any non-success response — expired token (401), capability check failure (403), or host-edge block. The diagnostic order is:

  1. Reconnect via /mcp first (above) — rules out stale token, which is the common case.
  2. If that doesn’t fix it, check Royal MCP → Activity Log in wp-admin — if recent attempts show up with errors, the request reached PHP and we can read the failure reason. If the log is empty after you reproduce the failure, the request died at the host edge (WAF, security plugin, or hosting firewall) — jump to the stack-specific section below.
  3. Confirm the WordPress user attached to your API key has the right capability. Post/page write tools (wp_create_post, wp_update_page, etc.) require edit_posts/edit_pages. Media writes require upload_files. If your OAuth flow registered a low-privilege user, writes will fail with 403 even though reads succeed. Confirm in Users → All Users that the connected account has Editor or Administrator role.

If those three checks don’t resolve it — meaning /mcp shows green, Activity Log shows attempts reaching PHP, and the user has the right capability — continue to Step 0 below. The diagnostic path applies to your situation too.

Step 0 — The 30-Second Edge Probe

Before doing anything inside WordPress, run this one curl command from your local machine to find out whether your edge (Cloudflare, ModSecurity, host firewall, etc.) is blocking the request before it reaches WordPress. Your response pattern tells you exactly where the problem lives and which fix to apply.

The probe

Open a terminal on your own computer (not on your WordPress server) and run the command below. Two variants — use the one matching your shell:

Mac Terminal, Linux, Windows Command Prompt (cmd.exe), Git Bash:

curl -sS https://example.com/.well-known/oauth-authorization-server -H "Accept: application/json"

Windows PowerShell: PowerShell aliases curl to Invoke-WebRequest, which uses different flag syntax and will error on the command above. Use curl.exe instead — that bypasses the alias and runs Windows’ built-in real curl with the same syntax as everywhere else:

curl.exe -sS https://example.com/.well-known/oauth-authorization-server -H "Accept: application/json"

Replace example.com with your actual domain. Match the result against one of the patterns below.

No terminal at all? Use Postman or Insomnia.

Both are free GUI HTTP clients that let you GET a URL, set a User-Agent header (important for the 403 / 406 / 429 patterns below where the UA changes the result), and see the response with headers visible. Avoid plain browser tabs for this probe — browsers send a browser User-Agent, which often passes through edge filters that block Anthropic’s OAuth backend, giving you a false “healthy” result. For the deeper diagnostic walkthrough including dual-UA comparison, see the full curl diagnostic guide.

What did you see?

✅ JSON response with "issuer": "https://example.com"

JSON starting with {"issuer":"https://your-site.com","authorization_endpoint":"https://your-site.com/authorize",...} and the URLs match your actual domain. scopes_supported includes "mcp:full".

What this means

Your edge layer is fine and Royal MCP’s discovery is healthy from outside. If you’re still hitting a connection error, the problem is plugin-side — continue to Steps 1–4 below.

🛑 JSON, but "issuer" points to auth.example.com or another domain

JSON, but the issuer field references a subdomain like auth.your-site.com, OR scopes_supported includes openid / profile / email instead of mcp:full, OR endpoint paths have /oauth/ prefix (/oauth/authorize instead of /authorize).

What this means

Cloudflare Zero Trust Access is hijacking your OAuth discovery endpoint. Common when someone on your team set up a Cloudflare MCP Portal or Access app during MCP debugging — CF intercepts /.well-known/ and returns its own OIDC metadata, breaking Royal MCP’s OAuth flow. The fix is removal, not configuration.

Fix: Cloudflare Zero Trust hijacks MCP discovery
Delete the CF Access app + auth.* CNAME record. Step-by-step in the linked guide.

🛑 HTML response instead of JSON

You see <!DOCTYPE html> or <html> tags. Often a login page, paywall, access-denied page, or theme-styled error page.

What this means

A membership plugin (MemberPress, Restrict Content Pro, Paid Memberships Pro), security plugin, or theme template is intercepting /.well-known/oauth-authorization-server and returning a page instead of letting Royal MCP respond with JSON. Royal MCP 1.4.22+ auto-detects this and surfaces an admin notice.

Fix: OAuth discovery returns HTML instead of JSON
Identify and disable the intercepting plugin or template, or add a route exclusion.

🛑 403 Forbidden + Cloudflare branding (cf-ray header)

A 403 error page that mentions Cloudflare, shows a cf-ray reference ID, or says “Sorry, you have been blocked.” The 403 reproduces with curl -A "python-httpx/0.27.0" ... even if a browser UA gets through.

What this means

Cloudflare’s Bot Fight Mode, “Block AI Bots” toggle, AI Crawl Control, or a managed WAF rule is treating Anthropic’s OAuth backend as a bot and blocking it. Check all three CF panels (Security → Bots, Bot Fight Mode, and AI Crawl Control) — the first two being off does NOT mean CF isn’t blocking.

Fix: Cloudflare blocking Claude MCP OAuth
Add a CF WAF Skip rule for OAuth paths with the Bots checkbox ticked, or scope AI Crawl Control to exempt the OAuth endpoints.

🛑 406 Not Acceptable + “Mod Security” in the response body

A 406 error where the response body literally contains the phrase “Generally a 406 error is caused because a request has been blocked by Mod Security.” Reproduces with default curl headers.

What this means

cPanel ModSecurity is fingerprinting non-browser HTTP clients (Anthropic’s OAuth backend, scrapers, anything without the right header mix) and blocking them at the edge before WordPress sees the request. Common on InMotion, A2 Hosting, Bluehost, HostGator, GreenGeeks, Namecheap shared hosting.

Fix: ModSecurity 406 blocks MCP
Disable ModSecurity for the domain in cPanel, or open a hosting ticket for path-based exclusion on the OAuth endpoints.

🛑 429 Too Many Requests — persistent, not rate-related

A 429 error with a plain “Too Many Requests” body. Reproduces consistently with curl -A "python-httpx/0.27.0" ..., but returns 200 with curl -A "Mozilla/5.0" .... The 429 persists across multiple requests minutes apart (not a burst rate limit).

What this means

Your Apache shared host (managed-WordPress providers running Imunify360, mod_security with UA-fingerprint rules, or similar bot-defense layers) is returning 429 specifically for non-browser User-Agents — including Anthropic’s OAuth backend. The fix is host-side: you can’t configure your way out of this from inside WordPress.

Fix: Apache host blocking python-httpx with 429
Open a hosting ticket asking for UA whitelist OR path-based exclusion for the OAuth endpoints. Paste-ready ticket text in the linked guide.

🛑 404 Not Found

A 404 error. The URL appears to not exist at all.

What this means

Three possibilities, in order of likelihood:

  1. SiteGround (and some Hostinger, o2switch) nginx is blocking the .well-known/ path prefix. Most likely if you’re on SiteGround. SiteGround /.well-known/ 404 fix →
  2. Royal MCP is not active on this site. Check WP Admin → Plugins to confirm Royal MCP is installed and activated.
  3. WordPress rewrite rules need flushing. Go to WP Admin → Settings → Permalinks and click Save Changes (no actual changes needed; the save action regenerates rewrite rules).

🛑 301 Moved Permanently or 302 Found redirect

The response is a redirect (usually to a URL with a trailing slash, like /.well-known/oauth-authorization-server/).

What this means

Your web server is adding a trailing slash via canonicalization. OAuth clients don’t follow redirects on POST requests, so registration and token exchange break silently even though the discovery path is technically reachable. Royal MCP 1.4.22+ auto-detects this and surfaces an admin notice.

Fix: Trailing-slash 301 redirect on OAuth endpoints
Disable trailing-slash canonicalization in nginx mod_dir, Apache mod_dir, or .htaccess.

🤷 Something else — timeout, empty response, or unclear status

The curl command times out, returns nothing, returns a status code not listed above, or shows a response you can’t match to any of the patterns.

What this means

Could be a basic connectivity issue (DNS, expired SSL certificate, hosting outage), an unusual edge configuration, or a transient hiccup. Continue to Steps 1–4 below to narrow it down. If you’re still stuck after the plugin-layer pass, the diagnostic output from Steps 1–4 is what our support process needs to triage further.

Want a deeper diagnostic walkthrough?

For a more thorough probe sequence (testing /register, /wp-json/royal-mcp/v1/mcp, dual-UA comparison, response header inspection), see the full curl-based MCP diagnostic guide. Useful if you’re a developer or want to understand exactly what each OAuth step is doing.

Steps 1–4 — Plugin-Layer Diagnostic Checklist

Run these steps only after Step 0 above returns the healthy “JSON with matching issuer” response — or if Step 0 gave you a result that didn’t match any of the patterns. If Step 0 surfaced a specific edge-layer issue, click through to that fix instead; the plugin-layer steps below won’t help with edge-blocking.

Update Royal MCP to the latest version

In wp-admin go to Plugins → Installed Plugins, locate “Royal MCP”, and click Update if a newer version is available. Why first: every recent release has shipped meaningful OAuth diagnostics and edge-case fixes that change what you’ll see in later steps.

  • 1.4.13+ — OAuth endpoints send no-cache headers so edge caches stop poisoning them with stale responses
  • 1.4.14+ — OAuth discovery (claude.ai web / ChatGPT) probes get the correct 401 + WWW-Authenticate response instead of a 405
  • 1.4.15+ — API key Regenerate button actually works; MCP sessions use a 24-hour sliding TTL instead of expiring at exactly 1 hour
  • 1.4.16+every OAuth failure writes a structured row to the Activity Log, which is what Step 4 below relies on

Most pre-1.4.16 issues that look like host problems are actually fixed by the update alone.

Run a conflict test (plugin / theme / cache)

This single step resolves the majority of remaining tickets. Don’t skip it — even if you’re certain it isn’t a conflict. We see “I already tried that” very often, and “tried similar” isn’t the same as “ran these exact steps in order.”

(a) Deactivate ALL other plugins except Royal MCP. WordPress → Plugins → check the box at the top of the list, choose Deactivate from the bulk action menu, but uncheck Royal MCP first.

(b) Switch to a default theme. Appearance → Themes → activate Twenty Twenty-Five (or any unmodified default theme). Custom themes sometimes register their own URL rewrites or rewrite filters that interfere with our OAuth endpoints.

(c) Purge every cache. Three layers, all of them:

  • WordPress-side — if you use a cache plugin (LiteSpeed Cache, WP Rocket, W3 Total Cache, SpeedyCache, Hummingbird, etc.), purge it. If LiteSpeed is active, also flush the object cache.
  • Server-level — SiteGround Optimizer, Kinsta cache, WP Engine cache, Liquid Web cache, Cloudways Varnish — purge in your hosting control panel. Many managed hosts have their own cache layer separate from any plugin.
  • Cloudflare / CDN — if you use Cloudflare, purge everything. While you’re there, check whether “Block AI Bots” is enabled in Security → Settings — if it is, turn it off (this single setting breaks MCP for many users; see Step 5 below if disabling it isn’t enough). Also check “Bot Fight Mode” — same issue.
  • Browser cache — Cmd/Ctrl+Shift+R to hard-reload the relevant Claude page.

(d) Retry the connection. If it now works, the conflict was one of the deactivated plugins or the theme. Reactivate plugins one at a time, retrying after each, until it breaks — that’s your culprit. The most common offenders we see, in rough order:

  • Security plugins — Wordfence, Defender Pro, Solid Security (formerly iThemes Security), All In One WP Security & Firewall, NinjaFirewall. These intercept and sometimes block POST requests to the MCP endpoint and OAuth paths. Allowlist /wp-json/royal-mcp/*, /register, /token, and /authorize in the plugin’s firewall rules to unblock.
  • Caching plugins — LiteSpeed Cache and SpeedyCache running together is a confirmed reproducer of OAuth auth-code eviction. Add cache exclusions for the same paths.
  • Login/registration plugins — MemberPress, Paid Memberships Pro, Restrict Content Pro, Ultimate Member, Profile Builder. These can register a page with slug register that wins URL routing over our OAuth endpoint.
  • Custom theme functions — rare, but custom themes that filter rewrite_rules_array can deregister our endpoints.

Wipe stale OAuth state

Prior connection attempts leave behind client registrations, tokens, and authorization codes that can interfere with a fresh test. Wipe them.

On Royal MCP 1.4.17 or newer (one click):

Go to Royal MCP → Settings and click the Reset OAuth State button near the bottom of the page. Confirm in the modal. Done.

On Royal MCP 1.4.16 or older (database queries):

The Reset OAuth State button doesn’t exist yet. Run these queries via phpMyAdmin, your host’s database manager, or SSH (wp db query if you have WP-CLI):

DELETE FROM wp_royal_mcp_oauth_clients;
DELETE FROM wp_royal_mcp_oauth_tokens;
DELETE FROM wp_options WHERE option_name LIKE '_transient_royal_mcp_authcode_%';
DELETE FROM wp_options WHERE option_name LIKE '_transient_timeout_royal_mcp_authcode_%';
Custom table prefix?

Some hosts (managed-WordPress, hardened installs) randomize the wp_ prefix. Open wp-config.php and check the $table_prefix line — if it’s anything other than wp_, substitute it in all four queries above before running them.

Then on the Claude side:
  • In Claude (web or Desktop), delete the existing Royal MCP connector.
  • Wait 30 seconds. Claude.ai caches its own discovery state for a short window.
  • Re-add the connector from scratch. This forces a full OAuth flow rather than reusing the cached (and now invalid) client credentials Claude was holding.

If the connection works after this step, the issue was stale OAuth state. You’re done.

Check the Activity Log

If steps 1–3 didn’t resolve it, this step tells us (and you) exactly which validation rule is firing — or whether the request is reaching your WordPress install at all.

In wp-admin go to Royal MCP → Activity Logs. Reproduce the failed connection attempt — click Connect in Claude, watch it fail, then come back to the Activity Log page and refresh.

If there’s a recent row whose action starts with oauth:

Click View Details. The panel shows the OAuth error code and error_description — for example:

  • invalid_grant: Authorization code is invalid, expired, or already used. — usually means object cache (LiteSpeed + SpeedyCache) is evicting the auth code between /authorize and /token. Fix in Royal MCP 1.4.17.
  • invalid_grant: PKCE verification failed. — usually means a security plugin is URL-decoding the POST body. Disable security plugins per Step 2.
  • invalid_grant: redirect_uri mismatch. — Claude’s stored redirect URI doesn’t match what was registered. Wipe OAuth state per Step 3 and try again.
  • invalid_client — client_id Claude is sending isn’t in our database. Wipe OAuth state per Step 3.
  • invalid_request: Missing required parameters — something is stripping POST fields between Claude and your WordPress. Almost always a security plugin or WAF.
If the Activity Log is empty after a reproduced failure

That’s diagnostic on its own. It means the request never reached your WordPress PHP code — the failure is happening at the host edge, in a cache layer, or inside a security plugin’s firewall (before our code runs). Step 5 below lists the most common stack-specific culprits.

Additional Stack-Specific Articles

The full library of Royal MCP fix articles — including the ones Step 0 above routes to plus several others for specific situations Step 0 doesn’t cover (managed-host cache poisoning, SiteGround Content-Type issues, the static OAuth client setup trap, and the Claude Desktop API-key bypass).

If you arrived here from Step 0 above, the relevant article is already linked there — this section just lists everything in one place. If you completed Steps 1–4 and the connection still fails, browse below for your specific stack or symptom.

Cloudflare “Block AI Bots” breaks MCP
Symptom: OAuth completes in the browser, then claude.ai shows “Authorization failed” with an ofid_ code. Cause: Cloudflare blocking Anthropic’s backend IPs at the edge.
OAuth fails on managed hosts (edge cache poisoning)
Symptom: OAuth endpoints return stale 4xx responses. Activity Log empty. Hosts: o2switch PowerBoost, SiteGround Dynamic Cache, LiteSpeed Cache, Cloudflare APO.
SiteGround /.well-known/ returns 404
Symptom: /.well-known/oauth-authorization-server 404s. Cause: SiteGround nginx reserves the .well-known/ path prefix for ACME and blocks everything else. Also affects some Hostinger and o2switch configurations.
SiteGround serves .well-known/ as text/plain
Symptom: You’ve placed static .well-known/ files and they return 200, but strict MCP clients still reject because the Content-Type is wrong. Fix via a Cloudflare Transform Rule.
OAuth discovery returns HTML instead of JSON
Symptom: /.well-known/oauth-authorization-server returns 200 but the body is an HTML page (often a login or access-denied screen). Cause: a membership plugin or theme template is intercepting the request. Auto-detected by Royal MCP 1.4.22+.
Web server 301-redirects /register to /register/
Symptom: POST to /register returns a 301 redirect with a trailing slash. OAuth clients don’t follow 301 on POST, so registration silently fails. Cause: Nginx mod_dir, Apache mod_dir, or .htaccess canonicalization. Auto-detected by Royal MCP 1.4.22+.
ModSecurity returns 406 (InMotion, A2, Bluehost, HostGator)
Symptom: Activity Log stays empty no matter what. A curl from outside against any URL on your site returns 406 Not Acceptable with a literal “Mod Security” phrase in the response body. Cause: cPanel ModSecurity rules fingerprint non-browser HTTP clients and block Anthropic’s backend before requests reach WordPress. Fix: disable ModSecurity for the domain in cPanel, or open a hosting ticket for path-based exclusion.
“invalid_client: Unknown client_id” on a wp_* static OAuth client
Symptom: Activity Log shows an oauth:authorize row with client_id: wp_... and the error invalid_client: Unknown client_id at /authorize. Claude.ai surfaces this as “Authorization with the MCP server failed”. Cause: you used the Generate button in Royal MCP → Settings → Advanced but didn’t click Save Settings before copying the value into Claude.ai — the generated value lives in your browser only until Save is clicked. Fix: re-generate, click Save Settings, retry. Or switch to auto Dynamic Client Registration entirely (no setup gap).
Bypass OAuth entirely (Claude Desktop)
If your host stack is genuinely incompatible with OAuth, Claude Desktop can connect via a static API key header instead of OAuth. Two-line config change, no /.well-known/ discovery required.

Still Stuck? Two Support Paths

If you’ve worked through Step 0, the relevant stack-specific article it pointed you to, and Steps 1–4 above, and the connector still fails, you have two options for further help:

Community Support (free) — wp.org Plugin Forum

Post a new thread at wordpress.org/support/plugin/royal-mcp/. The Royal Plugins team checks the forum regularly and other community members — including hosting providers and developers who’ve hit the same issues — often answer faster than email could. This is the right path if you’re not on a deadline.

Premium Support (paid) — direct one-on-one help

For priority response (24-hour SLA), direct email access, and hands-on diagnostic help, our Premium Support tier is $149/year. Useful if you’d rather have us walk you through the fix, you’re on a deadline, or your stack is genuinely complicated (Cloudflare + custom WAF + edge cache combinations). Includes a 30-day “if it breaks again” follow-up window on every resolved ticket.

What to include in your post or ticket (either path)

  • Your hosting provider (SiteGround, Cloudways, Hostinger, Kinsta, WP Engine, Liquid Web, self-hosted VPS, etc.)
  • Royal MCP version from WP Admin → Plugins (please be on 1.4.16 or newer — older versions don’t produce the Activity Log entries we need)
  • Active caching plugins (LiteSpeed Cache, WP Rocket, W3 Total Cache, SpeedyCache, Hummingbird, none)
  • Active security plugins (Wordfence, Defender Pro, Solid Security, NinjaFirewall, none)
  • Cloudflare or CDN in front of the site? If yes, is “Manage AI Bots” or “Bot Fight Mode” on?
  • Which Claude client — claude.ai web custom connector, Claude Desktop with mcp-remote, ChatGPT MCP, or another MCP-compatible client
  • The exact error message you see, plus any ofid_xxxxx reference code if claude.ai shows one
  • Screenshot of the most recent oauth: row in your Activity Log with View Details expanded (or confirmation that the log is empty after a reproduced failure)
  • Your Step 0 curl output (the response pattern from the edge probe above) plus which steps you ran from the 4-step checklist and what changed at each