Okapi

MCP & agents

Okapi mounts an MCP server over HTTP at /mcp, inside the same running instance as everything else — there's no separate process to start and no stdio transport. One transport, identical on self-host and cloud: point an agent at your instance's /mcp endpoint and it can read issue context, logs and traces, discover issue deltas, triage issues and performance issues, manage alert rules and notification channels, and provision projects and credentials through the tools below, scoped to what its credential is allowed to see. Agents are never metered and never gated to a paid tier — the whole MCP surface ships in every edition, every plan.

Two ways to authenticate

/mcp accepts two credentials, and they are equivalent once resolved: the same tools, the same scoping, the same roles, the same errors. They differ in how you obtain one, who can revoke it, and what the audit log records next to the actions it takes. There is one exception: personal alert rules belong to a person, so an agent token is always refused on personal-rule calls (see Personal alert rules).

OAuth (okapi_oauth_…) Agent token (okapi_agent_…)
How you get it Sign in and approve in your browser An owner mints it in the dashboard or on the CLI
Best for A person working interactively at a laptop CI, headless agents, shared automation
Lifetime 30 days, then re-approve Until revoked
Revoked by You (Connected apps), an organization owner, or a password reset/change An organization owner
Audit rows Name the human who approved it Name the token, no human
Configuration None — no header, no secret in a file The token lives in the client's config

whoami reports which door a call arrived on (door), and — for OAuth only — whose approval it is acting under (user).

OAuth: the interactive path

With OAuth enabled on the instance and a client that supports its authorization flow, add the server with no header at all:

claude mcp add --scope user --transport http okapi https://your-okapi-host/mcp
claude mcp login okapi

--scope user makes the server available in every project on this machine. claude mcp login okapi opens the consent screen in your browser straight away; without it, Claude Code waits until you run /mcp in a session and choose to authenticate. Codex (codex mcp add okapi --url …) always saves to ~/.codex/config.toml, which is user-wide too, and signs in as part of add; for Cursor, use the global ~/.cursor/mcp.json.

Client Sign in Sign in again (renew, or approve new permissions)
Claude Code claude mcp login okapi claude mcp logout okapi, then claude mcp login okapi
Codex part of codex mcp add; otherwise codex mcp login okapi codex mcp logout okapi, then codex mcp login okapi
Cursor Cursor Settings → Tools & MCPs, next to okapi; or cursor-agent mcp login okapi the same
OpenCode opencode mcp auth okapi opencode mcp logout okapi, then opencode mcp auth okapi

These sign-in commands are for you to run in your own terminal, not for an agent: in Claude Code, signing in first revokes the current approval, and without an interactive terminal the new sign-in can't finish. Sign in from outside any repository that has its own local-scope okapi entry, because the login picks the server by name and a local entry wins. An OAuth approval lasts 30 days; sign in again to renew it. Reconnecting a client can reuse the old approval, so to grant something new — such as access to your personal alert rules, which connections approved before that feature existed don't have — sign out and sign in again so the consent screen appears.

Cloud is not open for signup yet. When it opens, the same command works with the cloud instance's /mcp URL.

The first call gets a 401 pointing at your instance's own authorization server — Okapi is both the authorization server and the protected resource, so authorization never leaves your instance — and the client opens a consent screen in your browser (Claude Code instead marks the server as needing authentication and waits for claude mcp login okapi or /mcp). Sign in if you aren't already; the screen names the client asking, and you choose the organization, the projects, and the role it will get. Approve and the client completes the exchange itself; there is nothing to paste. Deny and no grant exists.

Clients identify themselves by a Client ID Metadata Document — an https:// URL Okapi fetches to learn the client's name and redirect URIs. A client that can't do that may register itself dynamically (RFC 7591) instead; Okapi verifies nothing about such a client, so the consent screen presents it as an unverified application named only by what it calls itself. Registration confers no access on its own and is rate limited.

A grant lives 30 days, and its power is whatever you chose on the consent screen — not something the client asked for. When it expires, sign in again (the table above) to renew it.

