{"_id":"@0xfabrica/mcp-meta-ads","_rev":"2-b610a2fb65e2cba7de7be8f16e9a816a","name":"@0xfabrica/mcp-meta-ads","dist-tags":{"latest":"1.0.1"},"versions":{"1.0.0":{"name":"@0xfabrica/mcp-meta-ads","version":"1.0.0","keywords":["mcp","meta","facebook","ads","marketing-api","model-context-protocol","claude","ai","advertising","meta-ads","facebook-ads","campaign-management"],"author":{"name":"0xfabrica"},"license":"MIT","_id":"@0xfabrica/mcp-meta-ads@1.0.0","maintainers":[{"name":"0xfabrica","email":"intelligroow@gmail.com"}],"homepage":"https://github.com/0xfabrica/mcp-meta-ads#readme","bugs":{"url":"https://github.com/0xfabrica/mcp-meta-ads/issues"},"bin":{"mcp-meta-ads":"dist/index.js"},"dist":{"shasum":"51fcbc908535a842f8680a10b319094bd588461f","tarball":"https://registry.npmjs.org/@0xfabrica/mcp-meta-ads/-/mcp-meta-ads-1.0.0.tgz","fileCount":10,"integrity":"sha512-eJmYx7GVSm2J9vC5kouHOWmPY6zA93dH07CyjgIDm9muPGUoG/4gp2bsaD2vEbF1jWYgQ/VuM4ojEJ3wXGeycg==","signatures":[{"sig":"MEUCIG5Xt8VeCJvOqVP8OmfyNqEghMC0n6tzeysvcr8i32PVAiEAi3LmLhUKtKX2MB4QrSBage1T8InGlAHvLJRTFi/yd64=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":52444},"main":"dist/index.js","type":"module","engines":{"node":">=20.0.0"},"gitHead":"a4f662b3b9fc6f553bf19a08765c0d14c78c9c4d","scripts":{"dev":"tsx watch src/index.ts","test":"node --import tsx --test tests/meta-api.test.ts","build":"tsc -p tsconfig.json","clean":"node -e \"require('fs').rmSync('dist', { recursive: true, force: true })\"","start":"node dist/index.js","doctor":"node dist/index.js doctor","typecheck":"tsc -p tsconfig.json --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"0xfabrica","email":"intelligroow@gmail.com"},"repository":{"url":"git+https://github.com/0xfabrica/mcp-meta-ads.git","type":"git"},"_npmVersion":"11.6.2","description":"Open-source MCP server for Meta Ads management — read insights, create campaigns, update budgets, and pause ads via any MCP-compatible AI client.","directories":{},"_nodeVersion":"24.12.0","dependencies":{"zod":"^4.3.6","dotenv":"^17.4.0","@modelcontextprotocol/sdk":"^1.29.0","facebook-nodejs-business-sdk":"^24.0.1"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.21.0","typescript":"^6.0.2","@types/node":"^25.5.2"},"_npmOperationalInternal":{"tmp":"tmp/mcp-meta-ads_1.0.0_1775730608447_0.36755504452283017","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@0xfabrica/mcp-meta-ads","version":"1.0.1","description":"Open-source MCP server for Meta Ads management — read insights, create campaigns, update budgets, and pause ads via any MCP-compatible AI client.","license":"MIT","type":"module","main":"dist/index.js","bin":{"mcp-meta-ads":"dist/index.js"},"scripts":{"build":"tsc -p tsconfig.json","clean":"node -e \"require('fs').rmSync('dist', { recursive: true, force: true })\"","dev":"tsx watch src/index.ts","doctor":"node dist/index.js doctor","test":"node --import tsx --test tests/meta-api.test.ts","start":"node dist/index.js","typecheck":"tsc -p tsconfig.json --noEmit","prepublishOnly":"npm run build"},"keywords":["mcp","meta","facebook","ads","marketing-api","model-context-protocol","claude","ai","advertising","meta-ads","facebook-ads","campaign-management"],"repository":{"type":"git","url":"git+https://github.com/0xfabrica/mcp-meta-ads.git"},"homepage":"https://github.com/0xfabrica/mcp-meta-ads#readme","bugs":{"url":"https://github.com/0xfabrica/mcp-meta-ads/issues"},"author":{"name":"0xfabrica"},"engines":{"node":">=20.0.0"},"dependencies":{"@modelcontextprotocol/sdk":"^1.29.0","dotenv":"^17.4.0","facebook-nodejs-business-sdk":"^24.0.1","zod":"^4.3.6"},"devDependencies":{"@types/node":"^25.5.2","tsx":"^4.21.0","typescript":"^6.0.2"},"gitHead":"958fd4f081fd8a3de724e748f87aba70ef7518b5","_id":"@0xfabrica/mcp-meta-ads@1.0.1","_nodeVersion":"24.12.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-cfkM+cFJTNZaHIVfGtSKXh0Quv6j/PvcIQDa+EgXCx5Fsf+zWRSa2RzZBbE+ecMKpQN2RydwNzol0sx/V9Ioag==","shasum":"6c4fe87e2e23e05b1e1eb16789920898c5ec9874","tarball":"https://registry.npmjs.org/@0xfabrica/mcp-meta-ads/-/mcp-meta-ads-1.0.1.tgz","fileCount":10,"unpackedSize":56980,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCID4QzWDJxPAh9DY/LvAMCIG8ZIIJ5h8cP/n4fkUNMlDqAiEA15FiGZorK+Gh8i8ti2HpXtETu/TSig8cs/7Vj1r3pFY="}]},"_npmUser":{"name":"0xfabrica","email":"intelligroow@gmail.com"},"directories":{},"maintainers":[{"name":"0xfabrica","email":"intelligroow@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/mcp-meta-ads_1.0.1_1776894458885_0.3694092269070979"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-09T10:30:08.355Z","modified":"2026-04-22T21:47:39.133Z","1.0.0":"2026-04-09T10:30:08.607Z","1.0.1":"2026-04-22T21:47:39.030Z"},"bugs":{"url":"https://github.com/0xfabrica/mcp-meta-ads/issues"},"author":{"name":"0xfabrica"},"license":"MIT","homepage":"https://github.com/0xfabrica/mcp-meta-ads#readme","keywords":["mcp","meta","facebook","ads","marketing-api","model-context-protocol","claude","ai","advertising","meta-ads","facebook-ads","campaign-management"],"repository":{"type":"git","url":"git+https://github.com/0xfabrica/mcp-meta-ads.git"},"description":"Open-source MCP server for Meta Ads management — read insights, create campaigns, update budgets, and pause ads via any MCP-compatible AI client.","maintainers":[{"name":"0xfabrica","email":"intelligroow@gmail.com"}],"readme":"# mcp-meta-ads\n\n[![npm version](https://img.shields.io/npm/v/@0xfabrica/mcp-meta-ads.svg)](https://www.npmjs.com/package/@0xfabrica/mcp-meta-ads)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n[![Node.js](https://img.shields.io/badge/Node.js-%3E%3D20-green.svg)](https://nodejs.org)\n[![TypeScript](https://img.shields.io/badge/TypeScript-strict-blue.svg)](https://www.typescriptlang.org)\n[![MCP](https://img.shields.io/badge/MCP-stdio-purple.svg)](https://modelcontextprotocol.io)\n\n> Open-source MCP server for safe Meta Ads management from AI coding agents and any MCP-compatible client.\n\n[Leer en Español](README.es.md)\n\n---\n\n## Features\n\n- **7 MCP tools** for reading metrics, managing budgets, pausing entities, and creating campaigns.\n- **Built-in `doctor` command** for offline account health checks.\n- **Safety first** — every created object is forced to `PAUSED`. Credentials never leak to LLM output.\n- **Works with any MCP client** — Claude Code, Cursor, Windsurf, Cline, or your own agent.\n\n## Installation\n\n### Option A: npm (recommended)\n\n```bash\nnpm install -g @0xfabrica/mcp-meta-ads\n```\n\nOr run directly with npx:\n\n```bash\nnpx @0xfabrica/mcp-meta-ads\n```\n\n### Option B: From source\n\n```bash\ngit clone https://github.com/0xfabrica/mcp-meta-ads.git\ncd mcp-meta-ads\ncp .env.example .env   # fill in your Meta credentials\nnpm install\nnpm run build\n```\n\n## Setup with MCP clients\n\n### Claude Code\n\n```bash\nclaude mcp add --transport stdio mcp-meta-ads -- npx @0xfabrica/mcp-meta-ads\n```\n\n### Claude Desktop\n\nAdd to your `claude_desktop_config.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"mcp-meta-ads\": {\n      \"command\": \"npx\",\n      \"args\": [\"@0xfabrica/mcp-meta-ads\"],\n      \"env\": {\n        \"META_APP_ID\": \"your_app_id\",\n        \"META_APP_SECRET\": \"your_app_secret\",\n        \"META_ACCESS_TOKEN\": \"your_access_token\",\n        \"META_AD_ACCOUNT_ID\": \"your_ad_account_id\"\n      }\n    }\n  }\n}\n```\n\n### Cursor / Windsurf / Cline\n\n```json\n{\n  \"name\": \"mcp-meta-ads\",\n  \"transport\": \"stdio\",\n  \"command\": \"npx\",\n  \"args\": [\"@0xfabrica/mcp-meta-ads\"]\n}\n```\n\n## Environment variables\n\nCreate a `.env` file in the project root (see [`.env.example`](.env.example)):\n\n| Variable | Description |\n|----------|-------------|\n| `META_APP_ID` | Your Meta app ID |\n| `META_APP_SECRET` | Your Meta app secret |\n| `META_ACCESS_TOKEN` | Long-lived access token with `ads_read` and `ads_management` permissions |\n| `META_AD_ACCOUNT_ID` | Numeric ad account ID (with or without `act_` prefix) |\n| `META_API_VERSION` | Graph API version (default: `v25.0`) |\n\n## API compatibility notes\n\nMeta's current Marketing API requires a few fields that older integrations could omit. This server now sends them by default when creating campaigns and ad sets:\n\n- `is_adset_budget_sharing_enabled=false` on campaign creation when not using campaign budget sharing\n- `bid_strategy=LOWEST_COST_WITHOUT_CAP` on ad set creation\n- `targeting.targeting_automation.advantage_audience=0` on ad set targeting\n\nFor `OUTCOME_SALES`, the server also switches the ad set to sales-compatible delivery settings:\n\n- `optimization_goal=OFFSITE_CONVERSIONS`\n- `promoted_object.custom_event_type=PURCHASE` when `pixel_id` is provided\n\nFor link creatives, the server uses `object_story_spec.link_data.picture` instead of deprecated/unsupported fields such as `image_url` or `link_caption`.\n\nIf `instagram_actor_id` is provided, it is sent as `instagram_user_id` in the creative payload. Your ad account must have access to that Instagram account or Meta will reject the creative with a permissions error.\n\n## MCP tools\n\n| Tool | Description | Writes? |\n|------|-------------|---------|\n| `get_account_insights` | Account-level spend, CPA, CPC, CTR, ROAS for a date range | No |\n| `list_active_campaigns` | Active campaigns with ad set metrics (last 7 days) | No |\n| `get_campaign_performance` | Deep drill into a single campaign with ad set + ad metrics | No |\n| `get_entity_insights` | Inspect any campaign, ad set, or ad by ID | No |\n| `pause_underperforming_entity` | Pause a campaign, ad set, or ad | Yes |\n| `update_budget` | Update daily budget on a campaign or ad set | Yes |\n| `create_campaign` | Create a full campaign > ad set > ad structure (always `PAUSED`) | Yes |\n\n### `get_account_insights`\n\n```\nsince: \"2025-01-01\"   # YYYY-MM-DD\nuntil: \"2025-01-31\"   # YYYY-MM-DD\n```\n\nReturns spend, CPA, CPC, CTR, ROAS, impressions, clicks, and raw action arrays.\n\n### `list_active_campaigns`\n\n```\nlimit: 25   # optional, max 100\n```\n\nReturns active campaigns with their ad sets and last-7-days metrics.\n\n### `get_campaign_performance`\n\n```\ncampaign_id: \"123456789\"\ndays: 7              # optional, max 90\ninclude_ads: true    # optional\nad_limit: 25         # optional, max 100\n```\n\nReturns campaign, ad set, and optional ad-level performance breakdown.\n\n### `get_entity_insights`\n\n```\nentity_id: \"123456789\"\nentity_type: \"adset\"   # optional: campaign, adset, ad\ndays: 7                # optional, max 90\n```\n\nReturns metadata plus metrics for any entity. Auto-resolves entity type if not provided.\n\n### `pause_underperforming_entity`\n\n```\nentity_id: \"123456789\"\nentity_type: \"ad\"   # optional\n```\n\nSets the entity status to `PAUSED`.\n\n### `update_budget`\n\n```\nentity_id: \"123456789\"\nnew_daily_budget: 50.00     # in account currency (e.g., USD, EUR)\nentity_type: \"adset\"        # optional: campaign or adset\n```\n\nBudget is expressed in major currency units. The server converts to minor units for Meta.\n\n### `create_campaign`\n\n```\ncampaign_name: \"My Campaign\"\nadset_name: \"My Ad Set\"\nad_name: \"My Ad\"\ndaily_budget: 20.00\ndestination_url: \"https://example.com\"\npage_id: \"123456789\"\nimage_url: \"https://example.com/image.jpg\"\nprimary_text: \"Your ad copy here\"\nheadline: \"Your headline\"\ndescription: \"Optional description\"           # optional\ninstagram_actor_id: \"123456789\"               # optional\nurl_tags: \"utm_source=meta&utm_medium=paid\"   # optional\ncall_to_action_type: \"SIGN_UP\"                # optional\npixel_id: \"123456789\"                         # optional\nobjective: \"OUTCOME_TRAFFIC\"                  # OUTCOME_TRAFFIC | OUTCOME_LEADS | OUTCOME_SALES | OUTCOME_ENGAGEMENT\ncountries: [\"US\", \"CA\"]\nage_min: 25\nage_max: 55\n```\n\nEvery object is created in `PAUSED` state. Nothing goes live without manual activation.\n\nAdditional behavior:\n\n- `instagram_actor_id` is optional. Omit it if the ad account does not have Instagram permissions and create a Facebook-only creative first.\n- `url_tags` are sent at the creative level.\n- `age_max` can be constrained by Meta when Advantage+ audience rules apply.\n\n## Doctor command\n\nRun a read-only health check without starting the MCP server:\n\n```bash\nnpm run doctor\n```\n\nReturns account info, last 7 days metrics, and a sample of active campaigns.\n\n## Development\n\n```bash\nnpm run dev        # watch mode with tsx\nnpm run typecheck  # type-check without emitting\nnpm test           # run offline tests\n```\n\n## Project structure\n\n```\nsrc/\n  index.ts          # Entry point, MCP server + doctor command\n  config.ts         # .env validation with Zod\n  meta-api.ts       # Meta Graph API client\n  tools.ts          # MCP tool registration + input validation\n  diagnostics.ts    # Read-only health report\n  logger.ts         # Secret redaction for logs\n```\n\n## Security\n\n- Credentials loaded exclusively from `.env` -- never hardcoded.\n- Access tokens, secrets, and proofs are redacted in all log output.\n- Error messages to the LLM are clear but never expose stack traces or internal state.\n- `appSecretProof` is computed via HMAC-SHA256 for every API request.\n- All campaign creation is forced to `PAUSED` -- nothing goes live by default.\n\n## Contributing\n\n1. Fork the repo\n2. Create a feature branch (`git checkout -b feature/my-feature`)\n3. Make your changes\n4. Run `npm run typecheck && npm test`\n5. Open a pull request\n\n## License\n\n[MIT](LICENSE) -- 0xfabrica\n","readmeFilename":"README.md"}