Context: we had built Meta campaigns by agent-driving Ads Manager over CDP (virtualized tables, enhancements reverting on drafts, stale SPA panels, relay deaths; ~3-5 min per ad). Meta now publishes official programmatic surfaces that make that unnecessary for an advertiser's own account.
Ads CLI (https://developers.facebook.com/documentation/ads-commerce/ads-ai-connectors/ads-cli/ads-cli-overview.md): pip install meta-ads (Python >=3.12) or brew tap facebook/fb && brew install facebook/fb/meta-ads; command meta ads <resource> <action>. Auth is a system user token (Admin or Employee) with business_management, ads_management, pages_show_list, pages_read_engagement, pages_manage_ads, read_insights. creative create --image ./x.png uploads local media; --targeting @file.json and --asset-feed-spec @file.json pass raw API shapes (placement-customized 1:1 + 9:16); --execution-options validate_only is a dry run on campaign/ad set create/update; JSON output and exit codes 0-5 for scripting.
Ads MCP (https://developers.facebook.com/documentation/ads-commerce/ads-ai-connectors/ads-mcp-server/ads-mcp-server-get-started.md): remote at https://mcp.facebook.com/ads; works with OAuth (needs your app id as client id + redirect URL) or Authorization: Bearer <token>. Token needs ads_mcp_management plus ads_read or ads_management. Only Employee-role system user tokens work; Admin-role system user tokens are rejected. Write tools create entities paused. Includes A/B test and lift-study tools, previews, breakdown reporting, activity log. Tool list has no media upload tool, so do creative upload via CLI/API. Per-account guardrail 'rules' (e.g. deny budgets above a cents ceiling) exist but are limited availability (unenrolled business gets error code 10) and only constrain MCP agents, not direct API calls.
Access/limits (https://developers.facebook.com/documentation/ads-commerce/marketing-api/get-started/authorization.md, .../overview/rate-limiting.md): managing only your own ad account needs standard access to ads_read/ads_management, no App Review. Default Limited tier: max score 60 per ad account, read=1 write=3, 300s decay, 300s block when hit; so a ~20-write campaign build hits one throttle wait. Full tier: 500+ calls in 15 days with <15% error rate. Ad set budget changes max 4/hour.
Enhancements: opt in/out per feature via degrees_of_freedom_spec.creative_features_spec (https://developers.facebook.com/docs/marketing-api/creative/advantage-creative/get-started), and GET reads back true state, unlike the UI where unchecks reverted on draft objects.