Validated OAuth clients: claude.ai and Claude Desktop were walked interactively against a staging instance on 2026-08-24, including browser approval, using a Client ID Metadata Document (CIMD). Add the instance's /mcp URL as a custom connector and leave the Client ID and Client Secret fields blank. Both connect from Anthropic's cloud, so the instance must be publicly resolvable.

Cursor and OpenCode were walked against a staging instance on 2026-08-25, including browser approval, using the registration fallback at POST /oauth/register. Point either client at the instance's /mcp URL; the consent screen labels it an unverified application. These are dated validation records, not a guarantee for every client version.

Agent tokens: the CI and headless path

An agent token is a Bearer credential you paste into a client's configuration — the right shape when there is no human and no browser:

claude mcp add --scope local --transport http okapi https://your-okapi-host/mcp \
  --header "Authorization: Bearer okapi_agent_…"

Run it in the repository's directory. For an organization-wide token, use --scope user instead.

Self-host and cloud differ only in hostname — same transport, same tools, same token format. The documented default is a project-scoped credential per repository, so each codebase talks to exactly its own Okapi project; mint a broader organization-wide token only when an agent genuinely needs to work across projects (e.g. provisioning a new one). Both scopes keep the token out of git, in your Claude Code config (~/.claude.json). A project-scoped token belongs in --scope local, which applies to this repository only, so every repository can hold its own okapi entry. --scope user applies to every project on the machine and holds a single okapi entry: use it for OAuth and organization-wide tokens. Adding a second user-scope okapi entry fails with "already exists"; a local-scope okapi can sit next to the user-scope one and takes precedence in its repository. This Claude Code installation scope is separate from the Okapi credential's project scope. A committed .mcp.json references it through an environment variable instead, as "Authorization": "Bearer ${OKAPI_TOKEN}".

Managing OAuth connections

  • Yours: Account settings → Connected apps lists your still-active grants, across every organization, with what it can reach and when it was last used. Disconnecting takes effect on the next call — the token is checked against the grant every time, never cached.
  • Your organization's: organization Settings → Connected apps (owner-only) lists every member's still-active grants into that organization and lets an owner revoke any of them.
  • A password reset or password change revokes every one of that user's grants, in the same transaction as the credential rotation.

For self-host operators

OAuth on /mcp is on by default and needs no configuration beyond OKAPI_BASE_URL being an absolute https:// origin (or http:// on a loopback host) without userinfo, a non-root path, query, or fragment (it's the OAuth issuer). When it isn't, OAuth stays off, /mcp keeps working on agent tokens alone, and okapi serve logs one WARN naming the problem — it never refuses to boot over it. To turn OAuth off deliberately, set OKAPI_MCP_OAUTH=0 (on self-host, in an override file — see Setting variables the compose file does not list); that closes the door completely and immediately invalidates any tokens it issued. Agent tokens are untouched by the switch.

Approving a new connection does not revoke the old grant; disconnect it in Connected apps.

With the cloud billing capability enabled, /mcp answers 402 subscription_required when the organization has never held a subscription and is not otherwise collecting. A live grant, an unapplied-payment marker, or a quarantine vouch opens that wall. OAuth consent can precede checkout; access follows stored billing state.

Minting an agent token

Dashboard: Settings → Agent tokens (organization settings, owner-only) → New token. Give it a name, a role, and — optionally — narrow it to one project. The plaintext is shown once, alongside a ready-to-paste claude mcp add command with the token already filled in.

CLI, for headless self-host operators or CI:

okapi createtoken --role triage
okapi createtoken --role read --project web-app --name ci

--project <slug> scopes the token to one project; omitted, the token is organization-wide. On a self-host instance (exactly one organization) the organization resolves automatically; on an instance with more than one organization, pass --organization <slug> or the command errors with that instruction. The plaintext and the inline claude mcp add command print once — there's no second chance to retrieve either.

Roles

Three capability tiers, checked on every tool call — the same three whether the credential is an agent token or an OAuth grant (an OAuth grant's role is chosen on the consent screen and can never exceed the approving user's own role in that organization):

