Shared schemas and guardrails
Used by all MGID MCP skills. Tool names: tool reference.
Thresholds marked ASSUMPTION are unvalidated defaults — tune per account
after backtesting (see threshold assumptions).
Recommendation schema
Signal skills emit objects in this shape:
{
"id": "rec-1-campaign-12061865-source-242669",
"source_skill": "mgid-source-auditor",
"action_type": "block_source",
"entity": {
"type": "source",
"id": "242669",
"name": "example.pt",
"campaign_id": 12061865
},
"reason": "CPA $32.05 is 2.1× target ($15.50) with 828 clicks in 7d",
"evidence": {
"metric": "cpa",
"current": 32.05,
"target": 15.5,
"baseline": null,
"sample_size": { "clicks": 828, "conversions": 5, "spend_usd": 160.25 }
},
"proposed_change": {
"field": "status",
"from": "active",
"to": "blocked"
},
"confidence": "high",
"risk": "low",
"impact_estimate": {
"spend_delta_daily_usd": [-23, -18],
"conversions_delta_daily": null,
"notes": "Estimated wasted spend removed"
},
"blocked_by": []
}
Use human-readable id values (rank + entity), not UUIDs.
action_type enum
| Value | ads-mcp write (when available) |
|---|---|
increase_budget |
update_campaign (limits.dailyLimit) |
increase_tcpa |
update_campaign (bidding.price) |
reallocate_budget |
update_campaign (limits) |
adjust_qf |
update_quality_factors |
block_source / unblock_source |
update_source_filters |
block_widget / unblock_widget |
update_source_filters |
block_provider / unblock_provider |
update_source_filters or provider API |
pause_teaser / unpause_teaser |
set_teaser_status |
alert_anomaly |
none |
fix_tracking |
none (guidance) |
launch_teaser_variant |
manual / future tool |
entity.type enum
account | campaign | source | widget | provider | teaser
OptimizationPlan schema
Written to a file (e.g. optimization-plan-{plan_id}.json), not pasted into chat.
{
"plan_id": "opt-2026-07-06-001",
"mode": "simulation",
"generated_at": "2026-07-06T14:00:00Z",
"scope": {
"auth_id": 200316,
"client_id": 330838,
"account_id": 330838,
"total_active_campaigns": 16,
"analyzed_campaign_ids": [12061397, 12061865],
"analyzed_count": 16,
"scope_mode": "all_active",
"scope_limit": 25,
"user_confirmed": true
},
"date_range": { "from": "2026-06-29", "to": "2026-07-05" },
"goal": { "type": "cpa", "target": 15.5, "target_source": "campaign_bidding" },
"gates": { "tracking_health": "pass", "details": [] },
"recommendations": [],
"suppressed": [],
"stats_snapshot": {
"12061865": { "spent": 7422.99, "conversions_buy": 439, "cpa": 16.91 }
}
}
Stats snapshot (apply-time drift check)
Store plain numeric aggregates per campaign at plan generation. At apply, re-fetch
get_campaign_statistics totals; if spent or CPA moved more than
10% (ASSUMPTION) vs snapshot, warn and require re-confirmation.
Do not use sha256 — agents compare numbers directly.
Chat vs file output
| Channel | Content |
|---|---|
| Chat | Summary block + recommendation table only |
| File | Full OptimizationPlan JSON for apply phase |
Do not emit full plan JSON or audit JSON into chat unless the user asks.
Global guardrails
- Never apply without explicit user approval.
- ASSUMPTION min data: sources/widgets/providers ≥ 50 clicks or ≥ 5 conversions; teasers ≥ 100 clicks or 1,000 impressions; budget moves need ≥ 3 days donor spend.
- ASSUMPTION max budget shift 20% of donor daily limit per plan.
- ASSUMPTION max QF change ±25% per entity per plan.
- ASSUMPTION min spend $10 before block recommendation.
- Never pause the last active teaser in a campaign.
- Return impact ranges, confidence, and risk.
- CPA Tune learning: do not recommend manual source blocks on campaigns in learning phase — see threshold assumptions.
Suppression reason codes
| Code | Meaning |
|---|---|
tracking_unhealthy |
Failed tracking gate |
insufficient_data |
Below min clicks/spend |
cpa_tune_learning |
CPA Tune still learning — manual block harmful |
guardrail_cap |
Exceeded max QF or budget shift |
last_active_teaser |
Cannot pause only creative |
top_converter |
Block downgraded |
permission_denied |
Missing write scope |
mcp_tool_unavailable |
Write tool not exposed |