Atribu
MCP Server

Quickstart

Connect an AI agent to Atribu over OAuth — no account required before you start

The Atribu MCP server speaks OAuth 2.1 with Dynamic Client Registration, so an agent can connect a human who does not yet have an Atribu account. The agent registers a client, builds an authorization URL and hands it over; the human signs up or signs in inside that hand-off and approves.

Claude Desktop, Claude.ai, ChatGPT and Cursor do all of this for you

Add https://mcp.atribu.app/mcp as a custom connector and the client runs the whole flow below on its own — the exact steps per client are on Connect an AI client. The steps here are for an agent, script or CI job driving the flow itself.

Register a client and build the authorize URL

1. Register (RFC 7591)
curl -sX POST https://www.atribu.app/oauth/mcp/register \
  -H "Content-Type: application/json" \
  -d '{
    "client_name": "My Agent",
    "redirect_uris": ["http://127.0.0.1:7788/callback"],
    "token_endpoint_auth_method": "none",
    "grant_types": ["authorization_code", "refresh_token"],
    "response_types": ["code"],
    "scope": "mcp:read"
  }'
201 Created
{ "client_id": "mcpc_9f2c…", "redirect_uris": ["http://127.0.0.1:7788/callback"], "scope": "mcp:read" }

Three scopes exist and each is a separate checkbox on the consent screen. Ask for the least you need:

scopewhat it grants
mcp:readanalytics — campaigns, creatives, ROAS. PII masked.
mcp:read_piithe same, with customer names/emails/phones, where the workspace allows it
mcp:writeconversion write-back to Meta CAPI, on workspaces where the user is an admin with write-back on
2. Authorize URL (PKCE S256 — plain is refused)
import base64, hashlib, os, urllib.parse

verifier  = base64.urlsafe_b64encode(os.urandom(32)).rstrip(b"=").decode()
challenge = base64.urlsafe_b64encode(
    hashlib.sha256(verifier.encode()).digest()
).rstrip(b"=").decode()
state = base64.urlsafe_b64encode(os.urandom(16)).rstrip(b"=").decode()

url = "https://www.atribu.app/oauth/mcp/authorize?" + urllib.parse.urlencode({
    "response_type": "code",
    "client_id": "mcpc_9f2c…",
    "redirect_uri": "http://127.0.0.1:7788/callback",
    "scope": "mcp:read",
    "state": state,
    "code_challenge": challenge,
    "code_challenge_method": "S256",
    "resource": "https://mcp.atribu.app/mcp",
})

Endpoints are discoverable at https://www.atribu.app/.well-known/oauth-authorization-server, and the resource server advertises itself at https://mcp.atribu.app/.well-known/oauth-protected-resource.

Your agent gives the human a URL. They open it, create their account, approve. They come back.

Print it and wait — this is the human's only step.

  • No Atribu account yet? The page sends them to sign in; an unrecognised email goes straight to signup with the pending authorization preserved. After they confirm their email, the confirmation link returns them to your consent screen, not to a dashboard.
  • The consent screen shows your client_name, one checkbox per scope you asked for, and the host behind your redirect_uri (loopback is labelled as a local application). A user with no workspace yet reads "You have no workspace yet — your agent will create one after you approve."
  • Approve redirects to your redirect_uri with code and your state. Compare state before you use code.

Deny, and an expired or malformed request, come back to the same redirect_uri with error + error_description rather than stranding either of you on a page — see the error table in the API quickstart.

Exchange the code for a token

POST /oauth/mcp/token
curl -sX POST https://www.atribu.app/oauth/mcp/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d grant_type=authorization_code \
  -d code=THE_CODE_FROM_THE_CALLBACK \
  -d redirect_uri=http://127.0.0.1:7788/callback \
  -d client_id=mcpc_9f2c… \
  -d code_verifier=THE_VERIFIER_FROM_STEP_1
200 OK
{
  "access_token": "atb_user_…",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "atb_refresh_…",
  "scope": "mcp:read"
}

Access token: 1 hour. Refresh token: 60 days, rotating — persist the new one on every refresh, because replaying an old one revokes the family.

Make your first call

whoami — always call this first
curl -sX POST https://mcp.atribu.app/mcp \
  -H "Authorization: Bearer atb_user_…" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
       "params":{"name":"whoami","arguments":{}}}'

It costs zero units and returns the workspaces and profiles the caller can reach, the default currency, the PII mode and whether write-back is enabled — so the model stops guessing. The same token also works on /api/v1 since #1084 — GET /api/v1/workspaces is its REST equivalent, and profile-scoped routes want an explicit ?profile_id=. See API authentication.

Using a static MCP token instead

For a script or CI job that belongs to one person and needs no consent screen, mint a token by hand:

  1. Log in to Atribu
  2. Go to Developer in the sidebar
  3. Switch to the MCP Tokens tab
  4. Click New token, select at least Read analytics, and copy it

Save your token

The token starts with atb_user_ and is shown only once. Store it somewhere secure.

Terminal
claude mcp add atribu --transport http \
  https://mcp.atribu.app/mcp \
  --header "Authorization: Bearer atb_user_YOUR_TOKEN"

Add to your Cursor MCP settings (.cursor/mcp.json):

.cursor/mcp.json
{
  "mcpServers": {
    "atribu": {
      "url": "https://mcp.atribu.app/mcp",
      "headers": {
        "Authorization": "Bearer atb_user_YOUR_TOKEN"
      }
    }
  }
}

Recommended: one-click connector

For Claude Desktop, the simplest path is the OAuth custom connector — no token needed. See Connect an AI client. The manual config below is an alternative if you prefer a static token.

Add to your Claude Desktop config (claude_desktop_config.json):

claude_desktop_config.json
{
  "mcpServers": {
    "atribu": {
      "url": "https://mcp.atribu.app/mcp",
      "headers": {
        "Authorization": "Bearer atb_user_YOUR_TOKEN"
      }
    }
  }
}

Any MCP client that supports Streamable HTTP transport works. Configure it with:

  • URL: https://mcp.atribu.app/mcp
  • Transport: Streamable HTTP
  • Auth header: Authorization: Bearer atb_user_YOUR_TOKEN

Verify the connection

Health check
curl https://mcp.atribu.app/health/live
Response
{ "status": "ok" }

Example conversation

Here's what a typical interaction looks like in Claude Code:

You: What happened to our ad performance last week vs the week before?

Claude: I'll compare the two periods for you.

[calls compare_periods with last week vs prior week]

Your ad performance improved last week:
- Spend: $2,450 → $2,680 (+9.4%)
- Revenue: $8,200 → $11,400 (+39.0%)
- ROAS: 3.35 → 4.25 (+26.9%)
- Conversions: 42 → 58 (+38.1%)

The jump in revenue is driven primarily by "Summer Sale - Retargeting"
which generated $4,200 in attributed revenue at a 6.8x ROAS.

Data as of: 2026-04-14T18:30:00Z | Model: last_touch | Currency: USD

Workspace resolution

If you belong to multiple workspaces, the AI tool will ask you to specify which one. If you have only one workspace with one profile, it's selected automatically.

Next steps

On this page