Role Can do
read List projects and issues, read issue context, search logs, search traces, list expensive queries, read performance issues, discover deltas, check resolutions and installations, and read team alert rules, alert views, channel metadata (never URLs or secrets) and channel alert history; whoami.
triage Everything read can, plus resolve, unresolve, ignore, and snooze issues and performance issues. Over OAuth only, it also manages the approving user's own personal alert rules and personal alert history (see Personal alert rules). The default role for new tokens.
admin Everything triage can, plus delete issues, bulk deletes, provisioning (create projects with a default DSN key, read and list DSN keys, mint additional DSN keys and source-map upload tokens), and creating, updating, deleting, resetting and testing team alert rules. An organization-wide admin credential can also create, update, delete and test notification channels.

Deletes, alert rule and channel changes, real test sends, minting additional DSN keys and upload tokens, and performance-issue triage need a named confirmation flag in the call (confirmDelete, confirmBulk, confirmChange, confirmSend, confirmCreate or confirm, depending on the tool). create_project needs no flag, although it also mints the project's default DSN key. Changes made over MCP are recorded in the audit log. DSN keys and upload tokens that an agent mints keep working after the agent's credential is revoked; delete them in the project's settings.

An agent token can be revoked at any time from Settings → Agent tokens; revocation is immediate and irreversible (mint a new one to replace it). OAuth grants are revoked from Connected apps, as above.

Tools

The minimum role for each tool is in brackets. A running instance lists the same tools, generated from the same registry, in GET /api/v1/agents.

Identity and issues

  • whoami [read] — the credential's own name, which door it came through (agent_token or oauth, plus the approving user for OAuth), scope, organization, role, rate-limit state, and a deep link. For narrowed credentials, it lists surviving projects; one survivor yields scope:"project", while scope:"projects" can mean several or zero. Its projects field is omitted with zero survivors or organization-wide scope. Dynamically registered application names carry (unverified). It does not list tools.
  • list_projects [read] — every project the credential can see (all of them for an organization-wide one; surviving granted projects for a narrowed one). Deleted projects are skipped; default limit 100, maximum 200.
  • list_issues [read] — list issues in a project; filter by status (unresolved default, all, resolved, ignored, snoozed), level, or a case-insensitive literal query across title, culprit, short issue ID, and error type, with -term exclusions.
  • whats_new [read] — what changed since a release or a recent time window: new issues, regressions, and spiking issues. Pass a known sinceRelease or positive sinceMinutes; the release wins if both are set. New issues include first-release attribution; spikes compare the trailing two daily-count buckets against the preceding daily rate, independently of the boundary. With no project, one survivor yields detail, several yield summary (up to 50 projects, three headlines per bucket); releaseNotSeen flags unknown releases and countsCapped marks floors. nextStep names a slug when a project saw the boundary, otherwise suggests a time window.
  • get_issue_context [read] — the one-shot fix bundle for an issue by short id: a symbolicated stacktrace, breadcrumbs, trace-id-correlated logs, release info, a daily frequency series, affected-user count and sample contexts, similar issues, and the raw event payload. title describes the issue's first event; latestEventTitle describes the latest stored event.
  • check_resolution [read] — did a previous single-issue resolve hold? Compares server receive times against the marker stamped on every update_issue resolve, even without commit/release. Bulk actions preserve earlier markers. With a known resolving release, older releases are excluded and release-less events still count; otherwise all later events count. hasMarker:false means no marker exists.
  • update_issue [triage] — triage by short id: resolve, unresolve, ignore, snooze (with snoozeMinutes), or delete (requires the admin role and a confirmDelete: true flag). resolve also accepts an optional commit/release and note.
  • bulk_update_issues [triage] — apply one triage action to a bounded selection matching a filter (status/level/query), up to 100 matches per call — resolve, unresolve, ignore, snooze, or delete (requires admin and confirmBulk: true). It reports selected IDs, write count, pre-write matching count, and hasMore. Repeat the filter only if the action removes selected issues from it. Bulk resolve records no provenance or fresh marker; earlier single-issue markers remain.
  • search_logs [read] — search a project's logs by level, message query, traceId, attributes, or a sinceMinutes time window.

