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
| MCP | Remote endpoint | Client identity | Grant types |
|---|---|---|---|
| MongoDB Atlas (Managed MCP) | https://mcp.mongodb.com | Client ID Metadata Document | user, workspace |
| GitHub | https://api.githubcopilot.com/mcp/ | Registered Cendriix client | user, workspace |
| Linear | https://mcp.linear.app/mcp | Dynamic registration | user, workspace |
| Jira | https://mcp.atlassian.com/v1/mcp | Dynamic registration | user, workspace |
| Confluence | https://mcp.atlassian.com/v1/mcp | Dynamic registration | user, 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:
| Choice | Stored as | Who can use it |
|---|---|---|
| Just me | a grant bound to your user | only your sessions, attributed to you |
| Everyone in this workspace | a grant with no user | any 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
- Discovery. Cendriix fetches the server’s protected-resource metadata (RFC 9728), then the authorization server’s metadata (RFC 8414), so endpoints are never hardcoded.
- Authorization. You are redirected to the provider with PKCE (
S256required), the RFC 8707resourceindicator for the MCP server, and an opaquestate. The PKCE verifier stays on the server, in Redis, keyed by that state. - Consent. The provider authenticates you and lists what is being requested.
- 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 9207issparameter, it must match the issuer the state was minted for or the code is never redeemed. - 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:
| Mode | How it works | Used by |
|---|---|---|
document | Our 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 |
dcr | Dynamic client registration (RFC 7591) against the provider’s registration endpoint. | Atlassian, Linear |
static | A 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.
| Route | Purpose |
|---|---|
GET /client-metadata | Our 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 /callback | Provider 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
| Symptom | Cause | Fix |
|---|---|---|
404 from any /v1/mcp/oauth/* route | OAuth is not enabled for the environment | Contact Cendriix support — the surface is absent rather than broken by design |
404 provider_unknown | The catalog entry has no registered authorization server | Install it with a pasted credential instead |
501 registration_unsupported / pkce_unsupported | The provider exposes neither registration nor CIMD, or does not support S256 | Not connectable by consent; use a credential |
reauth_needed — 409 from these routes, 401 from a tool call | Refresh failed or the grant was revoked upstream | Click Reconnect |
Returned with mcp_oauth=error&reason=state_invalid | The consent link was reused, expired, or opened twice | Start the connection again |
Returned with reason=issuer_mismatch | The code came from a different authorization server than the one you were sent to | Expected refusal; report it if it recurs |
| The provider says the authorization request is invalid | The provider has not enabled delegated access for your organization | For Atlas, an Organization Owner must enable App Connections |
| The panel shows ERROR and no Connect button | The status check itself failed | Retry; the paste-a-credential form below it still works |
Further reading
- MongoDB Atlas (Managed MCP) — the first provider on this capability
- MCP Marketplace — browse and install MCPs
- Policies & Guardrails — approval gates and blast radius
- Audit Log — every tool call, attributed to the authorizing user