WordPress Plugins
Free Tools
Pricing Blog Case Studies Switch to Royal Plugin Graveyard Support My Account Cart
Support / Royal MCP / Non-Standard 4xx on OAuth /register

ChatGPT’s MCP Connector Fails with HTTP 466 — Intermediary WAF Blocks OAuth /register

If ChatGPT’s MCP connector reports “Dynamic client registration failed: registration endpoint returned 466” (or 461, 462, 463, 465, 467, 468, 469 — anything in the 460–469 range) while Claude Desktop and Claude.ai web connect fine to the same URL, Royal MCP itself is not emitting the error. The plugin’s /register handler only ever returns 201, 400, 405, 429, or 500. Any status in the 460–469 range is being generated by a layer between the OAuth client and WordPress — a host-managed WAF, a CDN edge rule, a custom nginx directive, or ModSecurity with a non-default status-code override. The fix is a path-based exclusion at whichever layer is intercepting the Dynamic Client Registration POST.

Before applying these advanced steps

Royal MCP connection issues that look host-specific are usually a plugin conflict, cache layer, or stale OAuth state — about 90% resolve in our 4-step basic checklist. If you haven’t run through that yet, do it first — this article assumes the basics are already ruled out.

Signature Pattern: Claude Works, ChatGPT Fails

The distinguishing feature of this class is that Claude Desktop and Claude.ai web connect successfully to the same URL while ChatGPT’s connector fails at the OAuth registration step. Claude Desktop’s local bridge (mcp-remote, a Node.js client) and Claude.ai web’s server-side OAuth backend each send a distinct request signature — different User-Agent, different Dynamic Client Registration body shape. ChatGPT’s connector calls out from OpenAI’s OAuth backend with a python-httpx User-Agent and additional client-metadata fields in the DCR body. Some WAFs fingerprint the ChatGPT-flavored request and let the Claude ones through. If both Claude and ChatGPT fail on the same URL, the issue is upstream (edge cache, DNS, TLS, or a blanket block on the path) rather than shape-fingerprinting — see the basic checklist instead.

Before You Apply the Fix — Confirm This Is Your Issue

The specific error text ChatGPT surfaces is “Dynamic client registration failed: registration endpoint returned N”, where N is a value in the 460–469 range. That’s the leading fingerprint. The 60-second curl test below verifies whether an intermediary layer is actually emitting the code — because Royal MCP’s own handler doesn’t use those codes at all, the fact that you saw one means the response came from somewhere between the OAuth client and PHP.

This article applies to you if…

  • You’ve already run the 4-step basic checklist without resolving it
  • Claude Desktop and/or Claude.ai web connect successfully to your MCP URL — you can complete an OAuth flow and see tool calls in Royal MCP → Activity Log
  • ChatGPT’s MCP connector fails at the OAuth setup step with an error mentioning “Dynamic client registration failed” and a status code in the 460–469 range
  • You’re on a host where the response to a POST from the ChatGPT-style HTTP client is returned by an intermediary (managed WAF, CDN edge, ModSecurity with rule overrides, custom nginx limit_req_status)

Have these on hand before you start

You’ll need these to apply the fix below, and they’re what our support team needs if you end up emailing afterward:

  • Your exact hosting provider (the WAF layer varies by host, so the fix procedure differs)
  • Access to your host’s WAF configuration — either directly through a control panel or through their support team
  • Output of the curl test below — the response headers and body identify which layer emitted the code, and you’ll send this verbatim to your host if you need to open a ticket
  • Your Royal MCP version from WP Admin → Plugins (1.4.16 or newer for diagnostic-quality Activity Log entries)

Symptoms

The Telltale Signs

  • ChatGPT’s MCP connector fails with an error containing the phrase “Dynamic client registration failed: registration endpoint returned N, where N is in the 460–469 range (466 is the most common; we’ve seen 463 and 468 as well)
  • Claude Desktop or Claude.ai web connects to the same MCP URL without issue
  • Your Royal MCP → Activity Log shows entries for the working Claude connections but nothing corresponding to the failed ChatGPT attempts — because the request never reaches WordPress
  • Visiting the site in a browser works perfectly