Traces and performance (see Performance monitoring)

  • search_traces [read] — search trace segments by project, time (default the last 24 hours), duration, error status, release, or environment.
  • get_trace [read] — one trace by its 32-hex trace id: spans, database queries, correlated errors and logs, and performance issues. An organization-wide credential sees every project's segments of the trace. found:false means the trace expired or never existed.
  • list_expensive_queries [read] — normalized database queries ranked by total, count, mean, p95 or maximum duration, or by latest seen, with a sample reference.
  • search_performance_issues [read] — search slow-query and N+1 performance issues by project, detector, status (unresolved default), or text.
  • get_performance_issue [read] — one performance issue by id, with up to 50 recent occurrences. sampleAvailable:false means the raw trace has expired while the issue remains.
  • update_performance_issue [triage] — resolve, unresolve, ignore, or snooze one performance issue, with confirm: true. A snooze needs an until time no more than 30 days ahead.

Provisioning and credentials

  • create_project [admin, organization-wide] — provision a brand-new project and mint its default DSN key in one call.
  • get_dsn [admin] — read a project's DSN (the SDK init string), the same sensitivity as the dashboard's owner-only DSN Keys page. It only reads existing keys; found:false means no key exists. It prefers an enabled key, falling back to a disabled one that must be enabled before ingest works.
  • get_install_guide [admin] — read a platform's install guide with the project's real DSN filled in. Pass a supported platform; the ordinary project scope applies. It selects keys like get_dsn, so check list_dsn_keys for enabled state before sending events. With no key, found:false still returns the full guide with a recovery placeholder.
  • list_dsn_keys [admin] — every DSN key of a project, disabled keys included, each with its DSN.
  • create_dsn_key [admin] — mint an additional DSN key, with confirmCreate: true. Each call creates a new key, so do not retry blindly.
  • create_upload_token [admin] — mint a source-map upload token, with confirmCreate: true. The token is shown only in this response; put it in your CI secret store.
  • verify_installation [read] — is Okapi actually receiving events for this project? Reports any DSN key (including disabled keys), stored events, source maps, and configured alert rules. status is no_key, waiting_for_first_event, test_event_only or installed: test_event_only means every stored event has first exception type Test event; installed means one lacks that marker. This does not independently prove SDK origin or a genuine failure. alertsLive says whether any team or personal rule could deliver an alert, and activeAlertRules lists the team rules; neither proves that a delivery will happen. Correlate the result with your SDK test; diagnosis and reported SDK/environment/release fields are fenced captured data.

Alert rules and history

  • list_alert_rules [read] — team alert rules of a project or view, enabled and disabled, with channel names and kinds. scope:"personal" lists your own personal rules instead (OAuth, triage or admin).
  • list_alert_views [read] — the views this credential covers completely, which a rule or digest can target.
  • get_alert_rule [read] — one rule's configuration. scope:"personal" reads your own personal rule (OAuth, triage or admin).
  • list_notification_channels [read] — channel names, kinds, status and project scope. Channel URLs and secrets are never returned.
  • list_alert_history [read] — what Okapi delivered to channels for a project or view (a view needs an organization-wide credential). scope:"personal" adds your own personal deliveries (OAuth, triage or admin).
  • create_alert_rule, update_alert_rule, delete_alert_rule [triage; team rules need admin] — manage a rule with confirmChange: true (create, update) or confirmDelete: true (delete). Deleting a rule deletes its alert history.
  • test_alert_rule [triage; team rules need admin] — send real test messages to the rule's destinations, with confirmSend: true. MCP tests are limited to one per target per 60 seconds and ten per organization per hour.
  • reset_alert_rules [triage; team rules need admin] — restore a project's default rules, with confirmDelete: true. A team reset keeps your custom team rules. A personal reset deletes your custom personal rules in that project.
  • consolidate_personal_digests [triage, OAuth only] — delete your own seeded per-project digests for the projects in one view, with confirmDelete: true. Create the view digest first with create_alert_rule.

