Authentication & authorization
The CloudQuell MCP server is an OAuth 2.1 resource server. Access is gated by
standard, short-lived OAuth tokens minted by the CloudQuell identity service
(Amazon Cognito), and every write is protected by a double gate — the admin:write
scope plus an explicit confirm: true argument and a backend org-role check.
OAuth 2.1 + PKCE
Section titled “OAuth 2.1 + PKCE”- Grant: Authorization Code with PKCE (S256) — mandated by the MCP authorization spec for remote HTTP servers.
- Public client: the MCP app client has no secret; PKCE protects the code
exchange. Your MCP client obtains the client id automatically via the
/register(Dynamic Client Registration) shim — you never paste a client id or secret. - Identity provider: the CloudQuell Hosted UI
(
cloudquell-prod-auth.auth.us-west-2.amazoncognito.com), supporting email/password and Google sign-in — the same accounts as the dashboard. - Token lifetimes: access tokens are short-lived (~1 hour); a refresh token keeps the connection alive without re-prompting. Scheduled/agentic use is supported by a long refresh-token lifetime.
Discovery endpoints
Section titled “Discovery endpoints”Clients configure themselves from these (all public, unauthenticated):
| Route | Spec | Purpose |
|---|---|---|
GET /.well-known/oauth-protected-resource |
RFC 9728 | Declares the resource URI + supported scopes; points clients at the authorization server. |
GET /.well-known/oauth-authorization-server |
RFC 8414 | Maps OAuth endpoints onto the CloudQuell Hosted UI (/authorize, /token) and advertises /register. |
POST /register |
RFC 7591 | Dynamic Client Registration shim — returns the shared public PKCE client id. |
Resource indicator / audience
Section titled “Resource indicator / audience”The server’s canonical resource URI — and the OAuth audience — is:
https://mcp.cloudquell.com/mcpClients send resource=https://mcp.cloudquell.com/mcp on the authorize and token
requests (RFC 8707). The server validates the token’s audience against a small
allowlist — its own dedicated MCP client and the CloudQuell dashboard client —
and rejects anything outside it. That is the confused-deputy defense the spec calls
for; accepting the dashboard client as well is deliberate, so a token from your
existing CloudQuell session also works. This URL is both the OAuth
audience/resource identifier and the live endpoint you connect to (the same
https://mcp.cloudquell.com/mcp used everywhere in these docs).
Scopes: read (default) and admin:write
Section titled “Scopes: read (default) and admin:write”The server defines two custom scopes on its resource server:
| Scope | Fully-qualified name | Grants |
|---|---|---|
read |
https://mcp.cloudquell.com/mcp/read |
All 29 read tools. Default — granted unless you opt into more. |
admin:write |
https://mcp.cloudquell.com/mcp/admin:write |
The 14 write tools, in addition to read. |
Plus the standard OIDC scopes (openid, email, profile) used to identify you.
readis the baseline. A token that carries onlyreadcan analyze everything and mutate nothing — every write tool refuses withinsufficient_scopebefore any backend call.admin:writetypically rides the connector token. There is no separate consent screen or second connection that toggles it on. The Dynamic Client Registration shim registers your client for the server’s full advertised scope set, so in practice the token your client receives already includesadmin:write. Because of that, the real protection on any change is not the scope alone — it is the double gate below (confirm: trueand a backend org-role check), so holdingadmin:writedoes not by itself let an agent alter anything.
Mutations require admin:write and confirm: true
Section titled “Mutations require admin:write and confirm: true”Every write tool enforces two independent checks, server-side, before any downstream call:
- The caller’s access token carries
admin:write. Missing →insufficient_scope. - The tool input includes
confirm: true. Missing →confirmation_required.
If either check fails, the tool returns an error and nothing changes — no budget is created, no invite is sent, no channel is touched. This is stricter than relying on the MCP client’s allow/deny prompt: even a misbehaving client cannot mutate without both the scope and an explicit confirmed argument.
// Refused — has admin:write but no confirm:{ "name": "Prod AWS monthly", "amount": 50000, "start_date": "2026-07-01" }// → "confirmation_required: pass confirm:true to perform this write"
// Performed — scope present AND confirm:true:{ "name": "Prod AWS monthly", "amount": 50000, "start_date": "2026-07-01", "confirm": true }The MCP annotations (destructiveHint, etc.) shown in the
Tool Reference are UI hints only; they never gate behavior.
The scope + confirm check is the real control.
Authorization (RBAC) is enforced by CloudQuell
Section titled “Authorization (RBAC) is enforced by CloudQuell”OAuth scope decides read vs. write at the MCP layer. Your role and organization membership still apply downstream:
- The server forwards a token that identifies you (by your Cognito
sub); the CloudQuell backend resolves your organization and role from the database on every request. - Admin-only operations (e.g. renaming the org, managing invites) still require the
appropriate org role server-side. Holding
admin:writedoes not elevate your CloudQuell role — if your account isn’t an org admin, an admin-only call is rejected (403 Admin access required) by the backend regardless of scope.
So a write tool needs: the admin:write scope + confirm: true + the
backend permission for that action under your role.
Org scoping
Section titled “Org scoping”The agent operates within your organization only. Identity is derived from your
token’s sub, mapped to your org membership in CloudQuell — not from anything the
client or agent can set. There is no parameter to “switch” to an org you don’t
belong to. See Access, limits & data scope.
Service-account keys (cak_)
Section titled “Service-account keys (cak_)”For headless / scheduled agents that can’t do an interactive browser login, paid
organizations can mint service-account keys (prefix cak_) from
Settings → API Keys in the dashboard. A key is presented as
Authorization: Bearer cak_…, is read-only, org-scoped, and valid for one year
(revocable immediately). No sign-in, refresh, or client registration is needed —
the key is the credential. See API keys for the full
lifecycle and usage guidance.