Skip to main content

TL;DR

You don’t need to manage anything by hand. MCP-aware clients walk the full OAuth flow themselves the first time they hit the Cometly MCP endpoint:
  1. The client sees a 401 Unauthorized with a WWW-Authenticate header pointing at our OAuth discovery URL.
  2. The client registers itself dynamically (RFC 7591).
  3. The client opens your browser to the Cometly authorization page.
  4. You log in, pick which Space to grant access to, and click Approve.
  5. The client exchanges the resulting code for an access token bound to that Space.
After that the client just sends Authorization: Bearer <token> on every tool call. If you want the gritty detail — or you’re building a custom MCP client — keep reading.

Endpoints

Cometly is its own authorization server. There’s no third-party identity provider in the middle.
EndpointURL
Protected resource metadata (RFC 9728)https://app.cometly.com/.well-known/oauth-protected-resource/{path}
Authorization server metadata (RFC 8414)https://app.cometly.com/.well-known/oauth-authorization-server/{path}
Dynamic client registrationPOST https://app.cometly.com/mcp/oauth/register
Authorization (browser)GET https://app.cometly.com/mcp/oauth/authorize
Token exchangePOST https://app.cometly.com/mcp/oauth/token
MCP server (resource)https://app.cometly.com/mcp/{space_id}/public-api
We expose both the path-prefix (RFC 9728) and path-suffix (RFC 8414) .well-known URL variants because different clients implement different revisions of the spec. Claude Desktop uses the prefix form; Cursor uses the suffix form. Both resolve to the same metadata.

Discovery metadata

Hitting the auth-server metadata endpoint returns:
{
  "issuer": "https://app.cometly.com",
  "authorization_endpoint": "https://app.cometly.com/mcp/oauth/authorize",
  "token_endpoint": "https://app.cometly.com/mcp/oauth/token",
  "registration_endpoint": "https://app.cometly.com/mcp/oauth/register",
  "response_types_supported": ["code"],
  "code_challenge_methods_supported": ["S256"],
  "scopes_supported": ["mcp:use"],
  "grant_types_supported": ["authorization_code"]
}
PKCE with S256 is required. There’s no implicit grant, no password grant, no client-credentials grant — just authorization code with PKCE.

Dynamic client registration

POST /mcp/oauth/register with the client’s metadata. Minimal example:
{
  "client_name": "My MCP Client",
  "redirect_uris": ["http://127.0.0.1:33333/callback"],
  "token_endpoint_auth_method": "none"
}
Returns a client_id you’ll use for the authorization request. There is no client_secret — Cometly’s MCP server treats every client as a public client and relies on PKCE for security.

Accepted redirect_uris

The redirect URI is validated at registration. Each URI must fall into one of three accepted categories; redirect URIs that don’t match are rejected.
CategoryExamplesUse case
Loopbackhttp://127.0.0.1:33333/callback, http://localhost/cbNative desktop clients
https:// to an allowed hosthttps://claude.ai/api/mcp/auth_callbackHosted web clients — see Default allowed https hosts below
Well-known custom schemecursor://..., vscode://..., claude-desktop://..., com.example.app:/oauth2redirectDesktop and native apps

Default allowed https hosts

The following hosts are accepted out of the box. If you need a host that isn’t listed, contact support: support@cometly.com.
Host(s)Client
claude.ai, claude.comAnthropic Claude (web, desktop, mobile)
chatgpt.com, chat.openai.comOpenAI ChatGPT
cursor.com, www.cursor.comCursor web agents
vscode.dev, insiders.vscode.devVS Code for the Web / github.dev (desktop VS Code uses loopback + vscode://)
grok.comxAI Grok
gemini.google.comGoogle Gemini
perplexity.ai, www.perplexity.aiPerplexity

Accepted client_name

client_name is shown verbatim on the consent screen, so it’s validated to prevent impersonation and UI hijacking:
  • Maximum 120 characters.
  • No control characters (\x00–\x1f, \x7f).
  • Names that contain cometly as a standalone word (case-insensitive, word/whitespace/hyphen/underscore boundaries) are rejected to keep malicious clients from passing themselves off as Cometly itself.

Rate limits

POST /mcp/oauth/register is throttled to 10 registrations per hour per IP. Legitimate clients register once per install, so this leaves plenty of headroom for retries while making it impractical to flood the registration table. Exceeded requests return 429 temporarily_unavailable with an RFC 7591 error body.

Authorization flow

  1. Generate a PKCE code_verifier and the matching code_challenge (SHA256(verifier), base64url, no padding).
  2. Redirect the user (in their browser) to:
    https://app.cometly.com/mcp/oauth/authorize
      ?response_type=code
      &client_id={client_id}
      &redirect_uri={redirect_uri}
      &code_challenge={code_challenge}
      &code_challenge_method=S256
      &state={random}
      &scope=mcp:use
    
  3. The user logs in (if not already), then picks the Space and clicks Approve.
  4. Cometly redirects back to your redirect_uri with ?code={code}&state={state}.
  5. Exchange the code:
    curl -X POST https://app.cometly.com/mcp/oauth/token \
      -H "Content-Type: application/x-www-form-urlencoded" \
      -d "grant_type=authorization_code" \
      -d "code={code}" \
      -d "redirect_uri={redirect_uri}" \
      -d "client_id={client_id}" \
      -d "code_verifier={code_verifier}"
    
    Response:
    {
      "access_token": "1|abc...",
      "token_type": "Bearer",
      "expires_in": null,
      "scope": "mcp_space:42"
    }
    

Calling the MCP server

Once you have an access token, every JSON-RPC call to the MCP endpoint carries it:
curl -X POST https://app.cometly.com/mcp/42/public-api \
  -H "Authorization: Bearer 1|abc..." \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
The Space ID in the URL must match the Space the token was approved for — Cometly checks the token’s mcp_space:{id} ability against the route param on every request and returns 403 if they disagree.

Scopes

There’s a single MCP scope today:
ScopeWhat it grants
mcp_space:{id}Call any read-only tool against Space {id}. The Space ID is bound into the scope string — a token approved for Space 42 cannot read Space 43.
When you click Approve in the consent UI, the token’s ability is set to exactly one mcp_space:{id} value. There’s no broader “all spaces” scope, by design.

Revoking access

You can revoke a connected MCP client at any time:
  1. Open Settings → API Tokens in your Cometly dashboard.
  2. Find the token whose name matches the MCP client (e.g. MCP — Claude Desktop).
  3. Click Revoke.
The next tool call from that client gets 401 Unauthorized and the client will walk the auth flow again on next launch (or you can just remove it from the client’s MCP settings). Removing a user from a Space also immediately revokes any MCP tokens they have for that Space — there’s no separate cleanup step.

Common errors

StatusMeaningRecovery
401No / invalid / expired token.Walk the OAuth flow again. The WWW-Authenticate header includes the discovery URL.
403Token’s mcp_space:{id} doesn’t match the URL’s Space ID, or the user no longer has API permission in that Space.Re-authorize with the correct Space.
403 (subscription)The Space’s team doesn’t have an active Public API subscription.Reach out to your Cometly admin or contact sales.
429Rate limit exceeded.Back off. See Rate Limits & Errors.