# Static OAuth Client Setup — the Generate Button + the Save Settings Step

> Royal MCP static OAuth credentials are not saved until you click Save Settings; skipping it causes 'invalid_client: Unknown client_id' on every attempt.

- Canonical: <https://royalplugins.com/support/royal-mcp/static-oauth-client-setup/>
- HTML version: <https://royalplugins.com/support/royal-mcp/static-oauth-client-setup/>

---

Royal MCP supports two OAuth client paths. **Auto Dynamic Client Registration** (the default) is the simpler, recommended setup — you just paste your server URL into Claude.ai and the OAuth flow handles credential generation automatically. **Static client** (the “Generate” button at Settings → Advanced) is an alternate path for specific advanced setups. This page covers the static path because it has a common setup trap that produces an `invalid_client: Unknown client_id at /authorize` error and a misleading “Authorization with the MCP server failed” message in Claude.ai.

The trap, in one sentence

The Generate button creates a `wp_*` client\_id *in your browser* — it does NOT persist to the database until you click **Save Settings** at the bottom of the page. Customers who Generate, then immediately copy the value into Claude.ai Advanced Settings, then try to connect, hit `invalid_client: Unknown client_id` on every attempt because the value isn’t in the WordPress database yet.

Most users don’t need this page — use auto DCR instead

If you’re setting up Royal MCP for the first time, the recommended path is auto Dynamic Client Registration: paste your MCP server URL into Claude.ai and leave the Advanced Settings (Client ID / Client Secret) completely empty. The OAuth flow handles everything automatically and you’ll never touch the static client at all. Use this page only if you have a specific reason to configure a static client (deterministic credentials across multiple Claude installations, infrastructure-as-code deployments, or you’ve already started down this path and need to finish it correctly).

### Most setups don’t need this page

The default Royal MCP setup uses **auto Dynamic Client Registration** — you paste your MCP server URL into Claude.ai and the OAuth flow handles everything automatically. If you’re setting up for the first time, do that. This page is for the static-client path, which is a separate, advanced option behind the “Generate” buttons in Royal MCP → Settings → Advanced.

## Royal MCP’s Two OAuth Client Paths

Royal MCP supports OAuth 2.0 with two different ways of managing the client credentials that Claude.ai presents during the OAuth handshake:

| Attribute | Auto DCR (default) | Static client (this page) |
| --- | --- | --- |
| Setup | Paste URL into Claude.ai, leave Advanced Settings empty | Generate Client ID + Secret in WP, save settings, paste both into Claude.ai Advanced |
| Client ID prefix | `rmcp_` | `wp_` |
| Created by | Royal MCP server, on each Claude reconnect | You, via the Generate button |
| Stored in | `wp_royal_mcp_oauth_clients` DB table | `royal_mcp_settings` WordPress option |
| Rotation | Automatic on reconnect | Manual (regenerate when desired) |
| Use when | Default for almost everyone | You need a deterministic credential across machines, or you’re using IaC / Configuration Profiles to deploy Claude config to many devices |

Both paths give Claude the same level of access. The only thing that differs is how the credentials are generated and stored. **If you’re not certain you need static, use auto DCR.** Auto DCR is simpler, has fewer failure modes, and doesn’t require any of the steps on this page.

## Bonus: Static Credentials as a Diagnostic Isolator

Beyond production use, static Client ID + Secret are the fastest way to **prove the OAuth server side works** when discovery is failing. This is useful when a host or a WAF is interfering with `/.well-known/`, but you’re not sure whether that’s the actual cause of your Claude connection failure or just one of several possible causes.

Why it’s such a clean isolator

When you paste static Client ID + Secret into Claude.ai’s custom-connector dialog, Claude **skips Dynamic Client Registration entirely** and constructs the `/authorize` URL directly from the MCP server URL you provided — without reading `/.well-known/oauth-authorization-server` at all. If the consent screen renders with the “(static)” suffix and you can click Authorize and see WordPress issue a code, that **proves**:

- The Royal MCP OAuth endpoints are healthy at the server layer
- Your WordPress rewrites for `/authorize` / `/register` / `/token` are registered correctly
- Whatever’s wrong is *downstream* of code issuance — either discovery-related (fixable) or in the token-exchange step (see the [claude.ai web upstream bug](https://royalplugins.com/support/royal-mcp/claude-ai-web-token-exchange-fails/))

### The 3-minute isolation test

1. Generate Client ID + Client Secret in **Royal MCP → Settings → Advanced** and click **Save Settings** (per the setup sequence below)
2. In Claude.ai, add a fresh custom connector. Paste your MCP server URL. Open **Advanced Settings** and paste in the Client ID + Client Secret
3. Click Connect

Read the outcome:

- **Consent screen renders with “(static)” suffix → you click Authorize → the browser redirects back to Claude.ai and you see `mcp_token_exchange_failed`** — the OAuth server is 100% healthy. The failure is inside claude.ai’s token exchange step. This matches the [upstream claude.ai web bug](https://royalplugins.com/support/royal-mcp/claude-ai-web-token-exchange-fails/) — switch to Claude Desktop or Claude Code.
- **Consent screen renders and Authorize succeeds and the connector lands as connected** — everything works. If *DCR* (the auto path) was failing for you but static works, the difference is that Claude tried to read `/.well-known/` in the DCR path and something intercepted it. Check the [well-known troubleshooting docs](https://royalplugins.com/support/royal-mcp/well-known-served-as-html/).
- **Consent screen never appears / you get “Authorization with the MCP server failed” before any consent UI** — the rewrite for `/authorize` isn’t registered, or you missed the Save Settings step. See [The Save Trap](#the-trap) below.

This isolator is what separates “server-side broken” from “client-side broken” in about three minutes — without editing `.htaccess`, without adding files to `/.well-known/`, and without contacting your host.

## The Common Setup Trap

The static-client path has one specific failure mode that produces an unhelpful error in Claude.ai. It’s worth understanding before you start, because it’s easy to trip on accidentally.

What goes wrong

The **Generate** button in **Royal MCP → Settings → Advanced** creates a `wp_*` client\_id value *in your browser*. The value appears in the input field, but it is NOT saved to the WordPress database until you click **Save Settings** at the bottom of the page.

If you Generate, immediately copy the value into Claude.ai’s Advanced Settings, and then try to connect — without first clicking Save Settings in WordPress — Royal MCP’s `/authorize` endpoint will return `invalid_client: Unknown client_id at /authorize` on every attempt. The value Claude.ai is presenting doesn’t exist in your WordPress database yet.

Claude.ai surfaces this as “Authorization with the MCP server failed” or “Couldn’t reach the MCP server” with an `ofid_*` reference code — misleading framing for what is really an unrecognized-credential error.

The fix is straightforward once you know to look for it: Save Settings on the WP side before connecting on the Claude.ai side. The full sequence is in the next section.

## The Correct Setup Sequence

Total time: about 3 minutes. You’ll need admin access to your WordPress site and a Claude.ai account.

#### Open Royal MCP’s Advanced Settings

WP Admin → **Royal MCP → Settings**. Scroll down to find the **Advanced** section (you may need to expand it). You’ll see two empty fields: **OAuth Client ID** and **OAuth Client Secret**, each with a **Generate** button next to it.

#### Click Generate for Client ID

This creates a `wp_*` prefixed value and puts it in the input field. A toast notice will appear saying “OAuth Client ID generated. Remember to save your settings!” — don’t dismiss this without acting on it.

#### Click Generate for Client Secret

Same flow — creates a 48-character random value, puts it in the field, shows a save reminder toast.

#### Click Save Settings ← critical step

This is the step that catches most people out. The Generate buttons only create values in your browser; the WordPress option `royal_mcp_settings.oauth_client_id` and `royal_mcp_settings.oauth_client_secret` aren’t updated until you click **Save Settings** at the bottom of the page.

After saving, the page should reload (or refresh) and the values should still be visible in the fields. If the fields are now empty after reload, the save didn’t persist — check for validation errors or a notice at the top of the page, and try again.

#### Copy both values

Carefully select and copy the **Client ID** (the `wp_*` value) and the **Client Secret**. Avoid trailing whitespace — double-click typically selects just the value without the spaces around it.

#### Add the connector in Claude.ai

In Claude.ai (web or Desktop): **Settings → Connectors → Add custom connector**. Enter your MCP server URL (`https://example.com/wp-json/royal-mcp/v1/mcp`). Expand **Advanced Settings**. Paste the Client ID into the **Client ID** field and the Client Secret into the **Client Secret** field.

#### Click Connect

Claude opens a browser tab pointing at your `/authorize` endpoint. You should see Royal MCP’s consent screen with your site’s name and the suffix **“(static)”** — that “(static)” suffix confirms Royal MCP found the static client you just configured.

Click Authorize. The browser redirects back to Claude.ai with the auth code. Claude exchanges it for an access token. The connector should now appear as connected with your tools available.

If the consent screen shows the (static) suffix, you’ve done the WP side correctly

The consent screen title includes the suffix **“(static)”** only when Royal MCP found the client\_id in `royal_mcp_settings`. If you see that suffix, your Save Settings step succeeded. If the consent screen doesn’t render at all and Claude shows “Authorization with the MCP server failed,” you’re still hitting the unsaved-state trap from the previous section — go back to step 4.

## Diagnostic — Confirming You Hit the Save Trap

If Claude.ai shows “Authorization with the MCP server failed” (or similar) with an `ofid_*` reference, check Royal MCP’s Activity Log to see exactly what happened:

#### WP Admin → Royal MCP → Activity Log

Look for the most recent row with action `oauth:authorize`.

Click **View Details** on that row. You’re looking for a request row containing `client_id: wp_<random-chars>` and a response row containing:

```
{
  "http_status": 400,
  "error": "invalid_client",
  "description": "Unknown client_id at /authorize."
}
```

If you see exactly that — **client\_id starts with `wp_` and the error is `invalid_client`** — you’ve confirmed the Save Settings trap. The value Claude.ai is sending exists nowhere in your WordPress database.

The fix: go back to **Royal MCP → Settings → Advanced**, confirm the OAuth Client ID field still shows a value (if empty, regenerate), then click **Save Settings** at the bottom of the page. Reload the page and confirm the value still shows in the field after reload (proves the save persisted). Then retry the Claude.ai connection — this time the value WILL be in the database.

## Switching to Auto DCR (Recommended for Most Setups)

If you set up a static client and now want to switch to the simpler auto DCR path:

#### Clear the static client in Royal MCP

WP Admin → **Royal MCP → Settings → Advanced**. Click the **Clear** button next to OAuth Client ID, and again next to OAuth Client Secret. Click **Save Settings**.

Royal MCP version 1.4.22 and later support clearing these fields directly through the UI. On older versions you may need to leave the fields blank manually and save, or use the **Reset OAuth State** button which also clears manual credentials.

#### Delete the connector in Claude.ai

Claude.ai → Settings → Connectors → find your existing Royal MCP connector → **Delete** it entirely. This wipes the static Client ID and Secret from Claude’s local config.

#### Re-add with no Advanced Settings

Add the connector again with ONLY your MCP server URL. **Leave the Advanced Settings completely empty** — no Client ID, no Client Secret. Claude.ai will do Dynamic Client Registration automatically and get a fresh `rmcp_*` client\_id directly from Royal MCP.

#### Click Connect

The consent screen this time will not have the “(static)” suffix — just your site name. That confirms auto DCR is now in use. Click Authorize, and the connector will be set up.

## Why the Save Trap Exists (Honest Note)

This is a UX gap in Royal MCP that we’re aware of and plan to address in a future release. The Generate button currently creates values client-side in JavaScript and inserts them into the form, which is a common pattern in WordPress admin UIs — the form is what gets persisted on Save, not individual field changes. The pattern works fine for opaque-looking settings, but is confusing for credential fields where users naturally assume “Generate” means “create this credential server-side and make it active.”

Two possible fixes are on our radar: (a) have the Generate button POST the new value to a server-side endpoint that immediately persists it, removing the need for a separate Save step, or (b) deprecate the static-client path in favor of auto DCR for everyone. In the meantime, this support page exists to make the trap obvious.

## Still Stuck? Two Support Paths

If you’ve worked through the steps above and your connection still fails:

### 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 issues faster than email could. 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](https://royalplugins.com/premium-support/) 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

- **The first 6 characters of your OAuth Client ID** (e.g. `wp_OdM...`) — this tells us whether Claude.ai is sending what you configured. Don’t paste the full value, just the prefix.
- **Screenshot of WP Admin → Royal MCP → Settings → Advanced** with the OAuth Client ID field visible after a page reload — confirms the value is actually saved in WordPress, not just sitting in an unsaved form.
- **Screenshot of the most recent `oauth:authorize` Activity Log row** with View Details expanded.
- **The exact error message and any `ofid_*` reference code** Claude.ai shows you.

[Skip OAuth entirely with API key](https://royalplugins.com/support/royal-mcp/connect-claude-desktop-api-key/)
[Back to Royal MCP Support](https://royalplugins.com/support/royal-mcp/)
