Revised

MCP authentication

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.

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

  1. 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"
  2. 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"]
    }
  3. 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.

  4. 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>.

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

ScopeAdvertisedRequired
openidyesno
profileyesyes
emailyesno

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 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, Claude Desktop and 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 for the token format and the per-plan key ceilings.

Which one to use

OAuthAPI key
Needs a browser to sign inyes, onceno
Key stored in a config filenoyes
Works in CI or a headless containernoyes
Rate-limit countershared across everything that account has connectedper key
Entitlementsidenticalidentical

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.

StatusWWW-AuthenticateMeaningFix
401bare challengeNo credential was presented.Start authenticating.
401error="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.
403error="insufficient_scope", scope="profile"The sign-in granted less than this server needs.Disconnect and connect again, accepting the consent screen.
429Over 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.

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.

Type to search…

↑↓ navigate openesc close