meta-mcp
MCP Server for connecting to the Meta Marketing API
Documentation
Meta Ads MCP Server
A Cloudflare Workers MCP server for Meta Ads account setup, campaign management, ad sets, creatives, audiences, reporting, and batch workflows.
This repo is built on `xmcp` and exposes a Streamable HTTP MCP endpoint plus browser-facing Meta OAuth routes.
Open Source / Self-Hosted
This repository is intended to be deployed in your own Cloudflare account with your own Meta app credentials.
It does not ship with:
- a hosted control plane
- a shared Meta app
- a built-in end-user dashboard
- a JWT issuer for your users and workspaces
You bring:
- your Cloudflare Worker deployment
- your Meta developer app
- your JWT issuer or auth provider
- your own UI or backend that initiates the OAuth flow
What It Does
- Runs as a Cloudflare Worker
- Uses direct Meta Graph API `fetch` calls instead of the Meta SDK
- Stores Meta user connections per workspace in D1
- Stores short-lived OAuth state in KV
- Encrypts stored Meta access tokens
- Protects MCP requests with your app-issued JWTs
Endpoints
- `GET /health`
- `GET /app`
- `POST /mcp`
- `GET /oauth/meta/start`
- `GET /oauth/meta/callback`
Auth Model
This server is multi-tenant. Every MCP request must include a bearer JWT issued by your app.
If you are open-sourcing this project, the important implication is that consumers must wire it into their own auth system. The server does not know how to identify a user or workspace without that JWT.
Required JWT claims:
- `sub` or `userId`
- `workspaceId`
- optional `roles`
Example payload:
{
"sub": "user_123",
"workspaceId": "workspace_abc",
"roles": ["admin"]
}Why `/oauth/meta/start` is not a generic public link:
- the server must know which workspace the Meta account should be attached to
- that workspace context comes from the JWT
- without it, the server cannot safely bind the resulting Meta token
Tool Surface
Implemented tool families:
- Account and setup
- Campaign management
- Ad set management
- Creative and ads
- Audience and targeting
- Reporting and insights
- Batch helpers
The server currently registers 39 tools.
Project Layout
- `src/tools` tool definitions grouped by domain
- `src/lib` auth, storage, OAuth, runtime, and Meta client helpers
- `src/services` domain-specific Meta service logic
- `src/middleware.ts` OAuth routing and MCP JWT auth
- `cloudflare-entry.mjs` Worker wrapper entry for Cloudflare-specific route interception
- `schema.sql` D1 schema
- `test` unit and contract-style tests
Local Development
Install dependencies:
pnpm installRun local dev:
pnpm devUseful scripts:
pnpm build
pnpm test
pnpm deployCloudflare Bindings
Required bindings:
- D1 database bound as `META_DB`
- KV namespace bound as `META_OAUTH_STATE`
Required secrets:
- `JWT_SECRET` or `JWT_JWKS_URL`
- `META_APP_ID`
- `META_APP_SECRET`
- `META_TOKEN_ENCRYPTION_KEY`
- `APP_UI_PASSWORD` for the built-in admin page at `/app`
Optional configuration:
- `JWT_ISSUER`
- `JWT_AUDIENCE`
- `APP_SESSION_SECRET`
- `APP_UI_WORKSPACE_ID`
- `APP_UI_USER_ID`
- `META_REDIRECT_URI`
- `META_GRAPH_VERSION`
- `META_OAUTH_SCOPES`
- `META_OAUTH_ALLOWED_RETURN_ORIGINS`
Defaults:
- `META_GRAPH_VERSION=v25.0`
- `META_OAUTH_SCOPES=ads_management,business_management`
- `APP_UI_WORKSPACE_ID=workspace_admin`
- `APP_UI_USER_ID=app_admin`
Built-In Admin UI
The Worker now includes a small browser UI at `/app`.
What it does:
- prompts for an admin password
- starts the existing Meta OAuth flow without requiring you to manually mint a bearer JWT
- shows whether a Meta account is connected for the admin workspace
- loads accessible ad accounts using the same service logic as `get_ad_accounts`
Required setup:
1. Set `APP_UI_PASSWORD` on the Worker.
2. Make sure `META_REDIRECT_URI` matches your public host, for example:
https://meta-mcp.gestalt.xyz/oauth/meta/callback3. Open:
https://meta-mcp.gestalt.xyz/appMeta App Setup
In your Meta app:
1. Add the Marketing API product.
2. Add a Website platform.
3. Set the Website platform URL to your Worker origin.
4. Set `App Domains` to your Worker domain.
5. Set the callback URL to:
https:///oauth/meta/callbackIf your app uses `Facebook Login` or `Facebook Login for Business`, also add that exact callback URL to the product-specific redirect URI settings.
For a Worker deployed on `workers.dev`, these fields usually need to match the Worker host exactly.
Database
Apply the D1 schema:
pnpm wrangler d1 execute META_DB --remote --file schema.sql -yTables:
- `meta_connections`
- `meta_ad_accounts_cache`
Deployment
Deploy the Worker:
pnpm deployAfter deploy:
1. note the public Worker URL
2. set `META_REDIRECT_URI` to `https:///oauth/meta/callback`
3. update the same callback in the Meta app settings
If you plan to use a separate frontend or dashboard on another origin, allow that origin for post-OAuth browser redirects:
META_OAUTH_ALLOWED_RETURN_ORIGINS=https://your-ui.example.com,http://localhost:3000Use your real frontend origin in production.
Manual Test Flow
1. Generate a short-lived JWT
Use the same JWT secret your app uses for the Worker.
export JWT_SECRET="YOUR_JWT_SECRET"
TOKEN=$(node --input-type=module /oauth/meta/start?workspace_id=workspace_test"Copy the `Location` header into your browser and complete the Meta login flow.
Expected success page:
Meta account connected.3. Initialize MCP
curl -s https:///mcp \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{"jsonrpc":"2.0","id":"init-1","method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"manual-test","version":"1.0.0"}}}'4. List Tools
curl -s https:///mcp \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{"jsonrpc":"2.0","id":"tools-1","method":"tools/list","params":{}}'5. Call a Real Tool
After OAuth succeeds, this should return the accessible ad accounts for that workspace:
curl -s https:///mcp \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{"jsonrpc":"2.0","id":"call-1","method":"tools/call","params":{"name":"get_ad_accounts","arguments":{}}}'If you get a connect/reconnect error, the OAuth flow and the MCP call used different `workspaceId` values.
Notes
- Cloudflare `workers.dev` domains can require extra care in Meta app settings.
- The Worker entrypoint explicitly intercepts OAuth routes before delegating to the generated XMCP Worker.
- The Cloudflare Worker build path is not identical to local `xmcp dev`, so always verify the deployed routes after OAuth-related changes.
References
Frequently asked questions
What is meta-mcp?
meta-mcp is MCP Server for connecting to the Meta Marketing API
How do I install meta-mcp?
Open the GitHub repository and follow its README. Most MCP servers are added to your client's MCP config, then called by your agent.
Is meta-mcp open source?
Yes — it is hosted on GitHub at https://github.com/brijr/meta-mcp and has 197 stars.
Related MCP tools
The Open-Source Multimodal AI Agent Stack: Connecting Cutting-Edge AI Models and Agent Infra
A MCP for Claude Desktop / Claude Code / Windsurf / Cursor to build n8n workflows for you
Browser MCP is a Model Context Provider (MCP) server that allows AI applications to control your browser
A Model Context Protocol (MCP) server and CLI that provides tools for agent use when working on iOS and macOS projects.
The go-to web for your AI coding agent — local-first search, fetch, crawl & research over MCP. No API keys, no cloud, $0/query. Public beta.
MCP Aggregator, Orchestrator, Middleware, Gateway in one docker
Run your own MCP server? See who uses it and what to fix.
Measure it with TrackMCP