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 identifies itself — either via a hosted metadata document (CIMD) or by calling the registration endpoint (DCR).
  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’re building a custom MCP client, you have two registration paths: CIMD (preferred — no registration call required) and Dynamic Client Registration (fallback, e.g. for custom URI schemes). If you want the gritty detail, keep reading. If you’re connecting a server-side agent (headless script, CI job, backend service — no browser), skip OAuth entirely and use a personal access token instead.

Endpoints

Cometly is its own authorization server. There’s no third-party identity provider in the middle. 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:
PKCE with S256 is required. There’s no implicit grant, no password grant, no client-credentials grant — just authorization code with PKCE.

Client ID Metadata Document (CIMD)

CIMD is the preferred registration path for new custom MCP clients. Instead of calling /mcp/oauth/register to get a client ID, you host a JSON document at an https:// URL and use that URL itself as your client_id — no registration request needed. Support is advertised via client_id_metadata_document_supported: true in the discovery metadata. If that field is absent or false, fall back to Dynamic Client Registration.

Metadata document

Host a JSON file at any stable https:// URL with a non-root path (for example, https://app.example.com/oauth/client-metadata.json). The document must include: All other fields (client_uri, grant_types, response_types) are accepted and recorded but not enforced.
On the consent screen, Cometly shows the verified client domain alongside client_name. Clients whose only redirect URIs are loopback addresses receive an advisory notice on the consent screen.

Accepted redirect_uris for CIMD clients

Each URI in the document must satisfy one of two rules: Custom URI schemes (e.g. cursor://, vscode://) are not accepted for CIMD clients. If your client uses a custom scheme, use Dynamic Client Registration instead — the custom-scheme allowlist applies only to DCR. The redirect_uri you send on /authorize and /token must exactly match one of the URIs in the document (loopback port normalization per RFC 8252 applies).

Document fetching and caching

On every /authorize request with a URL-shaped client_id, Cometly fetches and validates the metadata document. The fetch is:
  • SSRF-guarded — private, loopback, link-local, and cloud-metadata IPs are refused.
  • TLS-verified — the certificate must be valid; redirects are not followed by default.
  • Rate-limited and size-capped — oversized or excessively frequent responses are rejected.
Cometly caches the validated document per client_id URL, honoring Cache-Control: max-age up to a 24-hour ceiling (default window 15 minutes). Deploy an updated document and wait up to 24 hours for all caches to clear, or set a shorter max-age on your server’s response.

Dynamic client registration

Dynamic Client Registration (RFC 7591) is the fallback path when CIMD isn’t suitable — for example when your client uses a custom URI scheme (cursor://, vscode://) that CIMD doesn’t accept, or when you can’t host a metadata document at a stable https URL. POST /mcp/oauth/register with the client’s metadata. Minimal example:
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. This allowlist applies to DCR clients only — CIMD clients use a same-host rule instead.

Default allowed https hosts

These hosts are accepted for DCR clients out of the box. If you need a host that isn’t listed, contact support: support@cometly.com. (CIMD clients don’t need to be on this list — they use the same-host rule described above.)

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

This flow is the same whether your client_id is an opaque string from DCR or an https URL from CIMD.
  1. Generate a PKCE code_verifier and the matching code_challenge (SHA256(verifier), base64url, no padding).
  2. Redirect the user (in their browser) to:
  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:
    Response:

Server-side agents (PAT)

The Authorization flow above is the right default for MCP-aware clients with a browser. If you’re building a server-side agent (a headless script, a CI job, a backend service), there’s no human at a browser to click Approve. For those cases, generate a personal access token (PAT) in the Cometly dashboard and send it as a bearer header. A personal access token behaves exactly like an OAuth-issued token: it’s tied to your user account, works for one Space only, and your access to that Space is re-checked on every request. The only difference is how you obtain one.

Generate a token

Before you start, make sure you’re signed in to Cometly and can see the target Space’s Settings → Integrations → MCP page. If you can’t, ask a Space admin to grant you API access.
  1. Open Settings → Integrations → MCP in your Cometly dashboard.
  2. Under MCP Access Tokens, enter a name for the token (e.g. CI Agent) and click Generate Token.
  3. Copy the token right away. For security reasons, it isn’t shown again. A ready-to-paste config snippet is displayed alongside it.

Configure your agent

The token works with any MCP client that supports type: http servers with bearer auth. Minimal .mcp.json:
If you’re calling the MCP endpoint directly (no MCP client library), see Calling the MCP server. The Authorization: Bearer header is the only difference from an OAuth-issued token.

Limits

  • You can generate tokens on this page until you hold 25 MCP tokens for the Space. Tokens issued to OAuth clients (Cursor, Claude Desktop, etc.) count toward that number, so if you hit the limit, revoke tokens you no longer use from the same page.
  • The token works only for the Space you generated it in. There is no “all Spaces” token.
  • Token names are limited to 120 characters and can’t contain control characters. The name is only a label for the list on the settings page; it has no effect on what the token can do.
  • Tokens don’t expire. Revoke them when an agent is decommissioned (see Revoking access).

Calling the MCP server

Once you have an access token, every JSON-RPC call to the MCP endpoint carries it:
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: 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 any MCP token for a Space — whether issued via OAuth (Cursor, Claude Desktop, etc.) or generated as a PAT — from a single list:
  1. Open Settings → Integrations → MCP in your Cometly dashboard.
  2. Under Server-side (headless) agents, find the token you want to revoke. OAuth-issued tokens appear here too, named after the client that requested them (e.g. MCP: Cursor (Acme Inc.)).
  3. Click Revoke.
The next tool call from that token gets 401 Unauthorized. OAuth clients will walk the auth flow again on next launch; PAT clients will need a fresh token generated for them. Removing a user from a Space also immediately revokes every MCP token they hold for that Space — there’s no separate cleanup step.

Common errors