> ## Documentation Index
> Fetch the complete documentation index at: https://ago.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP OAuth Reference

> How AGO's OAuth 2.1 provider works and how to register a new MCP client.

AGO's MCP server implements OAuth 2.1 with PKCE for clients that don't support custom HTTP headers (e.g. Claude Web). Existing X-API-Key authentication continues to work unchanged for SDK / Zapier / CLI integrations.

## Per-tenant URLs

All endpoints are tenant-scoped via subdomain:

| Endpoint                                 | Path                                                                     |
| ---------------------------------------- | ------------------------------------------------------------------------ |
| Authorization Server metadata (RFC 8414) | `https://<tenant>.api.useago.com/.well-known/oauth-authorization-server` |
| Protected Resource metadata (RFC 9728)   | `https://<tenant>.api.useago.com/.well-known/oauth-protected-resource`   |
| Authorize                                | `https://<tenant>.api.useago.com/api/v1/oauth/authorize/`                |
| Token                                    | `https://<tenant>.api.useago.com/api/v1/oauth/token/`                    |
| Revoke                                   | `https://<tenant>.api.useago.com/api/v1/oauth/revoke/`                   |

The MCP resource itself is `https://<tenant>.api.useago.com/api/v1/mcp`.

## Supported flow

* **Grant type**: `authorization_code`
* **PKCE**: required (`S256` only — `plain` rejected)
* **Token format**: opaque (not JWT)
* **Access token TTL**: 1 hour
* **Refresh token TTL**: 30 days, with rotation and a 30-second grace period (covers concurrent-refresh races from pipelined clients)
* **Authorization code TTL**: 60 seconds
* **Public clients**: yes — no `client_secret` required when `token_endpoint_auth_method=none`
* **Per-tenant isolation**: each tenant has its own database; a token issued in tenant A's DB cannot be looked up from tenant B's MCP URL — replay attempts return 401

## What's not (yet) supported

* **Dynamic Client Registration (RFC 7591)** — the `registration_endpoint` is intentionally absent from the metadata document. Register clients manually as below.
* **Client credentials / device flow** — only authorization-code is implemented.
* **OIDC ID tokens** — the resource model is OAuth 2.1, not OIDC.
* **Token introspection (RFC 7662)** — not exposed to third parties.

## Register a new MCP client

If you build an MCP client (Cursor, Windsurf, an internal agent), email **[support@useago.com](mailto:support@useago.com)** with:

* The product name (shown to end-users on the consent screen).
* A list of redirect URIs (HTTPS only, exact match).
* The scopes you'll request by default.
* Whether you're a public (no secret) or confidential (server-side, with secret) client.

We respond with a `client_id`. We're tracking demand — once a few more clients ask we'll ship Dynamic Client Registration.

## Sample auth-code flow (curl)

```bash theme={null}
# 1. Generate PKCE pair
verifier=$(openssl rand -base64 60 | tr -d '=+/' | cut -c1-64)
challenge=$(printf '%s' "$verifier" | openssl dgst -sha256 -binary | openssl base64 | tr -d '=' | tr '/+' '_-')

# 2. Open in a browser:
# https://acme.api.useago.com/api/v1/oauth/authorize/
#   ?client_id=claude-web
#   &redirect_uri=https://your-app/callback
#   &response_type=code
#   &scope=knowledge:read
#   &state=xyz
#   &code_challenge=$challenge
#   &code_challenge_method=S256
# After Allow, you receive ?code=AUTH_CODE&state=xyz at your redirect.

# 3. Exchange the code:
curl https://acme.api.useago.com/api/v1/oauth/token/ \
  -d grant_type=authorization_code \
  -d code=$AUTH_CODE \
  -d client_id=claude-web \
  -d redirect_uri=https://your-app/callback \
  -d code_verifier=$verifier
```

The full flow plus an MCP call is wrapped in `scripts/oauth_smoke.sh` in the AGO repository.

## Refresh

```bash theme={null}
curl https://acme.api.useago.com/api/v1/oauth/token/ \
  -d grant_type=refresh_token \
  -d refresh_token=$REFRESH_TOKEN \
  -d client_id=claude-web
```

Concurrent refresh: two requests with the same `refresh_token` arriving within 30 seconds both succeed. Outside that window, replaying an already-rotated refresh token revokes the entire chain (RFC 6749 §10.4 reuse detection).

## Revoke

```bash theme={null}
curl https://acme.api.useago.com/api/v1/oauth/revoke/ \
  -d token=$ACCESS_OR_REFRESH_TOKEN \
  -d client_id=claude-web
```

A revoked access token returns 401 on the next MCP call (no cache in MVP). Active SSE streams live until the client reconnects.
