URL: /docs/mcp/authentication

---
title: MCP authentication
description: OAuth 2.1 through Clerk, or the same rvd_ API key the REST API takes — on the same Authorization header.
---

`https://getrevised.com/api/mcp` takes two credentials on the same `Authorization: Bearer ...` header. The server picks the right verifier from the token's shape; you do not.

Either way the caller resolves to the same user id and the same plan, through the same lookup the REST API uses. There is no second code path in which a rule could be enforced differently: the reveal quota, the hold cooldown, the access-delay window and name disclosure all key off those two values and nothing else.

## Option 1: OAuth 2.1 (recommended)

For anything with a browser to sign in from. Give the client the URL and nothing else — no key is ever pasted.

<Steps>
  <Step title="The client POSTs with no credential">
    It gets `401` and a challenge naming where to look:

    ```http
    WWW-Authenticate: Bearer realm="revised",
      resource_metadata="https://getrevised.com/.well-known/oauth-protected-resource/api/mcp"
    ```
  </Step>
  <Step title="It reads the protected-resource document">
    RFC 9728. The same document is also served at the bare `/.well-known/oauth-protected-resource`, because several shipping clients probe the origin first.

    ```json
    {
      "authorization_servers": ["https://clerk.getrevised.com"],
      "bearer_methods_supported": ["header"],
      "resource": "https://getrevised.com/api/mcp",
      "resource_documentation": "https://getrevised.com/docs/api",
      "resource_name": "Revised",
      "scopes_supported": ["openid", "profile", "email"]
    }
    ```
  </Step>
  <Step title="It registers and runs the flow">
    Dynamic client registration against Clerk, then the OAuth 2.1 authorisation-code flow with PKCE `S256`. `/.well-known/oauth-authorization-server` passes Clerk's RFC 8414 metadata through from the Revised origin, for clients that probe there first; its `issuer` names Clerk and is deliberately not rewritten.
  </Step>
  <Step title="The person signs in and consents">
    A browser tab opens on the Revised sign-in, then the consent screen. The client stores the access token and sends it as `Authorization: Bearer <token>`.
  </Step>
</Steps>

Every URL in that flow is built from the request's own origin, so a preview hostname or a local server advertises itself rather than production.

### Scopes

| Scope | Advertised | Required |
| --- | --- | --- |
| `openid` | yes | no |
| `profile` | yes | **yes** |
| `email` | yes | no |

`profile` is the one scope a token must carry. It is deliberately a single scope rather than a per-tool ladder: splitting reads from reveals across two scopes would look like least privilege and would not be one, since a client that can search can ask for the reveal scope at the next consent screen. The thing that actually bounds spending is the plan's monthly reveal allowance, which no token can widen.

Clerk's instance also offers `public_metadata`, `private_metadata` and `offline_access`. The first two are deliberately not advertised — this server never reads the user's Clerk metadata through the token; it resolves the plan server-side. `offline_access` is the client's business to request, not Revised's to require.

## Option 2: API key

For a script, a container, CI, or any client that cannot complete an OAuth flow. The same `rvd_` keys the REST API takes, created at [getrevised.com/account](https://getrevised.com/account) on any plan.

```json
{
  "mcpServers": {
    "revised": {
      "url": "https://getrevised.com/api/mcp",
      "headers": {
        "Authorization": "Bearer rvd_yourprefix_yoursecret"
      }
    }
  }
}
```

The exact configuration shape varies by client — see the install pages for [Claude Code](/docs/mcp/install/claude-code), [Claude Desktop](/docs/mcp/install/claude-desktop) and [Cursor](/docs/mcp/install/cursor).

A key carries no entitlement of its own: the owner's current plan is resolved behind it and refreshed at least once a minute. See [Authentication](/docs/api/authentication) for the token format and the per-plan key ceilings.

## Which one to use

| | OAuth | API key |
| --- | --- | --- |
| Needs a browser to sign in | yes, once | no |
| Key stored in a config file | no | yes |
| Works in CI or a headless container | no | yes |
| Rate-limit counter | shared across everything that account has connected | per key |
| Entitlements | identical | identical |

`whoami` reports which one the session is using, as `auth: "oauth"` or `auth: "api_key"` — worth reading before telling someone where to change a setting.

## Failures

Authentication failures arrive as an HTTP status with a JSON-RPC error body and no tool result at all. They are distinct from a tool that ran and refused, which returns a result with `isError: true` and an UPPER_SNAKE_CASE code.

| Status | `WWW-Authenticate` | Meaning | Fix |
| --- | --- | --- | --- |
| 401 | bare challenge | No credential was presented. | Start authenticating. |
| 401 | `error="invalid_token"` | A credential was presented and is wrong, expired or revoked. | Do not retry the same one. Re-authenticate, or check the key on the account page. |
| 403 | `error="insufficient_scope", scope="profile"` | The sign-in granted less than this server needs. | Disconnect and connect again, accepting the consent screen. |
| 429 | — | Over the per-minute ceiling. Carries `Retry-After`. | Wait and retry. On an OAuth connection the counter is shared with everything else this account has connected. See [Rate limits](/docs/api/rate-limits). |

Every `401` and `403` carries the `WWW-Authenticate` challenge with a `resource_metadata` pointer built from the request's own origin, so a client that lost its token can rediscover the authorisation server without being reconfigured.

## CORS

The two discovery documents are public and cross-origin: a browser-hosted client fetches them from its own origin before it has a token. They carry `Access-Control-Allow-Origin: *`, and `OPTIONS` answers the preflight on the MCP endpoint itself. There is nothing to protect in them — they say which public authorisation server Revised uses.