Why the plugin’s own handler can’t emit these codes

Royal MCP’s /register route follows RFC 7591 (Dynamic Client Registration) and OAuth 2.0 conventions. The handler emits 201 Created on success, 400 Bad Request on an invalid body or unregistered redirect URI, 405 Method Not Allowed on non-POST requests, 429 Too Many Requests when its per-IP rate limiter fires, and 500 Internal Server Error only on genuine failures like a missing database table. Everything else — every 460–469 code, every HTML-body response, every custom “Access Denied” page — comes from a layer above WordPress in the request path.

How to Verify It’s This Specific Issue

One curl command from outside your site confirms the diagnosis and identifies which layer emitted the code. Run it from any terminal — macOS, Linux, Windows PowerShell, WSL all work. Don’t run it from inside your hosting account’s SSH; the test is checking what an outside HTTP client sees, so it has to come from outside your host.

Send a ChatGPT-shaped POST to /register with a python-httpx User-Agent

Replace example.com with your WordPress site’s domain:

curl -i -X POST \
  -H "Content-Type: application/json" \
  -H "User-Agent: python-httpx/0.27.0" \
  -d '{"redirect_uris":["https://chatgpt.com/connector_platform_oauth_redirect"],"client_name":"ChatGPT","token_endpoint_auth_method":"none"}' \
  https://example.com/register

The python-httpx User-Agent and the ChatGPT-flavored body shape (with token_endpoint_auth_method: "none" and the ChatGPT redirect URI) approximate what OpenAI’s OAuth backend actually sends. This is the shape most WAFs fingerprint.

Read the response — the headers and body tell you which layer emitted the code

If the diagnosis is correct, the response will start with a status line in the 460–469 range and the body will be HTML or plain text (never JSON — Royal MCP always emits JSON). The Server header and the body content together identify the layer:

  • server: openresty with an HTML body saying “Access Denied. Your request has been blocked by our web application firewall” → typical managed-host WAF page (confirmed on Websupport). The host’s edge WAF is intercepting the POST before it reaches your PHP.
  • server: nginx with a body mentioning a ModSecurity rule ID → ModSecurity with a custom SecRuleRemoveById action that overrides the default 403 to a 46x code. Common on cPanel shared hosts with a customized ruleset.
  • server: cloudflare or a cf-ray header on the response → Cloudflare is passing through a 46x from your origin (rare — CF itself rarely returns 46x). The origin-side WAF is still the source; the CF header is just proxied metadata.
  • server: Apache or Apache/PHP-FPM with a small text body → likely a security plugin or an .htaccess rule using a non-standard ErrorDocument status. Uncommon.
  • A plain server header with a hosting-vendor name (Imperva, Sucuri, AWS WAF, Newfold-brand hosts, etc.) → managed-host WAF. The customer-side fix always requires opening a hosting ticket.

Sanity-check with a browser User-Agent

Repeat the same POST with a browser-style User-Agent to confirm the WAF is fingerprinting by request signature, not blocking the path unconditionally:

curl -i -X POST \
  -H "Content-Type: application/json" \
  -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" \
  -d '{"redirect_uris":["https://example.com/cb"],"client_name":"diag"}' \
  https://example.com/register

If this returns 201 Created with a JSON body (the plugin’s own registration response), the fingerprint is confirmed — the WAF is treating the python-httpx request specifically as suspicious while letting a browser-shaped POST through. If both curl runs return the same 46x, the WAF has a blanket rule on /register and the fix is the same, just simpler to justify to your host.

Why Royal MCP’s Activity Log stays empty for the failed attempts

The intermediary WAF returns its response to the OAuth client without ever passing the request through to WordPress. There is no PHP execution, no plugin code path, no database write — nothing for the Activity Log to record. That’s why plugin-side debugging (deactivating other plugins, switching themes, resetting OAuth state) does nothing to change this behavior: you’re modifying what happens after a gate that’s already closed.

The Fix — Path-Exclude the OAuth Endpoints from the WAF Layer

