Authentication
All MetadataONE MCP requests are authenticated with a bearer token scoped to a single account. Keys are minted from the app, stored server-side only, and can be rotated or revoked at any time.
Mint an API key
- Sign in at app.metadataone.com
- Open Settings → API Keys
- Click Create Key, name it after the agent that will use it (
claude-code-gil,hermes-prod,paperclip-sandbox) - Set scopes (see below) and copy the token — it's shown exactly once
Keys are shown once. If you lose a key, rotate it rather than contacting support. Treat tokens like passwords — never commit to git, never log them, never paste into chat.
Scopes
Keys can be scoped to limit blast radius. If a key only needs analytics, don't grant launch permissions.
| Scope | Grants | Destructive |
|---|---|---|
read:all | All get_*, search_*, list_*, *_stats, *_insights tools | No |
write:audiences | Create, update, archive audiences & target groups | No (reversible) |
write:creatives | Generate/upload creatives, build ads | No |
write:campaigns | Create & edit campaigns in Draft, excluding launch | No |
launch:campaigns | launch_campaign, manage_campaign — real spend begins | Yes |
write:integrations | Connect/disconnect channels & CRMs | Yes |
admin:* | Account impersonation, billing, user mgmt | Yes |
Using the key
As an environment variable
The MCP client reads the key from METADATA_API_KEY by default:
export METADATA_API_KEY="md1_live_7f3a…" npx @anthropic/mcp-client add metadataone
In Claude Code
Add to your ~/.config/claude-code/mcp.json:
{
"mcpServers": {
"metadataone": {
"command": "npx",
"args": ["-y", "@metadataone/mcp-server"],
"env": {
"METADATA_API_KEY": "md1_live_7f3a…"
}
}
}
}
Direct HTTP (non-MCP)
If you're not using the MCP protocol, every tool is also exposed at https://mcp.metadataone.com/v1/<tool_name>:
curl -X POST https://mcp.metadataone.com/v1/get_account_details \ -H "Authorization: Bearer $METADATA_API_KEY" \ -H "Content-Type: application/json" \ -d '{}'
Multi-account access
If your user has access to multiple MetadataONE accounts (agencies, holding companies), call
list_user_accounts first and include X-Account-ID on subsequent requests:
accounts = mcp.list_user_accounts() for a in accounts: stats = mcp.account_level_stats( account_id=a["id"], # passed on every call date_range="last_30_days", ) print(a["name"], stats["total_spend"])
Key rotation
Best practice is to rotate keys quarterly, and immediately on any of:
- Employee or contractor offboarding
- Suspected key leak (logs, shared screen, repo commit)
- Scope expansion or reduction for the agent
Rotation is atomic — the old key stays valid for 15 minutes after a new one is issued, so you can deploy the new key without downtime. Older keys are hard-revoked after the grace window.
Auth errors
| HTTP | Code | Meaning |
|---|---|---|
401 | missing_key | No Authorization header |
401 | invalid_key | Key is revoked, rotated out, or malformed |
403 | scope_denied | Key is valid but lacks the scope for this tool |
403 | account_mismatch | X-Account-ID not accessible to this user |
402 | insufficient_credits | Credit balance is zero — top up or upgrade tier |
Next: with a key in hand, connect MetadataONE to your MCP client, or jump straight to shipping your first campaign.