Notification channels (organization-wide admin only)

  • create_notification_channel, update_notification_channel, delete_notification_channel — manage Slack and webhook channels, with confirmChange: true or confirmDelete: true. The channel URL is write-only. Revealing it, rotating the signing secret and Add to Slack stay in the dashboard.
  • test_notification_channel — send one real test delivery, with confirmSend: true. A successful test clears the channel's failure state.

Ordinary project tools take an optional project slug. Omit it only when exactly one granted project still exists: the tool then uses that project, the same one whoami reports. An organization-wide credential, or a grant with several surviving projects, must pass a slug from list_projects. If no granted project survives, mint a new agent token or reconnect the application.

Personal alert rules

The personal-rule branches (scope:"personal" and consolidate_personal_digests) act for the person who approved an OAuth connection, on that person's own rules only. They need a grant at triage or admin. An agent token is always refused, because it has no person behind it. No tool shows another member's personal rules, not even to an owner.

A connection approved before personal alert rules existed does not have access to them. Sign out of that connection and sign in again (see OAuth: the interactive path), so the consent screen appears and records your consent. Reconnecting is not enough, because it can reuse the old approval.

Every tool call is scoped to the credential's organization (and projects, if it's project-scoped) — a credential can never reach another organization's data, and read-role tools expose no product mutations (usage/rate-limit bookkeeping still occurs). Event- and log-derived text (messages, stack frames, breadcrumbs, correlated logs, release names, the raw payload) returned by these tools is wrapped in an explicit untrusted-data envelope before it reaches an agent: it's captured application data, never instructions.

Agent bootstrap

An agent arriving at a running instance with no prior context starts at GET /api/v1/agents: a public, ungated JSON manifest describing how to authenticate (OAuth in the browser or a pasted agent token — no session, no credential granted), the three roles and what each grants, recommended first calls (whoami → list_projects → whats_new / verify_installation), and doc links. Its tool catalog is generated from the same registry the instance's live /mcp endpoint runs, so it can't drift from what's actually callable.

For a signed-in dashboard session, GET /api/v1/organizations/{organizationSlug}/projects/{projectSlug}/install/{node|python|browser|laravel|php|nextjs|go|rails|spring|aspnetcore|rust|phoenix|vue|nuxt|sveltekit}.md returns a DSN-personalized guide for an organization member. This HTTP route requires dashboard session authentication. With an admin MCP credential, prefer get_install_guide(project, platform) for the same guide with the real DSN filled in. On older instances without this tool, use get_dsn with an admin credential and the matching public guide at https://useokapi.app/docs/install/{id}.md. For non-admin credentials, ask an organization owner for the DSN and follow that public guide; get_dsn requires admin too. Send a test event, then call verify_installation to confirm delivery.

Agent Kit ships two skills, served as plain markdown from the instance — GET /api/v1/agents/skills/okapi-setup.md and GET /api/v1/agents/skills/okapi-fix-issues.md — encoding the setup loop (detect stack → install → initialize → test event → verify_installation, then mint a per-repo triage token) and the debugging loop (whats_new → bulk-suppress noise → get_issue_context per issue → fix → check_resolution → resolve-in-commit). There's no installer: an agent fetches the markdown and places it itself — .claude/skills/<name>/SKILL.md for Claude Code, the Cursor rules directory, or a fragment appended to AGENTS.md for Codex.

For AI agents

If you're an agent reading this because a human pointed you at an Okapi instance: don't scrape the dashboard UI or ask for a pasted stack trace. Connect over MCP and work from the real data instead —

  1. whoami to confirm your own scope and role, then list_projects.
  2. whats_new or list_issues (default unresolved) to see what's actually open.
  3. get_issue_context for the full fix bundle on anything you're investigating.
  4. search_logs to pull structured logs correlated by trace id or time window around an error.
  5. search_traces, get_trace or search_performance_issues when the problem is slowness rather than an error.
  6. update_issue or bulk_update_issues to resolve, snooze, or ignore once you've verified a fix — don't leave triage to the human if you've already confirmed the fix landed.

A machine-readable summary of Okapi — what it is, pricing, and where these docs live — is published at /llms.txt.

Next: Telemetry for what an Okapi instance sends home on its own, independent of anything you do with MCP.