WordPress Plugins
Free Tools
Pricing Blog Case Studies Switch to Royal Plugin Graveyard Support My Account Cart
Support / Royal MCP / BitNinja WebShield Blocks Royal MCP OAuth Discovery

BitNinja WebShield Blocks Royal MCP OAuth Discovery

If Claude, ChatGPT, or Cursor fails to connect to your Royal MCP endpoint and a direct curl against /.well-known/oauth-authorization-server returns an HTML page titled “One moment, please...” with an auto-reload script, your host is running BitNinja WebShield in front of WordPress. WebShield serves a JavaScript CAPTCHA challenge for these paths — MCP clients don’t execute JavaScript, so the OAuth handshake dies at discovery. Fix is at the hosting layer; no WordPress setting will resolve it.

Before applying this fix

Royal MCP connection issues that look host-specific are often a plugin conflict, cache layer, or stale OAuth state — work through our Troubleshooting Start Here checklist first if you haven’t already. This article assumes the basics are ruled out and the curl fingerprint below matches.

Often stacked on top of Imunify360

BitNinja WebShield and Imunify360 are both host-layer bot-protection products, and shared cPanel/CloudLinux hosts frequently run both. If your OAuth endpoints show HTTP 200 with an “Access denied by Imunify360” JSON body and `/.well-known/*` paths return the “One moment, please...” HTML page, you have both layers to clear — see the Imunify360 fix for the companion request.

Symptoms

You’re hitting this specific issue if the following are true:

The Telltale Signs

  • Claude.ai, ChatGPT, or Cursor fails to connect to your Royal MCP endpoint — often silently or with a reference code the client can’t explain
  • A curl against /.well-known/oauth-authorization-server returns HTTP 200 with a Content-Type: text/html body containing <title>One moment, please...</title> and an auto-reload setTimeout(function(){window.location.reload();}, 5000)
  • The HTML body includes obfuscated JavaScript that references wsidchk (a form parameter) and webdriverCheck (a bot-fingerprint function name)
  • Reproduces on ALL User-Agents — browser UAs, plain curl, python-httpx — the challenge fires unconditionally on the path
  • Royal MCP’s Activity Log (WP Admin → Royal MCP → Activity Log) stays empty for every failed connection attempt — the requests never reach WordPress
  • Your hosting provider is a shared cPanel host running CloudLinux — often layered on top of Imunify360
Why MCP clients can’t solve the challenge

BitNinja WebShield’s JavaScript CAPTCHA relies on a real browser executing the challenge script, setting a clearance cookie, and reloading the page. MCP clients (Claude, ChatGPT, Cursor) are headless HTTP clients — they don’t run a JavaScript engine, don’t maintain a browser cookie jar for challenge responses, and don’t reload. The response body they receive is HTML where they expected JSON, so the OAuth handshake aborts at discovery.

How to Confirm It’s BitNinja WebShield

A 30-second curl test confirms the signature. Run from any terminal — replace example.com with your actual domain:

Test your OAuth discovery URL

curl -i https://example.com/.well-known/oauth-authorization-server

The diagnostic fingerprint is HTTP 200 with Content-Type: text/html and a response body starting with:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0">
  <script>
      (function(){
          setTimeout(function(){
              window.location.reload();
          }, 5000);
      }())
  </script>
  <link rel="icon" href="data:,">
  <title>One moment, please...</title>

Grep the response body for BitNinja’s signature tokens

curl -s https://example.com/.well-known/oauth-authorization-server | grep -oE "wsidchk|webdriverCheck"

If both wsidchk and webdriverCheck appear in the output, you’re looking at BitNinja WebShield’s JS challenge. These tokens only co-occur in WebShield’s obfuscated fingerprinting script.

Confirm the block is path-based, not domain-wide

curl -I https://example.com/

Your site homepage should return HTTP 200 with normal WordPress output (no interstitial). This proves the intercept is scoped to specific paths — the rest of the site works normally.

Why the Activity Log stays empty

BitNinja WebShield sits in front of WordPress at the web-server layer, so denied requests never reach PHP and never register in the plugin’s Activity Log. An empty log combined with a Claude connection failure isn’t proof of WebShield by itself — but combined with the curl fingerprint above, it’s conclusive.

The Fix — Ask Your Host to Disable WebShield for the OAuth Paths

BitNinja WebShield runs at the hosting provider’s layer, not inside WordPress. The fix is a support ticket to your host asking them to exclude specific paths from WebShield (or disable WebShield for the whole domain). Most hosts complete this in under 24 hours — it’s a routine change on their end.

Ready-to-paste hosting-provider request

