OverviewAuthentication

Authentication

Authenticate management requests with a Supabase admin session, and MCP tool calls or HTTP API requests with a scoped mcp_ API key.

Management API authentication

Every endpoint under /admin/mcp (servers, tools, agency access, API keys) requires a Supabase session JWT for an allowlisted admin account. Provide it as a bearer token.

header
Authorizationstring
Required

Supabase session JWT for an allowlisted admin account. Format: Bearer <access_token>.

A missing token, an invalid/expired token, or a token for an account not on the admin allowlist returns 401 with { "error": "Unauthorized" }.

Gateway authentication

The gateway at POST /mcp accepts an mcp_ API key created through the management API. Provide it as a bearer token or in the X-Api-Key header.

header
Authorizationstring

MCP API key as bearer token. Format: Bearer mcp_....

header
X-Api-Keystring

MCP API key. Alternative to the Authorization header.

The key must begin with mcp_. A missing, malformed, or deactivated key returns HTTP 401 with a JSON-RPC error (code -32600).

Scopes

An mcp_ key carries a scopes array that gates which tools it can call (only tools within the scopes are listed; calling any other tool by name answers insufficient_scope naming the scope to add) — and, when the key is sent as a Bearer to the HTTP API, which routes it may call. Scopes use <family>:<action> form, with * wildcards:

FormExampleMeaning
family:readpeople:readRead operations in one family
family:writeinsights:writeWrite operations in one family — implies family:read
family:*dashboards:*Any action on one family
**Everything

An empty scopes array grants nothing. Unrestricted access is the explicit ["*"]. Keys created without a scopes field default to ["*"].

Families

Families follow the plan features they belong to, so a plan and a key describe access in the same words. Twenty-three families:

FamilyGrantsActions
peoplePerson profiles, identities, merges, merge warningsread
eventsEvent volumes, trends, breakdowns, property discovery, Explore queries, tracking coverage, Core Web Vitalsread
sessionsSession analyticsread
replaysSession replay timelinesread
exceptionsError trackingread
heatmapsClick and scroll heatmapsread
bigquery_exportExport status and schemaread
insightsSaved insights, run and previewread, write
dashboardsDashboardsread, write
canvasesCanvasesread, write
segmentsSegments, counts, membershipread, write
constraintsConstraint finder and its benchmarksread, write
correlationCorrelationread
incrementalityIncrementality experiments and coefficientsread, write
contractsEvent contracts and violation reportsread, write
destinationsDestinations, credentials, deliveriesread, write
settingsTracking settings and the ingestion on/off switchread, write
linksLink redirects, click analytics, link webhooks, uptimeread, write
tags / snippets / transformersSDK configurationread, write
airbyteAirbyte sync orchestration — agency-wide keys onlyread, write
agencyClient roster and cross-location rollups — agency-wide keys onlyread

Every tool's exact scope is in the Tool Reference, which is generated from the server's registry. list_clients and select_client need no scope on an agency-wide key.

Key issuance (POST/PATCH /builder/mcp/api-keys) validates every scope string against this catalog and answers 400 invalid_scope — listing the offending strings and every valid one — rather than storing a typo that silently grants nothing. The retired data:* and analysis:* families are rejected the same way; existing keys that held them were expanded to the new families.

A key with a null location is agency-wide (it selects a client per session, or names one per HTTP request); one bound to a location is client-scoped and can never reach an agency-grain operation, whatever its scopes say.

Gateway tools

Gateway (upstream) tools at POST /mcp require <scope_prefix>:call, where <scope_prefix> is the owning server's configured prefix. If the server has no scope prefix, the required scope is upstream:call.

Using an mcp_ key over HTTP

The same mcp_ key is accepted as a Bearer on every /client/v1 and /builder route. It is the scoped credential of the HTTP API: an agency key (ak_) is read-write across the whole agency and a location secret (sk_) is read-only for one location, so an mcp_ key is how you hand an integration exactly one capability.

curl "https://mythic-analytics.gulp.workers.dev/client/v1/data/people?location_id=loc_abc" \
  -H "Authorization: Bearer mcp_..."

Each route requires the scope of the tool that proxies it — the Proxies column of the Tool Reference is the mapping. Rules:

  • Location binding works as for ak_/sk_. A client-scoped key carries its own location; an agency-wide key names one with location_id or X-Location-Id on location-grain routes (400 location_required otherwise).
  • Writes need the :write scope, whichever key shape holds it — unlike sk_, a client-scoped mcp_ key can write.
  • Agency-grain routes (/client/v1/agency/*, /client/v1/airbyte/*, GET /builder/locations) refuse client-scoped keys with 403 agency_key_required.
  • Routes with no tool are closed to mcp_ keys, including an unrestricted one: the OAuth browser legs, the embed SPA's internals, and above all key issuance under /builder/mcp answer 403 not_available_to_scoped_keys. Minting or rescoping a key is the privilege boundary and stays with ak_.
  • A missing scope answers 403 insufficient_scope with the required scope named.
  • Plan entitlements and per-key rate limits apply as on any other key (rate_limit_per_minute, default 60).

Never expose admin session tokens or mcp_ API keys in client-side JavaScript, public repositories, or logs. Both are server-side credentials. The raw mcp_ key is shown only once, at creation.