# OAuth Discovery Returns HTML Instead of JSON

> Royal MCP OAuth discovery at /.well-known/oauth-authorization-server returns HTML instead of JSON when a membership plugin or theme intercepts it. The fix.

- Canonical: <https://royalplugins.com/support/royal-mcp/well-known-served-as-html/>
- HTML version: <https://royalplugins.com/support/royal-mcp/well-known-served-as-html/>

---

Royal MCP’s admin self-check flagged that `/.well-known/oauth-authorization-server` is returning an HTML document at HTTP 200 instead of the JSON metadata MCP clients expect. A membership plugin, theme template, or restricted-content rule is intercepting the request and serving its own login or access-denied page. Claude.ai and other discovery-aware MCP clients fail silently when they receive HTML on this URL. This page walks through identifying the culprit and three fixes that don’t require uninstalling anything.

⚠️ Wrong page if your response is JSON (not HTML)

This doc covers the case where `/.well-known/oauth-authorization-server` returns **HTML** (a login page, access-denied screen, or theme template). If your discovery endpoint returns **JSON** but the `issuer` field points to an `auth.<subdomain>` instead of your site root — or the `scopes_supported` includes `openid` / `profile` / `email` — that’s a different pattern (Cloudflare Zero Trust hijacking discovery) with a different fix.