Copy the text below into a support ticket with your hosting provider. Substitute example.com with your actual domain:

Subject: Please exclude OAuth paths from BitNinja WebShield for example.com

Hi,

We’re running the Royal MCP WordPress plugin on example.com,
which lets AI assistants like Claude, ChatGPT, and Cursor
connect to our site via the Model Context Protocol (MCP).
The connection requires OAuth 2.0 discovery and token endpoints
to be reachable without a JavaScript challenge.

Right now BitNinja WebShield is intercepting these paths and
returning an HTML CAPTCHA page (title: “One moment, please...”)
with the wsidchk / webdriverCheck challenge script. MCP clients
don’t execute JavaScript, so the OAuth handshake dies at
discovery.

Please exclude the following URL paths for example.com from
BitNinja WebShield (or, equivalently, disable WebShield for the
whole domain):

  /wp-json/*
  /.well-known/*
  /authorize
  /token
  /register

Important: please use a path-based or domain-level exclusion,
NOT an IP allowlist. Claude.ai and other MCP client backends
connect from constantly-rotating IP ranges, so an IP-based rule
will silently break within a few weeks. Path or domain scope
is the correct mechanism.

These are standard WordPress REST API + OAuth 2.0 (RFC 8414)
endpoints. Excluding them from WebShield will not reduce
security — they are the plugin’s own authenticated
endpoints subject to WordPress’s standard capability checks.

Thanks in advance.
If your host asks “why can’t you just whitelist your IP?”

Claude.ai and Anthropic’s backend connect from constantly-rotating IP ranges. You can’t whitelist a fixed set of Anthropic IPs, so path-based exclusion is the correct approach. The paste-ready text above already explains this — point your host at this article if they need further convincing.

Retry the connection

Once your host confirms the exclusion is in place, the fix is immediate:

  1. Re-run the curl test from the “How to Confirm” section above. You should now see a normal OAuth metadata JSON response, not the HTML challenge page.
  2. In your MCP client, delete the existing Royal MCP connector if present, wait 30 seconds, then re-add it fresh. This forces the full OAuth flow from scratch rather than reusing cached failure state.
  3. Complete the authorize consent screen. Royal MCP’s Activity Log should now show entries the moment you click “Authorize.”

What NOT to Try (WordPress-Side Fixes Won’t Help)

BitNinja WebShield runs at the web-server layer, ahead of PHP. That means the following common troubleshooting steps will NOT resolve this issue — don’t waste time on them:

What Royal MCP 1.4.39 Already Does for You

Royal MCP 1.4.39 detects this exact failure mode automatically. When the plugin’s well-known-endpoint self-check sees an HTML response containing both wsidchk and webdriverCheck, it surfaces a dismissible admin notice on the Plugins screen and Royal MCP settings linking back to this page.

So future customers on hosts running BitNinja WebShield will land here from inside their own WordPress admin instead of having to search for “Royal MCP can’t connect” and stumble across the diagnosis. The plugin can’t auto-fix the block for you — WebShield is upstream of WordPress and the customer’s hosting-provider exclusion is the only mechanism — but the notice makes the diagnosis fast.

A caveat about the self-check

Royal MCP’s well-known probe runs from the site to itself (a WordPress-loopback HTTP request). Some WebShield configurations exclude loopback traffic and some don’t. If loopback is excluded but external traffic still gets the challenge, our self-check will see a valid metadata response and NOT trigger the notice — even though Claude (external) still can’t connect. If you see this pattern, run the curl tests in the “How to Confirm” section above from EXTERNAL to your site — those are the definitive diagnostic.

Still Stuck? Two Support Paths

If your host completed the allowlist and Claude still can’t connect:

Community Support (free) — wp.org Plugin Forum

Post a new thread at wordpress.org/support/plugin/royal-mcp/. Include the diagnostic info listed below in your post.

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

For priority response (24-hour SLA) and hands-on diagnostic help, our Premium Support tier is $149/year.

Information to include in your post or ticket

  • Full curl output for /wp-json/royal-mcp/v1/mcp and /.well-known/oauth-authorization-server BEFORE and AFTER your host applied the allowlist (use curl -i, not just -I, so we see the body)
  • Your hosting provider (SiteGround, Bluehost, HostGator, Namecheap, etc.) — helps us cross-reference known-good allowlist patterns for that host
  • Confirmation your host completed the allowlist (paste any confirmation email they sent)
  • Royal MCP version from WP Admin → Plugins
  • Whether the Activity Log now shows entries during a failed attempt (any entry means the request reached WordPress — different diagnosis)