The pattern is the same whichever WAF is intercepting the request: get the OAuth endpoints excluded from the layer that’s emitting the code. Which team applies the change depends on how much control your host gives you. Try Option A first; if you don’t have direct access to the WAF, jump to Option B.

Option A: Path-exclude the OAuth endpoints yourself (if you control the WAF)

Log into your host’s WAF configuration

The specific control varies: some hosts expose ModSecurity in cPanel under Security, some use their own dashboard (Cloudflare, Sucuri), some managed WordPress hosts hide it entirely. If you have direct access, add rule exclusions for the paths below. If you don’t, skip to Option B.

Add the OAuth endpoint paths to the WAF’s exclusion / bypass list

Every path that Royal MCP’s OAuth flow uses needs to be excluded:

/register
/authorize
/token
/.well-known/oauth-authorization-server
/.well-known/oauth-protected-resource
/wp-json/royal-mcp/*

The first three are the OAuth handshake endpoints — the ones most often fingerprinted by WAFs because they legitimately need to accept non-browser POSTs. The two /.well-known/ paths are OAuth discovery. The /wp-json/royal-mcp/* path is the MCP endpoint itself. Omitting any of these leaves a chance the WAF blocks a later step of the flow after the /register succeeds.

Retry the ChatGPT connector, then re-run the curl test

Reload the ChatGPT MCP connector setup, retry the connection, and check whether the DCR error is gone. Re-run the curl POST from the Verify section — you should now see a 201 Created with a JSON client-registration response body (or a 400 invalid_redirect_uri if the redirect URI in the test body isn’t HTTPS or localhost) instead of the 46x. Refresh Royal MCP → Activity Log; you should now see corresponding entries.

Option B: Open a hosting support ticket for path-based exclusion

If your WAF is managed by the host (Websupport, most managed-WordPress hosts, most shared cPanel plans where cPanel doesn’t expose the ModSecurity control), you’ll need to ask them to apply the exclusion. Send them this exact text:

Your web application firewall is returning HTTP status N (a value in the
460-469 range) on POST requests to /register on my WordPress site. The
plugin behind that endpoint (Royal MCP - RFC 7591 Dynamic Client
Registration for MCP OAuth) does not emit any status code in that
range - the response is coming from your WAF layer, not from PHP.

I need path-based exclusions from the WAF for the following OAuth
endpoints so my MCP integration can complete Dynamic Client
Registration:

  /register
  /authorize
  /token
  /.well-known/oauth-authorization-server
  /.well-known/oauth-protected-resource
  /wp-json/royal-mcp/*

Please also check the WAF audit log on my domain for the exact rule
(or rule set) that fired on POST /register with a python-httpx
User-Agent and let me know which rule triggered.

Most managed hosts respond within a few hours and apply the exclusion server-side. If they push back and ask you to whitelist the User-Agent instead, that’s a partial fix — it will work today, but if OpenAI ever updates their OAuth backend’s HTTP client (or changes its version string), the UA whitelist stops matching. Path-based exclusions on the OAuth endpoints are the durable fix.

Option C: Confirmed host walkthroughs

Websupport (openresty edge WAF, HTML “Access Denied” response)

Fingerprint: Response has server: openresty, content-type: text/html, status 466, and an HTML body containing the phrase “Access Denied. Your request has been blocked by our web application firewall.” No Cloudflare in front of the site and no WordPress security plugin installed.

Fix path: Websupport’s WAF isn’t exposed to customers directly — you’ll need to open a support ticket. Send them the canonical text from Option B above. Ask specifically for the WAF rule ID that triggered on the POST so you have a record of which rule was excluded, in case future rule updates re-introduce the block.

Other openresty-based managed hosts

The server: openresty header shows up on several European and Asian managed hosts. Whatever the vendor, if the response body is an HTML page with a generic “Access Denied by web application firewall” message and no obvious rule ID, that’s a managed-WAF layer. The fix follows the same pattern — open a support ticket with the canonical text.

cPanel with ModSecurity + custom rule action

If your response has server: nginx or server: Apache and mentions a rule ID like 942100 or 949110 in the body, ModSecurity is the emitter and someone (your host, or a control-panel default) has customized the block action to a 46x status. Follow the walkthrough at ModSecurity Returns 406 — the fix is the same, just applied through cPanel’s ModSecurity control.

Why Does This Happen?

The HTTP 4xx status range from 460 to 499 is officially unassigned in the IANA HTTP Status Code Registry. That leaves the range available for “intermediary” or “vendor-specific” uses, and several security and edge-network products have picked codes in that range for their own custom responses. nginx has a documented limit_req_status directive that accepts any 4xx code. Some WAFs let administrators override the default 403 block-action with any 4xx code they prefer, so their responses don’t collide with application-level 403 responses in log analysis. ModSecurity supports the same via custom SecAction directives.

Because the range is unassigned, most HTTP clients don’t have specific handling for these codes and just surface them as raw “server returned N” errors. OpenAI’s MCP connector does exactly this — it reports the numeric status verbatim in the error message, which is what you see in ChatGPT’s UI. That’s the smoking gun: Royal MCP never emits 466, so the OAuth client that surfaced “registration endpoint returned 466” had to have gotten the 466 from somewhere else.

Claude Desktop connects through mcp-remote, a Node.js bridge running locally on the user’s machine that talks to your MCP server directly. Claude.ai web goes through Anthropic’s server-side OAuth backend. ChatGPT’s connector goes through OpenAI’s server-side OAuth backend, which uses python-httpx with additional client-metadata fields specific to their integration. Some WAFs fingerprint the ChatGPT-flavored request specifically — typically because the exact combination of python-httpx User-Agent + OpenAI-shaped DCR body trips a rule that neither Claude path matches. That’s why the split behavior looks so strange: same URL, one OAuth client works, the other doesn’t.

Can Royal MCP handle this from the plugin side?

No — the WAF response is generated and sent to the OAuth client before the request ever reaches WordPress. Royal MCP’s code doesn’t execute, so it has no opportunity to detect or intercept the block. What the plugin does do is make the diagnostic easier: our internal support tooling (check-mcp.py, which our support team runs when triaging tickets) includes a Dynamic Client Registration POST probe that catches this class automatically. When you email support with the output of the curl test above, we can generally point you straight to the offending WAF layer.

Quick Alternative: Use Claude for MCP While You’re Waiting

If you need MCP working today and your host’s support team is going to take a few days to apply the exclusion, Claude Desktop and Claude.ai web are unaffected by this class of block. They complete OAuth successfully because their MCP client has a different HTTP signature. If your primary goal is having MCP working on your site — not specifically ChatGPT — connect Claude first, verify tool calls work, then follow up with your host on the WAF ticket to get ChatGPT working too.

Claude Desktop’s API-key path (which bypasses OAuth entirely) is documented at Connect Claude Desktop via API Key (Skip OAuth) — that’s the most robust connection method when WAF configuration is fighting you.

Still Stuck? Two Support Paths

If you’ve worked through the steps above and ChatGPT still fails to connect:

Community Support (free) — wp.org Plugin Forum

Post a new thread at wordpress.org/support/plugin/royal-mcp/. The Royal Plugins team monitors the forum regularly. Include the curl output from the Verify section — the response headers and body identify the WAF layer, and without that the reply loop is much slower.

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. Includes a 30-day “if it breaks again” follow-up window on every resolved ticket.

Information to include in your post or ticket

  • Your hosting provider — the WAF vendor and rule-set defaults vary by host
  • Royal MCP version from WP Admin → Plugins
  • The full curl -i output from the Verify section (both the python-httpx and browser User-Agent runs), including all response headers and the response body
  • The exact ChatGPT error message including the status code (466 / 463 / etc.)
  • Whether Claude connects successfully (this confirms Royal MCP itself is healthy and narrows the diagnosis to WAF fingerprinting)
  • Whether you’ve already contacted your host about the WAF, and if so, what they said
Related host-side OAuth failures

If the curl test does not show a 460–469 status — if you get a 403, 406, or 429 instead — then this isn’t your problem. Check the adjacent failure modes: