Developers

MCP Authentication & API

Two credential types work interchangeably at https://api.agently.dev/mcp, both sent as a standard bearer token:

Authorization: Bearer <credential>
API keys (agently_sk_...)OAuth 2.1 (agently_at_...)
Best forDeveloper tools you configure by hand: Claude Code, Cursor, VS Code, scriptsDirectory clients: Claude Desktop / claude.ai connectors, ChatGPT
SetupMint in Settings → API keys, paste into configAutomatic — the client discovers the flow, you approve in the browser
WorkspaceChosen when the key is mintedChosen on the consent screen
LifetimeUntil revokedAccess 1 h, auto-refreshed (refresh 30 d, rotating)

Every credential is scoped to one workspace, decided when it's created. The server derives the workspace from the credential on every request — tools never accept a workspace parameter.

API keys

Minted in Settings → API keys by any workspace member.

  • Read-only by default. Enable Allow writes at mint time to unlock the remember tool.
  • Shown once. Only a hash is stored — if you lose a key, revoke it and mint a new one.
  • Limits: 10 active keys per workspace, 120 requests/minute per key.
  • Revocation is immediate, from the same settings page.

Key management API

The settings page is a UI over three REST endpoints (signed-in Agently user with workspace membership required):

GET    /api/v1/workspaces/{workspaceId}/api-keys
POST   /api/v1/workspaces/{workspaceId}/api-keys        { "name": "...", "canWrite": false }
DELETE /api/v1/workspaces/{workspaceId}/api-keys/{keyId}

POST returns 201 with the key metadata plus "key": "agently_sk_..." — the only time the raw key is returned. 409 when the workspace already has 10 active keys. Listing never returns secrets; revoked keys stay listed for audit.

OAuth 2.1

Agently runs a spec-complete OAuth 2.1 authorization server for MCP clients. If your client supports MCP authorization, everything below happens automatically — this section is for implementers.

Discovery (RFC 9728 + RFC 8414): an unauthenticated request to /mcp returns 401 with

WWW-Authenticate: Bearer resource_metadata="https://api.agently.dev/.well-known/oauth-protected-resource"

and the metadata documents live at:

  • https://api.agently.dev/.well-known/oauth-protected-resource
  • https://api.agently.dev/.well-known/oauth-authorization-server

Client registration (RFC 7591, no pre-approval needed):

curl -X POST https://api.agently.dev/oauth/register \
  -H 'Content-Type: application/json' \
  -d '{ "client_name": "My Agent", "redirect_uris": ["https://myapp.example/callback"] }'

Returns a client_id. Public clients only — there are no client secrets; PKCE (S256) is mandatory. Redirect URIs must be https, loopback http (localhost / 127.0.0.1), or a native app scheme.

Authorization: send the browser to

https://api.agently.dev/oauth/authorize
  ?client_id=...&redirect_uri=...&response_type=code
  &scope=brain:read brain:write
  &code_challenge=...&code_challenge_method=S256&state=...

The user signs in, picks a workspace, chooses whether to grant write access, and your redirect URI receives ?code=...&state=.... Codes are single-use and expire in 10 minutes.

Token exchange:

curl -X POST https://api.agently.dev/oauth/token \
  -d grant_type=authorization_code \
  -d code=... -d client_id=... \
  -d redirect_uri=... -d code_verifier=...
{
  "access_token": "agently_at_...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "agently_rt_...",
  "scope": "brain:read brain:write"
}

Refresh with grant_type=refresh_token. Refresh tokens are rotating and single-use — each refresh returns a new pair and retires the old one, including the old access token.

Scopes: brain:read grants the five read tools (always granted); brain:write grants remember (the user can decline it on the consent screen).

The MCP endpoint

POST https://api.agently.dev/mcp

Speaks MCP Streamable HTTP (spec revision 2026-07-28, stateless). Send JSON-RPC with Content-Type: application/json and Accept: application/json, text/event-stream; responses stream as Server-Sent Events. There are no sessions — every request is self-contained, and GET / DELETE on /mcp return 405.

Errors & limits

StatusMeaningWhat to do
401Missing, invalid, expired, or revoked credentialCheck the bearer token; OAuth clients follow the WWW-Authenticate pointer to re-authorize
405GET/DELETE on /mcpThe server is stateless — use POST
429Rate limit exceededBack off — 120 requests/minute per credential, with RateLimit-* headers
400 (OAuth){ "error": "...", "error_description": "..." }invalid_grant on expired/replayed codes and rotated refresh tokens — restart the flow

Tool-level failures return a normal MCP result with isError: true and a short explanation. Not-found cases (unknown entity, empty brain) are not errors — they return guidance text so agents can self-correct.

Writes via remember count against the workspace's Brain ingest quota (Settings → Usage). At the plan cap, writes are rejected with a clear message; reads are unaffected.