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.