→ [**Cloudflare Zero Trust is hijacking MCP discovery →**](https://royalplugins.com/support/royal-mcp/cloudflare-zero-trust-shadows-mcp-discovery/)

### Detected by Royal MCP 1.4.22

This admin notice was added in Royal MCP 1.4.22. The self-check probes your discovery URL every 12 hours and classifies the response. If you arrived here from the admin notice link, the plugin has already confirmed your response is HTML (not JSON) — jump straight to the [Three Fixes](#fix) section.

## Confirm What’s Happening

From any terminal on your local machine, run:

**Mac Terminal, Linux, Windows Command Prompt, Git Bash:**

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

**Windows PowerShell:** (PowerShell aliases `curl` to `Invoke-WebRequest` with different syntax — use `curl.exe` to bypass the alias)

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

You’re hitting **this** issue (HTML hijack) if the response is:

#### The Telltale Signature

- Status: **`HTTP/2 200`** (not 404, not 301)
- Body: starts with `<!DOCTYPE html>`, `<html>`, or `<head>` — an HTML document, not JSON
- Body content: typically a login page, access-denied notice, password prompt, or your site’s 404 template
- Headers: may include cookies like `armember_*`, `mepr_*`, `rcp_*`, `wp-postpass_*`, or a session cookie set by your theme

If the response is JSON instead of HTML

You’re looking at a different issue. Check the `issuer` field in the JSON:

- If `issuer` matches your site root (`https://your-site.com`) and `scopes_supported` is `["mcp:full"]` — discovery is healthy. The connection failure is elsewhere. See the [troubleshooting start-here page](https://royalplugins.com/support/royal-mcp/troubleshooting-start-here/).
- If `issuer` points to `auth.<sub>` or `scopes_supported` includes OIDC scopes (`openid`, `profile`, `email`) — Cloudflare Zero Trust Access is intercepting your discovery endpoint. See [Cloudflare Zero Trust hijacks MCP discovery](https://royalplugins.com/support/royal-mcp/cloudflare-zero-trust-shadows-mcp-discovery/) for the fix.

## Why This Happens

Royal MCP registers a top-level rewrite rule mapping `/.well-known/oauth-authorization-server` to its OAuth metadata handler. The rule resolves at the WordPress rewrite layer, and the handler returns JSON. That’s the working path.

But several classes of plugins and themes hook earlier than the OAuth handler and short-circuit the response before it runs:

- **Membership plugins** (ARMember, MemberPress, Restrict Content Pro, Paid Memberships Pro, MemberMouse, Ultimate Member, Restrict User Access, BuddyBoss) hook `template_redirect` or `parse_request` with an “is this user allowed to see this URL?” check. If the default policy is “deny everything except an allowlist”, OAuth discovery URLs get caught.
- **Restricted-content themes** with global page-locks (often configured in the Customizer or a theme options panel) do the same check via a theme template.
- **Coming-soon and maintenance-mode plugins** (SeedProd, WP Maintenance Mode, Underconstruction Page) replace the entire frontend response with their own page regardless of URL.
- **Custom rewrite rules** added by another plugin or by your theme’s `functions.php` can take priority over Royal MCP’s rules. Re-saving Permalinks reshuffles priorities.

In all cases the symptom is the same: discovery clients ask for JSON, get HTML, and fail silently without a clear error message.

## Three Fixes

Try them in order. Fix #1 is the cheapest. Fix #3 narrows down the culprit if the first two don’t resolve it.

#### Fix #1 — Add OAuth paths to your membership plugin’s unrestricted-URL list

Almost every membership plugin has an “Excluded URLs” or “Bypass Pages” setting. The five Royal MCP paths to allow are:

```
/.well-known/oauth-authorization-server
/.well-known/oauth-protected-resource
/authorize
/token
/register
```

Add each as an exact match or a wildcard pattern depending on what the plugin supports. Save the setting and re-test with the `curl` command above.

Plugin-specific paths to the setting:

- **ARMember** → ARMember → Plugin Configuration → *Login* tab → “Restrict Pages” or “Page Restriction” section
- **MemberPress** → MemberPress → Settings → *Pages* tab → “Unauthorized Access” section
- **Restrict Content Pro** → Restrict → Settings → *Misc* tab → “Exempted URLs” or “Excluded URIs”
- **Paid Memberships Pro** → Memberships → Settings → *Advanced* tab
- **BuddyBoss** → BuddyBoss → Settings → *Pages* tab → Login redirect settings

#### Fix #2 — Re-save Permalinks to flush rewrite rules

WordPress rewrite rules are cached, and the order they evaluate in can be reshuffled by plugin activations and deactivations. Re-saving forces a fresh build and gives Royal MCP’s rules a clean priority.

Go to **WP Admin → Settings → Permalinks** and click **Save Changes** without changing anything else. Then re-test with the `curl` command above.

If you’re using a custom permalink structure

Royal MCP’s rewrite rules work on every standard permalink structure (Post name, Day and name, Month and name, Numeric, Custom Structure starting with `/%postname%/`). The Plain permalink structure (no rewriting at all) is the only configuration where these rules can’t be registered — switch to Post name if you’re currently on Plain.

#### Fix #3 — Bisect the culprit by deactivating suspects

If Fixes #1 and #2 don’t resolve it, identify which plugin is intercepting by deactivating candidates one at a time and re-running the `curl` test after each. Start with:

1. Membership / access-control plugins
2. Coming-soon / maintenance-mode plugins (these are often forgotten and left active in “authenticated bypass” mode that doesn’t bypass for non-browser requests)
3. Security plugins with custom WAF rules
4. Any other plugin whose name contains “Restrict”, “Lock”, “Private”, “Members”, “Force Login”, etc.
5. Your active theme — switch temporarily to **Twenty Twenty-Five** and re-test; if the issue disappears, your theme has a template-level page lock

Once identified, you have three options:

- Configure the plugin/theme to allow the OAuth paths (the equivalent of Fix #1 for non-membership plugins)
- If the plugin offers a per-URL filter hook, write a small must-use plugin that bypasses for OAuth URLs only
- Switch to a different plugin that handles allowlists more cleanly

## Verify the Fix Worked

After applying any of the three fixes:

1. Run the `curl` command from the top of this page again — the response should now be JSON starting with `{"issuer":"https://..."}`
2. In WordPress admin, go to **WP Admin → Royal MCP → Settings** and save the form (this invalidates the 12-hour self-check transient so the notice refreshes immediately)
3. Reload any Royal MCP admin page — the “OAuth discovery is being served as HTML” notice should no longer appear
4. Reconnect Claude.ai (or whichever MCP client was failing) — the OAuth handshake should now complete

## Still Stuck? Two Support Paths

If you’ve worked through all three fixes and the curl test still returns HTML:

### Community Support (free) — wp.org Plugin Forum

Post a new thread at [wordpress.org/support/plugin/royal-mcp/](https://wordpress.org/support/plugin/royal-mcp/). The Royal Plugins team monitors the forum regularly and community members often help disambiguate plugin conflicts faster than email could.

### Premium Support (paid)

For direct one-on-one help with 24-hour SLA, see [Premium Support](https://royalplugins.com/premium-support/) ($149/year).

#### Information to include (either path)

- The full `curl -i` output for `/.well-known/oauth-authorization-server` (headers AND body, redacted if your error page contains sensitive content)
- Your active theme name
- Your list of active plugins (WP Admin → Plugins → copy/paste the list)
- Royal MCP version (must be 1.4.22 or newer for the self-check to apply)
- Whether the issue persists after switching to Twenty Twenty-Five and disabling all non-essential plugins

## Related discovery-layer issues

If the curl above showed a response shape this doc doesn’t cover:

[Cloudflare Zero Trust hijacks discovery

Discovery returns JSON but `issuer` points to `auth.<sub>`, or scopes include `openid` / `profile` / `email`.](https://royalplugins.com/support/royal-mcp/cloudflare-zero-trust-shadows-mcp-discovery/)
[SiteGround returns 404 for `/.well-known/`

Discovery returns 404 instead of HTML or JSON. SiteGround nginx reserves the `.well-known/` path prefix.](https://royalplugins.com/support/royal-mcp/siteground-well-known-404/)
[Full curl diagnostic walkthrough

The complete 4-probe sequence with dual-UA testing — useful if you’re not sure which discovery issue applies.](https://royalplugins.com/support/royal-mcp/diagnose-mcp-with-curl/)

[Back to Troubleshooting Start Here](https://royalplugins.com/support/royal-mcp/troubleshooting-start-here/)
[Royal MCP Support Hub](https://royalplugins.com/support/royal-mcp/)
