How to Connect
Authentication reference for the ZopNight MCP server — OAuth 2.1 with Dynamic Client Registration, Protected Resource Metadata, refresh-token rotation with reuse detection, and Personal Access Tokens for non-browser clients.
The ZopNight MCP server accepts two auth methods. Both arrive as Authorization: Bearer <token> on every request; the gateway resolves identity, role, and RBAC per call.
- OAuth 2.1 (recommended) for interactive MCP clients that can drive a browser consent flow — Cursor, Claude Desktop, Claude Code, ChatGPT, VS Code, and the rest.
- Personal Access Token for CI, scripts, and non-browser clients that need a long-lived credential.
Client-side setup (config paths, install links, screenshots) lives in the product docs at zop.dev/docs/zopnight/integrations/mcp and zop.dev/docs/zopday/integrations/mcp. This page is the protocol reference: what the server implements and what a client sees on the wire.
Enable MCP Server (admin, one-time)
MCP is enabled per organisation. An admin needs to turn it on first.
Open organisation settings
Log in to ZopNight, open Settings → Organisation, and scroll to the MCP Server section in the Organisation details card.
Toggle MCP Server on
The status badge flips from "Inactive" to "Active". The Server URL becomes visible, and the Write access picker unlocks.
Choose a Write access level
Read-only ships. Raise it only after reading the security disclosure below.
OAuth 2.1
OAuth 2.1 is the recommended path for any MCP client that can open a browser. It builds on RFC 6749 (authorization code + refresh), RFC 6750 (Bearer usage), RFC 7591 (Dynamic Client Registration), RFC 9728 (Protected Resource Metadata), RFC 8414 (Authorization Server Metadata), and RFC 9700 §4.14.2 (refresh-token reuse detection). PKCE is required.
End-to-end flow
Client discovers the resource
Client sends any request to the MCP URL without a token. The server responds
401 Unauthorizedwith aWWW-Authenticate: Bearerchallenge naming the resource. The client fetches the resource's metadata at/.well-known/oauth-protected-resource(RFC 9728) and readsauthorization_serversfrom it.Client discovers the authorization server
Client fetches
/.well-known/oauth-authorization-server(RFC 8414) — and, if the AS lives under a path prefix, the path-suffixed form/.well-known/oauth-authorization-server/oauth. The metadata document listsauthorization_endpoint,token_endpoint,registration_endpoint,revocation_endpoint, supported grant types, PKCE methods, and scopes.Client registers dynamically (RFC 7591)
Client POSTs to
/oauth/registerwith a name and redirect URIs. Registration is open by design — no bearer or admin approval — because MCP clients discover the resource without prior arrangement. The response returnsclient_idand a single-useclient_secretthe client persists locally. Re-registration mints a new pair.User authorises
Client sends the user's browser to
authorization_endpointwithresponse_type=code,client_id,redirect_uri,code_challenge,code_challenge_method=S256, and the requestedscope. The user consents in a ZopNight page listing the scopes and the exact write tools each scope admits, then the browser returns toredirect_uriwithcode.Client exchanges code for tokens
Client POSTs to
token_endpointwithgrant_type=authorization_code,code,code_verifier,client_id, andclient_secret. Response: a short-lived JWTaccess_token(identity + granted scopes), a rotatingrefresh_token, and aConnected Approw visible to the user in ZopNight.Client calls the MCP server
Every JSON-RPC request carries
Authorization: Bearer <access_token>. The gateway validates the JWT, resolves the caller's live role in the target org, and checks the tool against the org's Write access setting and the token's granted scopes.Client refreshes
When the access token nears expiry, the client POSTs to
token_endpointwithgrant_type=refresh_token. The server issues a new access token and rotates the refresh token — the old refresh token remains valid for a 60-second in-row grace window to absorb races, then it is retired. Presenting a retired refresh token triggers family kill on reuse (RFC 9700 §4.14.2): every refresh token in that lineage is revoked, and the user must re-consent.
Discovery endpoints
/.well-known/oauth-protected-resource # RFC 9728
/.well-known/oauth-authorization-server # RFC 8414
/.well-known/oauth-authorization-server/oauth # RFC 8414 (path-suffixed)
/oauth/register # RFC 7591 DCR
/oauth/authorize
/oauth/token
/oauth/revoke # RFC 7009Revocation and lifecycle
- Access tokens are short-lived JWTs; identity/role/scope are re-resolved on every call, so removing a user from an org or dropping their role takes effect on the agent's next request.
- Refresh tokens rotate on every use, with a 60-second in-row grace window; reuse of a retired refresh token kills the entire token family (RFC 9700 §4.14.2).
- Instant revoke via Connected Apps in ZopNight — a user can revoke any connected client at any time, which invalidates its access and refresh tokens immediately.
- Client secrets issued by DCR are single-use per registration; there is no rotation API. Re-register to mint a new pair.
Personal Access Token
For CI, scripts, or any client that cannot drive a browser, mint a PAT.
Open Developer Settings
Click your profile avatar (bottom-left of the sidebar), then Developer Settings ↗.
Create a token
Click Create Token, enter a name (e.g. "CI runner"), choose an expiry, tick the Write capabilities you want it to carry, and click Create Token.
Copy the token immediately
The token is shown once. Store it in your CI's secret store. The Server URL is on the same page.
Send it as Bearer
On every request:
textAuthorization: Bearer <pat>
What your PAT can do
A PAT carries your identity. It is not a separate, narrower account:
- Every call resolves your live role at the moment it is made. Change your role, or get removed from the organisation, and the token's reach changes with it — immediately, with no re-mint.
- The token cannot do anything you cannot do in the UI. It also cannot do less, except for the write capabilities you tick at mint time (see below).
- Tokens are tied to your email, not to one organisation, and they work across every organisation you belong to.
- Tokens have an expiry. When it lapses, create a new one.
Mint the token as the person with the narrowest role that does the job, and keep Write access as low as the job allows.
Write access
The Write access setting (Settings → Organisation) decides how much an agent may change, regardless of auth method.
| Setting | What it admits |
|---|---|
| Read-only | Nothing. Read tools only. |
| Metadata only | Changes to ZopNight's own records: budgets, recommendation status, smart-tag acceptance. No cloud state, no cost. |
| Reversible changes | Bounded blast radius, may affect cost: schedules, overrides, tagging policies, Service deploys, rollbacks, config. |
| Irreversible changes | No undo, or incurs cost: starting/stopping resources, Provisioning jobs, Kubernetes writes, deletes. |
The settings are cumulative: Reversible admits Metadata-only too. The picker in Settings enumerates the exact tools each level turns on, generated from the same manifest the gateway authorizes against.
Some surfaces are excluded at every level and nothing adds them: roles and permissions, user management, organisation deletion, cloud-account deletion, credentials, and bulk actions.