Skip to Content

Connect an MCP with OAuth

Remote MCP servers — servers the vendor runs, not Cendriix — are installed with a browser consent flow instead of a pasted credential. You click Connect with <provider>, the provider asks you to authorize Cendriix, and the tokens are stored encrypted in your tenant’s Secrets Vault. Nobody ever handles a long-lived secret.

This page describes the shared OAuth capability: one implementation serves every remote MCP server, so a new provider is a catalog registration rather than new code.

Which servers support it

MCPRemote endpointClient identityGrant types
MongoDB Atlas (Managed MCP)https://mcp.mongodb.comClient ID Metadata Documentuser, workspace
GitHubhttps://api.githubcopilot.com/mcp/Registered Cendriix clientuser, workspace
Linearhttps://mcp.linear.app/mcpDynamic registrationuser, workspace
Jirahttps://mcp.atlassian.com/v1/mcpDynamic registrationuser, workspace
Confluencehttps://mcp.atlassian.com/v1/mcpDynamic registrationuser, workspace

Jira and Confluence share one connection. They are one Atlassian authorization server and one resource, so authorizing either connects both — and disconnecting either revokes both. Connect once; expect the second entry to already read as connected.

Every other catalog entry is installed by pasting a credential. An entry that advertises OAuth but has no registered authorization server still uses the paste form — the install panel falls back to it automatically, and the API refuses a consent flow with a message that says so rather than inventing endpoints.

Per-user vs workspace-wide grants

When you connect, you choose who the connection is for:

ChoiceStored asWho can use it
Just mea grant bound to your useronly your sessions, attributed to you
Everyone in this workspacea grant with no userany member, plus unattended work — schedules, triggers, automations

Resolution order at call time is your grant → your grant on a sibling entry sharing the same resource → the workspace grant → a workspace sibling grant → re-authenticate. So a personal connection always wins over the shared one, and a workspace grant is what keeps overnight automations running when nobody is at a keyboard.

Choose Everyone in this workspace deliberately. The provider attributes every call to the user who authorized it, and that user’s own permissions are the ceiling on what agents can do.

How the flow works

  1. Discovery. Cendriix fetches the server’s protected-resource metadata (RFC 9728), then the authorization server’s metadata (RFC 8414), so endpoints are never hardcoded.
  2. Authorization. You are redirected to the provider with PKCE (S256 required), the RFC 8707 resource indicator for the MCP server, and an opaque state. The PKCE verifier stays on the server, in Redis, keyed by that state.
  3. Consent. The provider authenticates you and lists what is being requested.
  4. Callback. The provider redirects to https://api.cendriix.ai/v1/mcp/oauth/callback. The state is consumed once — a replayed callback finds nothing. When the provider sends the RFC 9207 iss parameter, it must match the issuer the state was minted for or the code is never redeemed.
  5. Storage. The code is exchanged for tokens, which are envelope-encrypted with your tenant’s key before they touch the database. No response body from any of these routes ever contains a token, refresh token, authorization code, verifier, or client secret.

Client identity

Providers differ in how a client gets an id, so Cendriix supports all three:

ModeHow it worksUsed by
documentOur client_id is a URL that serves our client metadata: https://api.cendriix.ai/v1/mcp/oauth/client-metadata. The provider fetches it during authorization.MongoDB Atlas
dcrDynamic client registration (RFC 7591) against the provider’s registration endpoint.Atlassian, Linear
staticA client id (and secret, where required) configured for the environment.GitHub

Token lifecycle

  • Refresh happens automatically, five minutes before expiry.
  • If a refresh fails — the grant was revoked, or the provider expired it — the connection moves to re-authentication needed and the UI shows a Reconnect button. The failing operation gets exactly one re-authentication attempt, never a loop.
  • Disconnect deletes the grant locally and revokes it upstream when the provider exposes a revocation endpoint. Local deletion happens either way, so you can always disconnect.
  • Providers impose their own lifetimes. MongoDB Atlas, for example, ends delegated access after 7 days of inactivity or 30 days from consent, whichever comes first.

API

All routes live under https://api.cendriix.ai/v1/mcp/oauth. client-metadata and callback are public by necessity — the first is our published identity, the second is a browser redirect that carries no Cendriix session. start, status, and revoke require your session.

RoutePurpose
GET /client-metadataOur RFC 7591-shaped client metadata document. Its URL is our client_id at providers that support Client ID Metadata Documents.
POST /start{ catalogId, grantScope, returnTo } → { authorizationUrl, state, expiresAt, issuer, resource, scopes }. Visit the URL to consent.
GET /callbackProvider redirect target. Redirects back to the app with mcp_oauth=connected or mcp_oauth=error&reason=….
GET /status?catalogId=…&grantScope=… → { connected, scope, issuer, resource, expiresAt, scopes, connectedBy, connectedAt }.
POST /revoke{ catalogId, grantScope } → disconnects, revoking upstream where supported.
# Begin a personal connection to the Atlas Managed MCP server curl -X POST https://api.cendriix.ai/v1/mcp/oauth/start \ -H "Authorization: Bearer $CENDRIIX_TOKEN" \ -H 'Content-Type: application/json' \ -d '{"catalogId":"mcp-mongodb-atlas","grantScope":"user"}'

grantScope defaults to user. Omitting it on status answers the question “can I call this server right now”, which is the user → workspace precedence described above; passing grantScope=tenant asks specifically about the shared grant.

Troubleshooting

SymptomCauseFix
404 from any /v1/mcp/oauth/* routeOAuth is not enabled for the environmentContact Cendriix support — the surface is absent rather than broken by design
404 provider_unknownThe catalog entry has no registered authorization serverInstall it with a pasted credential instead
501 registration_unsupported / pkce_unsupportedThe provider exposes neither registration nor CIMD, or does not support S256Not connectable by consent; use a credential
reauth_needed — 409 from these routes, 401 from a tool callRefresh failed or the grant was revoked upstreamClick Reconnect
Returned with mcp_oauth=error&reason=state_invalidThe consent link was reused, expired, or opened twiceStart the connection again
Returned with reason=issuer_mismatchThe code came from a different authorization server than the one you were sent toExpected refusal; report it if it recurs
The provider says the authorization request is invalidThe provider has not enabled delegated access for your organizationFor Atlas, an Organization Owner must enable App Connections
The panel shows ERROR and no Connect buttonThe status check itself failedRetry; the paste-a-credential form below it still works

Further reading

Last updated on