Errors & troubleshooting
Every error response follows the JSON-RPC 2.0 envelope:
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32004,
"message": "Human-readable description",
"data": { "type": "tier_required", "retryable": false, "action": "https://app.adcommand.io/billing" }
}
}The HTTP status code is also set (401 / 402 / 404 / 429 / 500 etc.) for tools that filter by status without parsing JSON.
error.data (machine-readable, optional). Actionable errors include a data object so your agent can branch on the failure without parsing the message string:
| Field | Meaning |
|---|---|
type | One of unknown_tool, tier_required, insufficient_credits, rate_limited, invalid_input, upstream_error, internal_error |
retryable | true if retrying the same call later may succeed (transient / rate-limited) |
retryAfterSeconds | When retryable, how long to wait before retrying |
action | A URL or short instruction to resolve it (e.g. the billing page) |
Auth errors (401)
| Code | Message | Cause | Fix |
|---|---|---|---|
-32001 | Missing Authorization: Bearer header | No Authorization header in the request | Re-check ~/.claude.json formatting |
-32001 | Invalid key format (must start with ac_) | Auth header doesn't start with ac_ | Re-paste the cleartext key from the email or Settings dialog |
-32001 | Invalid or revoked key | Key not found, revoked, or expired in mcp_api_keys | Check key status at Settings → API Keys; mint a new one if revoked |
Rate / tier / quota errors (429)
| Code | Message | Cause | Fix |
|---|---|---|---|
-32002 | Rate limit exceeded. Retry after Ns. | More than 60 calls/min on this single key | Wait the suggested seconds, or split traffic across multiple keys |
-32003 | Daily credit cap reached (X/Y credits in last 24h on TIER tier). | Per-tier daily cap: Starter 1500, Pro 5000, Agency 15000 | Rolls off automatically. To raise the cap, upgrade tier |
Tier-gate errors (402, code -32004)
data.type is tier_required, retryable is false, and action is the billing URL — so an agent should upgrade or pick a different tool rather than retry.
| Message | Cause | Fix |
|---|---|---|
Tool 'generate_doodle_vsl' requires 'agency' tier or higher. | Your subscription tier is below what the tool requires | Upgrade to the required tier or switch to a tool your tier supports |
Tier matrix (current):
| Tier required | Tools |
|---|---|
| Starter (default) | All free tools + ad_image, ad_copy, image_variations, carousel, messaging_angles, scrape_offer, pull_reviews, analyze_ad_image, audience_research, decide_creative_strategy, broll_video |
| Pro | All Starter tools + video_reel, vsl_script, email_campaign, find_winning_ads, add_video_captions |
| Agency | All Pro tools + doodle_vsl |
Tool dispatch errors
| Code | Message | Cause | Fix |
|---|---|---|---|
-32601 | Method not found: X | Method name typo (most common: typo in tools/call) | Use exactly tools/list, tools/call, initialize, or notifications/initialized |
-32601 | Unknown tool: X. Available tools: ... (HTTP 404, data.type = unknown_tool) | Tool name typo or tool not registered. Note: the list shows the advertised tools; some legacy tools (e.g. generate_ad_copy) still work via tools/call even though they're no longer listed — prefer generate_copy. | List available tools via tools/list |
-32603 | Missing tool name | params.name was empty or not a string | Pass a non-empty name string in params |
Tool-side errors (passed through from underlying edge functions)
When a wrapped tool reaches the actual generation pipeline and that pipeline errors, the failure is mapped to a structured, recoverable code so your agent knows how to react: 402 insufficient credits (-32005) or tier (-32004); 429/5xx upstream (-32010, retryable: true — safe to retry); other 4xx invalid input (-32011, fix the args). Common patterns:
| Tool | Common error | Cause | Fix |
|---|---|---|---|
generate_ad_copy | Anthropic API key required for Claude | LOCAL dev environment without ANTHROPIC_API_KEY | Production has this set; only seen in local-dev usage |
generate_doodle_vsl | Missing required fields: script, voiceId, userId | Missing script in args | Pass script as a string. userId is auto-injected by the MCP server. |
generate_broll_video | Missing required fields: script, voiceId | Missing script | Required field; voiceId defaults to Brian if omitted |
| Any async tool | Job not found or not owned by this user (in check_generation_status) | jobId/jobType mismatch, or job belongs to a different user | Re-check the jobId returned by the original async call |
| Any paid tool | Insufficient credits. | Org credit balance below tool cost | Top up credits at Billing |
Strategist-specific errors
| Message | Cause | Fix |
|---|---|---|
ANTHROPIC_API_KEY not configured on this environment | Production env var missing (rare — should always be set on prod) | Contact support |
Strategist returned invalid JSON. Raw output: ... | Anthropic returned non-JSON despite the strict prompt | Retry the call once; if persistent, file a bug |
Strategist response missing manifest array | Schema validation rejected the LLM's output | Same as above — usually a one-off Claude oddity, retry |
Claude Code connection issues
| Symptom | Fix |
|---|---|
/mcp shows ad-command ✗ disconnected | Restart Claude Code. Verify auth header in ~/.claude.json. Check the Bearer token has no whitespace or newlines around it. |
Server health works (curl https://...mcp-server → 200) but Claude Code can't connect | Some Claude Code versions cache MCP server lists at session start. A full restart (not just slash-command refresh) is required after config changes. |
| Tools list is empty | Old client version cached the list before tools were registered. Restart Claude Code. |
Network / infrastructure
| Symptom | Cause | Fix |
|---|---|---|
connect: timeout | Outbound port 5432 (Postgres direct) blocked on cellular networks | Switch to a wifi network for any psql / Supabase CLI commands. The MCP server itself uses HTTPS (port 443) and works on any network. |
503 Service Unavailable | Edge function cold start exceeded the threshold | Retry after 1-2 seconds |
Where to dig deeper
- Claude Code logs:
~/.claude/logs/(or your platform equivalent) - Supabase function logs: Dashboard → Functions → mcp-server → Logs
- Audit trail: every authenticated request writes to
mcp_audit_logs. If you self-host or have admin SQL access:
-- Recent failures
SELECT created_at, tool_name, status, error_message, duration_ms
FROM mcp_audit_logs
WHERE status != 'ok' AND created_at > now() - interval '1 hour'
ORDER BY created_at DESC
LIMIT 20;If something's still confusing, open an issue or email support.