Meta Ads MCP

Meta Ads MCP

MCP server for the Meta Marketing API with 118 typed tools across ads, insights, pixels/CAPI, pages, Instagram, WhatsApp, catalogs, audiences, leads, and billing, featuring secure token storage and a confirmation gate on destructive calls.

Category
Visit Server

README

<div align="center">

Meta Ads MCP

An MCP server for the Meta Marketing API — built for people running real ad spend.

118 typed tools across Ads, Insights, Pixels/CAPI, Pages, Instagram, WhatsApp Business, Catalogs, Audiences, Leads and Billing — with the token kept out of your config files and a confirmation gate on every destructive call.

License: MIT Python 3.11+ MCP Graph API v21.0 Transports: stdio + HTTP

</div>


Why this one

There are several Meta Ads MCP servers out there. This one is built around a specific assumption: the person using it is spending real money, possibly on behalf of clients, and a mis-fired tool call costs more than an apology.

That shapes three decisions the code makes differently:

How most setups do it How this one does it
Token storage Pasted into a JSON config or .env that sits in plaintext on disk OS credential store first (Windows Credential Manager / macOS Keychain via keyring), .env only as fallback
Destructive calls The model calls delete_campaign and it deletes confirm=True required — the refusal names the operation and the target, so the intent shows up in the transcript before anything happens
Errors Meta's opaque code=3 / subcode=1487348 reaches you raw Decoded into a message that says what to actually do

Plus a global MCP_READ_ONLY kill switch — useful when the server is reachable from a phone.


Quick start

Requirements: Python 3.11+, a Meta System User token, and an MCP client (Claude Code, Claude Desktop, Cursor…).

<details open> <summary><b>Windows</b></summary>

git clone https://github.com/AbnerZx/meta-ads-mcp.git
cd meta-ads-mcp
powershell -ExecutionPolicy Bypass -File .\install.ps1

The installer checks your Python, creates .venv, installs dependencies, prompts for your token (masked input, stored in Credential Manager, never written to disk), and prints the exact registration command to run next.

</details>

<details> <summary><b>macOS / Linux</b></summary>

git clone https://github.com/AbnerZx/meta-ads-mcp.git
cd meta-ads-mcp
python3 -m venv .venv && source .venv/bin/activate
pip install -e .
python -m keyring set meta-ads-mcp access_token   # paste token when prompted

</details>

Then register it with your client:

claude mcp add meta-ads --scope user -- /path/to/.venv/bin/python /path/to/src/server.py

Restart the client. Tools appear as mcp__meta-ads__*.

Verify it works — ask your assistant:

"List my Meta ad accounts."


What's in it

118 tools across 12 modules:

Module Tools What it covers
ads 29 Campaigns, ad sets, ads — create, update, duplicate, pause, activate, delete, schedules, previews
catalog 12 Product catalogs, feeds, product sets, diagnostics
instagram 12 Media, insights, publishing (image/video), comment moderation
pages 11 Posts, insights, publishing, comment moderation
creatives 10 Link & carousel creatives, image/video upload, previews
whatsapp 9 Business accounts, phone numbers, message templates, sending
audiences 8 Custom & saved audiences, applying them to ad sets
pixels 7 Pixel management, stats, sharing, Conversions API events
insights 6 Reports, period comparison, async report lifecycle
billing 6 Spend, limits, funding source, invoices, cross-account summary
leads 5 Lead forms and lead retrieval
graph 3 graph_call escape hatch, pagination, token debugging

graph_call matters more than it looks. The Meta Marketing API is enormous and changes often. Rather than pretend 118 tools cover it, there's a typed escape hatch for any endpoint that isn't wrapped yet — so you're never blocked waiting on this repo.


Conventions

Worth knowing before your first call:

  • Ad account IDs are auto-prefixed with act_ — pass 123456 or act_123456, both work.
  • Budgets are integers in account-currency cents. R$ 10,00 → 1000. This is Meta's convention, not ours.
  • Destructive ops need confirm=True. Without it you get a blocked-operation error naming the target.
  • The token never travels through tool arguments. It's loaded once at startup from the credential store.

Security model

The threats this is designed against, and what handles each:

Asset Risk if exposed Control
Meta access token Full control of every ad account the token can reach OS credential store (encrypted at rest); never logged, never serialized, never returned by a tool
Server logs Token leaking through a stack trace Regex scrubbing in client.py; response bodies are not logged
Docker image Secrets baked into build layers .dockerignore excludes .env, .git, secrets
Public endpoint Brute force, DNS rebinding Bearer auth with constant-time compare, global rate limit, MCP_PUBLIC_HOSTS allowlist
Destructive calls A campaign paused or deleted by mistake confirm=True per call + MCP_READ_ONLY global switch
CAPI payloads PII sent in the clear SHA-256 hashing applied client-side before transmission

Found a vulnerability? See SECURITY.md — please don't open a public issue.

Getting a token

Use a System User token, not a personal one. It doesn't expire, it's revocable independently of your own account, and Meta gives you a per-user audit trail.

Business Manager → Business settings → Users → System users → Add → assign only the ad accounts and Pages you actually need → Generate new token.

Typical scopes: ads_management, ads_read, business_management, read_insights. Add pages_*, instagram_*, leads_retrieval, whatsapp_business_* or catalog_management only if you use those modules. Meta shows the token exactly once.


Configuration

All optional except the token. See .env.example.

Variable Default Purpose
META_ADS_TOKEN — Token, if you're not using the credential store
META_DEFAULT_BUSINESS_ID — Fallback Business Manager ID
META_API_VERSION v21.0 Graph API version
META_REQUEST_TIMEOUT 60 Read timeout, seconds — Meta's validation paths can sit 20–40s
META_RATE_LIMIT_RPS 5 Local rate limiter
MCP_READ_ONLY false true blocks every write, regardless of confirm
MCP_PUBLIC_HOSTS — Host allowlist — required for public HTTP deploys
MCP_RATE_LIMIT_RPM 60 Per-minute cap on the HTTP transport

Remote deployment

The server speaks two transports: stdio for local clients, streamable-http for remote ones. The HTTP mode lets you reach your ad accounts from Claude.ai on mobile via a Custom Connector.

→ Full deployment guide (DEPLOY.md) — Fly.io walkthrough, bearer secret generation, secret rotation, and an incident-response checklist.

Short version:

fly launch --no-deploy --copy-config    # edit fly.toml first: app name + MCP_PUBLIC_HOSTS
fly secrets set MCP_BEARER_SECRET="..." META_ADS_TOKEN="..."
fly deploy

fly.toml ships with MCP_READ_ONLY = 'true'. Leave it that way until you've confirmed the deployment works.


Project layout

src/
├── server.py           # stdio entrypoint
├── http_server.py      # streamable-http transport, bearer auth, rate limiting
├── mcp_instance.py     # shared FastMCP instance + transport security
├── client.py           # Graph API client — retries, backoff, log scrubbing
├── auth.py             # token loading (credential store → env fallback)
├── safety.py           # confirmation gate, ID normalization, input validation
└── tools/              # 12 modules, 118 tools

Contributing

Issues and pull requests are welcome — see CONTRIBUTING.md. Especially useful: Graph API error subcodes you've hit that aren't decoded yet, and coverage gaps you're currently working around with graph_call.

License

MIT © Abner Ferreira

<sub>Not affiliated with or endorsed by Meta Platforms, Inc. "Meta", "Facebook", "Instagram" and "WhatsApp" are trademarks of Meta Platforms, Inc.</sub>

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured