Skip to content

Tokens & scoping

The MCP endpoint accepts two auth styles. Both end up at the same scope check on the server — the difference is purely in how Claude obtains the bearer.

Issued by the OAuth Custom Connector flow. Stored only in Claude Desktop; the worker keeps a hash plus rotation metadata. Format: oat_<random>.

AttributeValue
LifetimeAccess token 1 h, refresh token 30 d, rotated on every refresh
Granted scopeAlways mcp:full — full surface visible to the user
Per-site scopeBound to the user’s user_sites whitelist (DB-side, not in the token)
User bindingLinked to a real user account (oauth_access_tokens.user_id)
Refresh strategyAutomatic — Claude refreshes silently
RevokeClick Remove in Claude → calls /oauth/revoke. Or master-admin can wipe rows in oauth_access_tokens table
Audit trailEvery tools/call records actor_user_id from the access token

Get one: Add SEO Navigator as a Custom Connector in Claude Desktop — see Quick start.

Plaintext static strings minted in the admin dashboard. Format: sn_prod_<32 hex>. Used by the mcp-remote bridge when OAuth isn’t an option, or by CLI/CI workflows.

AttributeValue
LifetimeNone (live until revoked)
Granted scopeExplicit per-token allowed_sites + allowed_tools arrays
Per-site scopeWhatever the creator ticked when minting
User bindingtokens.owner_user_id — NULL means super-admin-issued
Refresh strategyNone — recreate manually
Revoke/admin/tokens → red Revoke button
Audit trailactor_user_id set from tokens.owner_user_id
  1. Open /admin/tokens and click + Create token.
  2. Name: descriptive (eg “CI runner”, “blog writer staging”).
  3. Allowed sites:
    • Super-admin: pick specific sites or * for all.
    • Regular user: only your own sites are listed. Pick * to expand to everything you own at this moment (locks at create time — later grants don’t widen the token).
  4. Allowed tools:
    • Quick-pick Select all ticks every safe built-in + proxy tool.
    • Quick-pick All except destructive filters out proxy delete-*, publish-* tools.
    • Quick-pick Built-in only skips the wp-mcp-adapter proxy surface.
    • Super-admin-only tools (eg delete_astro_route) are hidden from regular users entirely.
  5. Create. Copy the plaintext — it’s shown once.

If you lose the plaintext, revoke and create a new one. The worker only stores SHA-256 of the bytes.

Use casePick
Claude Desktop on a personal laptopOAuth
Claude Desktop on a teammate’s machine — handover-friendlyOAuth (per-user token, not shared)
Old Claude Desktop without Custom Connector UIBearer + mcp-remote
CI runner posting to the MCP from CLIBearer (long-lived, no browser)
Test fixtures or curl explorationBearer
Multi-tenant ops where each team has its own userOAuth (cleaner audit)

You can have BOTH on the same worker for the same user — the OAuth token operates on the user’s user_sites, while a bearer token mints whatever scope the user explicitly picked. Each leaves a separate audit trail.

Sites are NOT pinned to bearer tokens by ID alone — they’re filtered against the calling user’s user_sites whitelist on every request:

  • OAuth: token has user_id. Tool calls intersect that user’s sites with the requested site_id. Out-of-scope → 403 E_SCOPE_DENIED.
  • Bearer: token has explicit allowed_sites. If owner is a regular user, the worker additionally intersects with their current user_sites. So removing a site from a user’s grant also locks down their bearer tokens.

This means a super-admin can revoke a user’s access by removing site grants in /admin/users — no need to revoke individual tokens.

No token, of either type, can publish-now or delete a WordPress / Duda post. The check happens at the tool registration layer — those tools simply don’t exist on the server. A token with allowed_tools: ["*"] still cannot call delete_post because there’s no delete_post to call.

The one documented exception — delete_astro_route — is super-admin-only at runtime regardless of the token’s allowed_tools value.

Every successful or failed tool call writes a row in audit_log:

ts INTEGER -- unix ms
actor_user_id TEXT -- from OAuth user_id or token owner_user_id
token_id TEXT
site_id TEXT
tool TEXT
status TEXT -- ok | denied | error
duration_ms INTEGER
args_json TEXT -- truncated to 1KB
error TEXT -- when status != ok
via TEXT -- "default" | "wp-mcp-adapter"

Browse and filter at /admin/audit. Regular users see only their own rows; super-admin sees everything.