{
  "markdown": "# Meta Ads MCP by ScaleForge\n\n> **Control Facebook & Instagram Ads from Claude, ChatGPT, Cursor, or any MCP-compatible agent.**\n>\n> Direct Meta Graph API v24.0 wrapper. 32 tools. No backend required — just bring your own Meta access token.\n\n[![npm](https://img.shields.io/npm/v/@getscaleforge/mcp-meta-ads.svg)](https://www.npmjs.com/package/@getscaleforge/mcp-meta-ads)\n[![license](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)\n[![Node](https://img.shields.io/badge/node-%E2%89%A520-blue.svg)](#prerequisites)\n\n---\n\n## The problem\n\nMeta's Marketing API is powerful but punishing. Anyone who's tried to automate Meta Ads has run into these five walls:\n\n1. **Rate-limit whack-a-mole (error code #17).** Your script hits `User request limit reached` halfway through a launch and leaves campaigns in a half-configured state. Meta's per-account budget of calls resets over 5 minutes, but nothing in the API tells you that without context.\n2. **Token expiry chaos.** User access tokens from the Graph API Explorer die every ~2 hours. You fix a bug, come back from lunch, and every request is suddenly `(#190) Error validating access token`.\n3. **v22 → v24 deprecations (Sept 2025).** `instagram_actor_id` → `instagram_user_id`, `degrees_of_freedom_spec` is gone entirely, `asset_feed_id` has been deprecated since v3.1. Copy-pasted sample code from Stack Overflow breaks silently.\n4. **Image hashes are per-ad-account.** An image uploaded on Account A cannot be used on Account B — you get `Image Not Found` on the second account. Video IDs are global, but image hashes are not. This trips up 100% of first-time multi-account automations.\n5. **The 250-ads-per-Page cap.** Meta limits ads-running-or-in-review per Page (not per account) — and this limit is shared across every account using that Page. Overshoot and the 251st ad silently fails review.\n\n## The solution\n\nThis MCP is a thin, typed wrapper over Meta's Graph API with those five pains baked out:\n\n- **Auto-batch for bulk ops** (`pause_campaigns_batch`, `activate_campaigns_batch`, `update_bids_batch`) — up to 50 ops per HTTP request, chunked automatically. Sidesteps rate-limit code #17 for bulk work.\n- **Pre-flight ads_volume check** before every bulk activation — warns you when a Page is near the 250-ad cap, per ad account, before Meta silently fails the reviews.\n- **Enhanced error messages** with actionable links — when your token expires or a rate limit fires, the MCP tells your agent exactly what to do (create a System User token, wait 5 min, etc.).\n- **v24.0 everywhere** — current field names, no deprecated spec shapes.\n- **PBIA auto-provisioning** (`get_pbia`) — when a Page has no linked Instagram account, the MCP creates a Page-Backed Instagram Account on demand so IG placements work.\n\nNo ScaleForge backend is in the chain. Your agent → this MCP → `https://graph.facebook.com/v24.0/*`. That's it.\n\n---\n\n## Hosted endpoint (no install)\n\nUse the ScaleForge-hosted Streamable HTTP endpoint — zero install, nothing to run locally:\n\n- **Smithery listing:** `https://smithery.ai/server/kirichyk-misha/meta-ads` (one-click install for Claude Desktop, Cursor, Windsurf, Continue, ChatGPT Desktop — Smithery prompts for your Meta token, writes the config).\n- **Direct URL** for custom clients: `https://getscaleforge.com/mcp` (MCP Streamable HTTP). Supply your token via Smithery session config or `Authorization: Bearer <token>` header.\n\nPrefer a local npm install? Use the stdio package below.\n\n---\n\n## Quick start — pick one\n\n### Smithery (easiest, auto-configures the client)\n\n```bash\nnpx -y @smithery/cli install @getscaleforge/mcp-meta-ads --client claude\n# also: --client cursor | --client windsurf | --client continue\n```\n\nSmithery will prompt you for the Meta access token and write the config file.\n\n### Claude Code CLI\n\n```bash\nclaude mcp add scaleforge \\\n  --env META_ACCESS_TOKEN=YOUR_TOKEN \\\n  -- npx -y @getscaleforge/mcp-meta-ads\n```\n\nVerify with `claude mcp list`.\n\n### Claude Desktop (manual JSON config)\n\nEdit `~/Library/Application Support/Claude/claude_desktop_config.json` on macOS (or the Windows / Linux equivalent — Claude Desktop creates it if missing):\n\n```json\n{\n  \"mcpServers\": {\n    \"meta-ads\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@getscaleforge/mcp-meta-ads\"],\n      \"env\": {\n        \"META_ACCESS_TOKEN\": \"YOUR_TOKEN_HERE\"\n      }\n    }\n  }\n}\n```\n\nRestart Claude Desktop. The 32 tools appear under the hammer icon.\n\n### Cursor\n\nCreate `.cursor/mcp.json` in your project (or `~/.cursor/mcp.json` globally):\n\n```json\n{\n  \"mcpServers\": {\n    \"meta-ads\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@getscaleforge/mcp-meta-ads\"],\n      \"env\": { \"META_ACCESS_TOKEN\": \"YOUR_TOKEN_HERE\" }\n    }\n  }\n}\n```\n\n### Local test (no client setup)\n\n```bash\nMETA_ACCESS_TOKEN=YOUR_TOKEN npx -y @getscaleforge/mcp-meta-ads\n```\n\nThe server starts on stdio. Poke it interactively with `@modelcontextprotocol/inspector`:\n\n```bash\nnpx -y @modelcontextprotocol/inspector \\\n  env META_ACCESS_TOKEN=YOUR_TOKEN npx -y @getscaleforge/mcp-meta-ads\n```\n\n---\n\n## Architecture\n\n```\n┌──────────────┐       MCP stdio        ┌───────────────────┐    HTTPS + OAuth token    ┌──────────────────────┐\n│ Claude / GPT │ ◄────────────────────► │  mcp-meta-ads     │ ◄───────────────────────► │  Meta Graph API v24  │\n│   Cursor     │   JSON-RPC over stdio  │  (this package)   │   graph.facebook.com      │  Marketing API       │\n│ ChatGPT Desk │                        │                   │                           │                      │\n└──────────────┘                        └───────────────────┘                           └──────────────────────┘\n```\n\nThe MCP is a thin, typed translation layer. It does not cache, does not proxy, does not phone home. Every call goes from your machine straight to Meta's servers with your token.\n\n---\n\n## Get a Meta Access Token\n\nYou need an access token with `ads_management`, `ads_read`, `business_management`, and (for Page-scoped work like PBIA provisioning) `pages_read_engagement` + `pages_manage_ads`.\n\nThere are two kinds of tokens. Pick based on your use case.\n\n### Option 1 — Quick token (2 minutes, expires in ~2 hours)\n\nGood for: trying the MCP, quick experiments, one-off scripts.\n\n1. Open the [Graph API Explorer](https://developers.facebook.com/tools/explorer/).\n2. In the **User or Page** dropdown, select **User Token**.\n3. Click **Add a Permission** and select: `ads_management`, `ads_read`, `business_management`, `pages_read_engagement`, `pages_manage_ads`.\n4. Click **Generate Access Token** and approve the dialog.\n5. Copy the token at the top. That's your `META_ACCESS_TOKEN`.\n\nThe token expires in ~2 hours. When it dies, the MCP will return an enhanced error pointing you here.\n\n### Option 2 — Stable token (never expires) <a id=\"stable-tokens\"></a>\n\nGood for: production, scheduled jobs, anything you don't want to re-auth every 2 hours.\n\nYou generate a **System User** token inside **Meta Business Manager**. System User tokens have no expiry and can be scoped to specific assets (ad accounts + Pages). This is the same token type ScaleForge and every production Meta integration uses.\n\n1. **Create a Facebook App** (if you don't have one) at [developers.facebook.com/apps](https://developers.facebook.com/apps/). Any app works — Business type is fine.\n2. **Create a Business Manager** at [business.facebook.com](https://business.facebook.com/). You need this as the container for your System User.\n3. **Add your ad accounts and Pages to the Business** under Business Settings → Accounts → Ad Accounts / Pages. (If they're owned by another Business, request access.)\n4. **Create a System User:** Business Settings → Users → **System Users** → **Add** → name it (e.g. `mcp-meta-ads`) → role **Admin**.\n    *[screenshot: Business Settings → Users → System Users tab with \"Add\" button]*\n5. **Assign ad accounts to the System User:** click the System User → **Add Assets** → pick Ad Accounts → select yours → turn on **Manage** permission. Repeat for Pages.\n    *[screenshot: Add Assets dialog with \"Manage\" toggle highlighted]*\n6. **Generate the token:** click **Generate New Token** → select your Facebook App → pick scopes:\n   - `ads_management`\n   - `ads_read`\n   - `business_management`\n   - `pages_read_engagement`\n   - `pages_manage_ads`\n   - `read_insights` (optional — needed for some insight breakdowns)\n   *[screenshot: Generate Token dialog with scopes checklist]*\n7. **Click Generate** and copy the token. It never expires. Store it in a secret manager / env var / password manager.\n\nNow use it:\n\n```bash\nMETA_ACCESS_TOKEN=EAAB...your-token... npx -y @getscaleforge/mcp-meta-ads\n```\n\nIf you revoke or regenerate later, the old token stops working immediately.\n\n---\n\n## Baked-in pain point fixes\n\n| Meta pain point | How this MCP handles it |\n| --- | --- |\n| Rate limit code #17 in bulk ops | `pause_campaigns_batch`, `activate_campaigns_batch`, `update_bids_batch` use Meta Batch API (up to 50 ops/request) with auto-chunking and a 2s gap between chunks. |\n| 250-ads-per-Page silent cap | `get_ads_volume` + automatic pre-flight check inside `activate_campaigns_batch` — warnings come back in the response before Meta starts any review. |\n| Token-expired errors | `enhanceMetaError` detects codes 190 / 102 / 104 / 463 / 467 and returns a message pointing to the [stable-token setup](#stable-tokens). |\n| Instagram placements without IG login | `get_pbia` auto-creates a Page-Backed Instagram Account and returns the `instagram_user_id` for your `object_story_spec`. |\n| v22 deprecations | Uses `instagram_user_id`, no `degrees_of_freedom_spec`, no `asset_feed_id`. |\n| Image hash scoping | Documented on `upload_image` + `create_ad_creative` — hashes are per-account, you must re-upload to each target account. (Cached per-account caching logic lives in ScaleForge's backend and will be added here in a later release.) |\n\n---\n\n## Tools reference\n\n**32 tools** across 10 categories.\n\n### Accounts (3)\n| Name | Purpose |\n| --- | --- |\n| `list_ad_accounts` | List Ad Accounts accessible to the token |\n| `get_ad_account` | Detailed info for one account (status, spend cap, balance) |\n| `get_ads_volume` | Per-Page running-ads count + limit + remaining slots (pre-flight check) |\n\n### Campaigns (5)\n| Name | Purpose |\n| --- | --- |\n| `list_campaigns` | Paginated campaign list |\n| `get_campaign` | Single campaign by ID |\n| `create_campaign` | **WRITE** — create new campaign (defaults to PAUSED) |\n| `update_campaign` | **WRITE** — update any mutable field |\n| `delete_campaign` | **WRITE** — hard delete |\n\n### Ad Sets (5)\n| Name | Purpose |\n| --- | --- |\n| `list_adsets` | List by ad_account_id OR campaign_id |\n| `get_adset` | Single ad set by ID |\n| `create_adset` | **WRITE** — create ad set under a campaign |\n| `update_adset` | **WRITE** — update targeting, bid, budget, status |\n| `delete_adset` | **WRITE** — hard delete |\n\n### Ads (4)\n| Name | Purpose |\n| --- | --- |\n| `list_ads` | List by ad_account_id, adset_id, or campaign_id |\n| `get_ad` | Single ad by ID (incl. creative + issues + preview link) |\n| `update_ad` | **WRITE** — update name, status, swap creative |\n| `delete_ad` | **WRITE** — hard delete |\n\n### Creatives (4)\n| Name | Purpose |\n| --- | --- |\n| `list_creatives` | List all creatives in an ad account |\n| `get_creative` | Single creative by ID |\n| `create_ad_creative` | **WRITE** — single-text creative via `object_story_spec` |\n| `create_ad_creative_with_asset_feed` | **WRITE** — dynamic/multi-text creative via `asset_feed_spec` |\n\n### Media (2)\n| Name | Purpose |\n| --- | --- |\n| `upload_video` | **WRITE** — upload video via remote URL (returns video_id) |\n| `upload_image` | **WRITE** — upload image via remote URL (returns image_hash, scoped to account) |\n\n### Insights (3)\n| Name | Purpose |\n| --- | --- |\n| `get_campaign_insights` | Metrics at campaign level with breakdowns |\n| `get_adset_insights` | Metrics at ad set level |\n| `get_ad_insights` | Metrics at ad level (compare creatives) |\n\n### Bulk (3)\n| Name | Purpose |\n| --- | --- |\n| `pause_campaigns_batch` | **WRITE (BULK)** — pause many campaigns via Batch API |\n| `activate_campaigns_batch` | **WRITE (BULK)** — activate many + pre-flight ads_volume check |\n| `update_bids_batch` | **WRITE (BULK)** — update `bid_amount` on many ad sets |\n\n### Pages (2)\n| Name | Purpose |\n| --- | --- |\n| `list_pages` | Facebook Pages the token can manage |\n| `get_pbia` | Get or auto-create a Page-Backed Instagram Account |\n\n### Ads Library (1)\n| Name | Purpose |\n| --- | --- |\n| `search_ads_library` | Public Meta Ad Library search for competitive research |\n\n---\n\n## Example prompts\n\nOnce the server is connected, try these in your agent.\n\n### Read-only\n\n- *\"List my Meta ad accounts and show me which ones are active, currency, and spend cap.\"*\n- *\"For campaign `1234567890`, pull last_14d insights with breakdown by placement — which placement has the lowest CPL?\"*\n- *\"Show me the ads_volume for account `act_555` — any Page over 85% of its limit?\"*\n- *\"Search the Meta Ad Library for ads from Competitor X running in the US in the last month.\"*\n- *\"List all ad sets in campaign `ABCD` and show which ones have is_dynamic_creative=true.\"*\n\n### Write (confirm first)\n\n> Write operations change live Meta Ads state — spend starts or stops immediately. A well-behaved agent (Claude, GPT-4) will show you the target list and ask \"proceed?\" before calling these.\n\n- *\"Pause campaigns `111`, `222`, `333` — show me their names and current spend first, then pause.\"*\n- *\"Activate campaigns `444` and `555`. Run the ads_volume pre-flight first; if any Page is over 85%, abort and tell me which.\"*\n- *\"Bump the bid on ad sets `6001` and `6002` to $4.50. Convert to cents for me.\"*\n- *\"Create a new campaign in `act_777` called 'Spring Promo Test', OUTCOME_LEADS objective, daily_budget 5000 cents, PAUSED.\"*\n\n---\n\n## FAQ\n\n### How do I get a Meta access token?\n\nSee [Get a Meta Access Token](#get-a-meta-access-token) above. Two options: quick 2-hour token (Graph API Explorer) or stable System User token (Business Manager, never expires).\n\n### Why does my token keep expiring?\n\nYou're using a **User access token** from the Graph API Explorer. Those expire in ~2 hours by design. For anything beyond experimentation, generate a **System User token** via Business Manager — those never expire. [Full steps here.](#stable-tokens)\n\n### What's ads_volume?\n\nMeta limits how many ads can be \"running or in review\" per Facebook Page — default 250 — and this limit is shared across every ad account using that Page. The `get_ads_volume` tool shows you how much headroom each Page has. `activate_campaigns_batch` calls it automatically as a pre-flight check.\n\n### Is this free?\n\nYes. MIT license, npm package is free. You pay Meta for ads as usual. There is no ScaleForge account or subscription needed to use this MCP.\n\n### How does this compare to Pipeboard / other MCPs?\n\n- **Pipeboard / hosted MCPs** — run on their server, you send your token to them, they rate-limit you. Fine for very light usage, but the token lives on someone else's machine.\n- **This MCP** — runs locally, your token never leaves your box, direct path to Meta. 32 tools (more coverage than any other Meta MCP we've seen).\n- **ScaleForge managed platform** (see below) — a separate product for teams that want managed Meta access, RedTrack integration, scheduled auto-rules, UI dashboards. This MCP is a standalone tool that does not depend on it.\n\n### Can I use this without ScaleForge?\n\nYes. This MCP is a standalone npm package — it talks straight to `graph.facebook.com`. No account anywhere.\n\n### Can I contribute more tools?\n\nPlease do. PRs welcome at [github.com/Mike25app/scaleforge-mcp-meta-ads](https://github.com/Mike25app/scaleforge-mcp-meta-ads). Each tool is a small file in `src/tools/` — copy one of the existing files as a template.\n\n---\n\n## Powered by ScaleForge\n\nBuilt and maintained by the [ScaleForge](https://getscaleforge.com) team. If you need managed Meta access (System User provisioning, RedTrack integration, scheduled auto-rules, dashboards), check out the full platform — this MCP stays free and standalone regardless.\n\n---\n\n## Security\n\n- **Generate least-privilege tokens.** Scope your System User to only the ad accounts + Pages it needs. Revoking a token takes effect immediately.\n- **Never commit tokens** to source control. The MCP reads from `META_ACCESS_TOKEN` env var — keep it in your agent host's secret store (Claude Desktop's env block, shell profile with 600 perms, 1Password, etc.).\n- **Rotate periodically.** Even non-expiring System User tokens should be rotated on a team policy. Regenerating in Business Manager invalidates the old one.\n- **No telemetry.** This MCP does not phone home. The only outbound requests it makes are to `https://graph.facebook.com/v24.0/*`.\n- **Rate limits apply per token / per ad account** (Meta-side). Bulk tools automatically use Meta Batch API to stay under.\n\n---\n\n## Links\n\n- **npm:** [@getscaleforge/mcp-meta-ads](https://www.npmjs.com/package/@getscaleforge/mcp-meta-ads)\n- **GitHub:** [Mike25app/scaleforge-mcp-meta-ads](https://github.com/Mike25app/scaleforge-mcp-meta-ads)\n- **Issues:** [github.com/Mike25app/scaleforge-mcp-meta-ads/issues](https://github.com/Mike25app/scaleforge-mcp-meta-ads/issues)\n- **ScaleForge (managed platform):** [getscaleforge.com](https://getscaleforge.com)\n- **Meta Marketing API docs:** [developers.facebook.com/docs/marketing-apis](https://developers.facebook.com/docs/marketing-apis)\n\n---\n\n## License\n\nMIT — see [LICENSE](LICENSE).\n",
  "bytes": 17572,
  "sha": "8726b0a242011936e2424c386f68d823d8d477b4e324f33dac53741450871844",
  "repo_slug": "mike25app/scaleforge-mcp-meta-ads",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_mike25app_scaleforge_mcp_meta__3275fd3a/readme"
}