OAuth Authorization Fails on Managed Hosts (SiteGround, o2switch, LiteSpeed)
If Claude.ai, Claude Desktop, or another MCP client returns “Authorization with the MCP server failed” immediately after you click “Authorize”, your host’s edge cache is almost certainly poisoning the OAuth endpoints. This is a known managed-hosting quirk and the fix is a few cache-exclusion rules.
Symptoms
You probably have this issue if all of the following are true:
The Telltale Signs
- You added Royal MCP as a connector in Claude.ai (or another MCP client) and the authorization window opened correctly with the “Authorize” button
- Within a second of clicking “Authorize”, the client returns “Authorization with the MCP server failed” (or “Couldn’t reach the MCP server”)
- You’ve already tried regenerating credentials, removing Cloudflare from the domain, reconnecting the connector multiple times, or creating a custom Bearer-Token connector — none worked
- The MCP endpoint visibly responds to manual HTTP requests (a curl POST returns JSON), so it doesn’t feel like the plugin is broken
- A
curl -Ion an OAuth endpoint shows cache-hit headers (x-cache: HIT,x-sg-cache: HIT,x-litespeed-cache: hit, etc.), confirming the response is being served from a cache layer in front of WordPress
An empty WP Admin → Royal MCP → Activity Log is expected behavior regardless of whether OAuth is succeeding or failing — the Activity Log captures only the legacy REST endpoints (/posts, /pages, /media, etc.) and does not currently log OAuth events or requests to the modern MCP JSON-RPC endpoint. We’re closing this gap in a future release. For diagnosing cache poisoning, use the curl headers test in the next section — cache-hit headers on OAuth endpoints are the actual smoking gun.
How to Verify It’s This Specific Issue
Two quick checks will confirm the cache hypothesis before you change anything.
Check for cache headers on the OAuth discovery endpoint
From any terminal, run:
curl -I https://YOUR-DOMAIN.com/.well-known/oauth-authorization-server
Look at the response headers. If you see any of x-cache: HIT, x-proxy-cache: HIT, x-sg-cache: HIT, x-litespeed-cache: hit, or a cf-cache-status: HIT, your host’s cache layer is sitting on top of the OAuth endpoints. That’s the smoking gun.
Confirm with a cache-busted POST
This forces a cache miss by adding a unique query string and a no-cache request header:
curl -v -X POST "https://YOUR-DOMAIN.com/register?_=$(date +%s)" \
-H "Content-Type: application/json" \
-H "Cache-Control: no-cache" \
-d '{"client_name":"Test","redirect_uris":["https://claude.ai/api/mcp/auth_callback"],"grant_types":["authorization_code"],"response_types":["code"],"token_endpoint_auth_method":"none"}'If this returns 201 Created with a client_id in the body, but your normal Claude.ai connector still fails, the cache layer is differentiating cache-busted requests from normal ones — the diagnosis is confirmed.
The Fix — Per-Host Cache Exclusions
Royal MCP 1.4.13 sends Cache-Control: no-store, no-cache, must-revalidate on every OAuth response, which is correct per RFC 7234. Some host edge caches still ignore those headers on URLs that match their cacheable-path regex, so we need to exclude the OAuth endpoints explicitly. Pick the section that matches your host.
Option A: SiteGround (SG Optimizer)
Open SG Optimizer’s Dynamic Cache settings
WP Admin → SG Optimizer → Caching → Dynamic Cache. Scroll down to the Exclude URLs from Caching field.
Add the Royal MCP OAuth paths
Paste these patterns, one per line:
/wp-json/royal-mcp/* /.well-known/oauth-authorization-server /.well-known/oauth-protected-resource /authorize /token /register
Click Save Changes. The last three paths (/authorize, /token, /register) are the actual OAuth handshake endpoints — missing them is the most common reason a cache-exclusion fix appears to do nothing.
Purge the cache and retry the connector
Click Purge SG Cache in the SG Optimizer toolbar (or under Caching → Dynamic Cache). Then retry the Claude.ai authorization. Re-run the curl headers test from the Verify section to confirm cache-hit headers are gone on the OAuth endpoints.
If exclusions in SG Optimizer aren’t enough, also check Site Tools → Speed → Caching → Dynamic Cache at the hosting-panel level (separate from the WordPress plugin), and toggle Dynamic Cache off temporarily to confirm the diagnosis. You can re-enable it once exclusions are in place.
SiteGround has two separate issues on top of caching that often need to be addressed together:
- nginx blocks
/.well-known/*. Their nginx layer reserves the path for ACME SSL renewals and returns a static 404 for everything else — before WordPress sees the request. Fix: drop two static OAuth metadata files in webroot. See SiteGround Returns 404 for /.well-known/. - nginx serves the static files as the wrong Content-Type. Strict MCP clients (Claude Desktop’s
mcp-remote) reject metadata served astext/plain. Since SiteGround migrated to Google Cloud, they no longer make per-customer nginx changes, and.htaccess ForceTypeis silently ignored on these paths. Fix: a free Cloudflare Transform Rule rewrites the response Content-Type at the edge. See Fix /.well-known/ Content-Type with a Cloudflare Transform Rule.
Option B: LiteSpeed Cache plugin
Open the LiteSpeed Cache exclusions panel
WP Admin → LiteSpeed Cache → Cache → Excludes tab.
Add the OAuth paths to “Do Not Cache URIs”
Paste these into the Do Not Cache URIs field, one per line:
/wp-json/royal-mcp/ /.well-known/oauth-authorization-server /.well-known/oauth-protected-resource /authorize /token /register
Click Save Changes, then LiteSpeed Cache → Toolbox → Purge All.
Option C: Cloudflare (APO or aggressive page rules)
Add a Cache Rule that bypasses cache for the OAuth paths
In the Cloudflare dashboard for your domain: Caching → Cache Rules → Create rule. Set the rule to match URI Path containing any of the OAuth paths and set Cache eligibility to Bypass cache.
(starts_with(http.request.uri.path, "/wp-json/royal-mcp/")) or (starts_with(http.request.uri.path, "/.well-known/oauth-authorization-server")) or (starts_with(http.request.uri.path, "/.well-known/oauth-protected-resource")) or (http.request.uri.path eq "/authorize") or (http.request.uri.path eq "/token") or (http.request.uri.path eq "/register")
Purge everything and retry
Caching → Configuration → Purge Everything. Then retry the Claude.ai authorization.
If your domain is proxied through Cloudflare, fixing the cache isn’t enough on its own. Cloudflare’s built-in Manage AI bots managed rule blocks Anthropic’s backend IP ranges by default, which prevents the server-to-server token exchange even after your cache rules are correct. Symptom: Claude reports “Couldn’t reach the MCP server” and your Royal MCP Activity Log stays empty. Fix: a Custom WAF Rule that skips managed rules for the Royal MCP and OAuth paths only. Full walkthrough at Allow Anthropic Through Cloudflare’s AI Bots Rule. Background on the underlying mechanism.
Option D: o2switch (PowerBoost)
PowerBoost is configured at the hosting-account level and most users can’t edit its rules directly. Open a ticket with o2switch support and ask them to exclude the following paths from PowerBoost edge caching:
/wp-json/royal-mcp/* /.well-known/oauth-authorization-server /.well-known/oauth-protected-resource /authorize /token /register
If they push back, the alternative is to disable PowerBoost on the affected domain entirely. Both options have resolved this for previous customers.
Option E: Other (Varnish, NGINX FastCGI, Squid, etc.)
If you run your own reverse-proxy cache, add a bypass rule for the same path patterns above. The general shape is “never cache anything matching /wp-json/royal-mcp/* or /.well-known/oauth-*, regardless of HTTP method.” Once that rule is in place and the cache is purged, OAuth flows will start hitting WordPress correctly.
Why Does This Happen?
OAuth 2.0 endpoints handle a mix of GET (discovery, redirect handoff) and POST (token exchange, dynamic client registration) requests on the same URL. RFC 7234 says caches should only store responses where the origin server has explicitly marked them cacheable, and they should key cache entries by URL and by request method.
Some aggressive edge caches don’t do that. When a security scanner, browser preview, or stale Claude.ai discovery probe sends a GET to /register and receives a 405 Method Not Allowed, the cache treats that 405 as “the response for this URL” and stores it — ignoring the method. Every subsequent POST to the same URL gets the cached 405 served back to it instantly, never reaching PHP. That’s why the cache-busted POST in the Verify section returns a clean 201 Created while the connector flow keeps failing — the OAuth handshake is colliding with a cached error response.
Royal MCP 1.4.13 added Cache-Control: no-store, no-cache, must-revalidate + Pragma: no-cache headers on every OAuth response specifically to defeat this behavior. That fix works on most hosts, but a small number of edge cache configurations (notably SiteGround’s NGINX Dynamic Cache and o2switch PowerBoost) ignore origin-supplied Cache-Control on URLs matched by their internal cacheable-path regex. For those, the customer-side URL exclusion above is the only reliable fix.
If you’ve confirmed the diagnosis with the curl test in the “Verify” section above and the OAuth endpoints are clearly being cached despite the no-store headers, the fix has to live at the cache-configuration layer. Royal MCP can’t override an upstream cache that decides to ignore origin headers — only excluding the URL from caching, or disabling the cache, will work.
Quick Alternative: Skip OAuth on Claude Desktop
If you’re only trying to connect Claude Desktop (not Claude.ai web) and the cache exclusions aren’t getting you over the line, you can bypass OAuth entirely. Royal MCP supports API key authentication via mcp-remote’s --header flag, which doesn’t use /.well-known/ at all and is unaffected by edge-cache or WAF behavior on the OAuth endpoints.
It’s a two-line change to your Claude Desktop config — full walkthrough at Connect Claude Desktop via API Key (Skip OAuth).
OAuth is still required if you need Claude.ai web (browser-based) connector support, but for desktop usage the API key path is the most reliable fallback when host configuration is fighting you.
Still Stuck After Adding the Exclusions?
If you’ve added the exclusions, purged the cache, the curl headers test no longer shows cache-hit responses on OAuth endpoints, and the connector still fails, contact support@royalplugins.com with the following:
Information We’ll Need
- Your hosting provider (SiteGround, o2switch, Hostinger, etc.) so we can check whether we’ve seen this on that host before
- Royal MCP version from WP Admin → Plugins (must be 1.4.13 or newer for the bypass headers)
- Output of the curl headers test from the Verify section above — full response headers, not just the body
- Active caching plugins — output of
wp plugin list --status=activeif you have WP-CLI access, or a screenshot of the Plugins admin page filtered by “cache” - WAF / security plugins that might filter REST requests (Wordfence, iThemes Security, GuardPress, etc.)
- Whether you have Cloudflare in front of the domain, and if so whether APO is enabled
We respond to support emails within one business day, and we’ve resolved this on every host we’ve seen so far — the fix is almost always one cache-exclusion rule away.