meta-mcp

meta-mcp

Read-only MCP server for Meta (Facebook) Graph API, enabling access to Marketing API, Pages, Instagram, and WhatsApp Business data through Claude Code and any MCP-compatible client.

Category
Visit Server

README

meta-mcp

Read-only MCP server for Meta (Facebook) Graph API. Plugs into Claude Code (and any other MCP-compatible client) over stdio (local) or Streamable HTTP (remote).

Covers four API surfaces with a single long-lived token:

  • Marketing API — ad accounts, campaigns, ad sets, ads, creatives, insights
  • Facebook Pages — pages, posts, comments, page insights
  • Instagram Graph — business accounts, media, media/account insights, hashtag search
  • WhatsApp Business — WABAs, phone numbers, message templates, analytics

Plus debug_token (inspect any token) and graph_get (raw GET escape-hatch).

HTTP method is hard-coded to GET everywhere — Claude cannot accidentally create, mutate, or delete anything.

Tools

Specialized (validated with zod):

Surface Tools
Common graph_get, debug_token
Pages pages_list, page_get, page_posts, post_get, post_comments, page_insights
Marketing ad_accounts_list, ad_account_get, campaigns_list, campaign_get, adsets_list, ads_list, adcreatives_list, adcreative_get, insights
Instagram ig_business_account_get, ig_media_list, ig_media_get, ig_media_insights, ig_user_insights, ig_hashtag_search, ig_hashtag_media
WhatsApp wa_business_owned_wabas, wa_phone_numbers, wa_phone_number_get, wa_message_templates, wa_template_get, wa_analytics

1. Get an access token

The token prefix EAA... is the same for every Graph token type — you can't tell which kind you have from the prefix. Run debug_token after first start to identify it. The four kinds:

Kind When to use How to obtain
System User Recommended for ads / business automation — long-lived, doesn't tie to a human account Business Manager → Business settings → Users → System users → Generate new token
Page Access Token Single page only Graph Explorer with a user token: GET /me/accounts?fields=access_token
User OAuth token Personal access, expires in ~60 days Standard FB Login OAuth flow
App access token Server-to-server calls that don't need user context (e.g. debug_token) `APPID

For page_insights and any Instagram tool you need a Page Access Token. This server resolves it lazily: if FB_ACCESS_TOKEN is a user/system token with admin rights, calling any Page/IG tool triggers a one-time /me/accounts fetch that caches each page's token. No manual swap needed.

2. App credentials (recommended)

If you set both FB_APP_ID and FB_APP_SECRET in .env:

  • Every request is signed with appsecret_proof — Meta's defence against token replay if the access token leaks.
  • debug_token works (Meta requires APPID|APPSECRET to call that endpoint).

Find them at developers.facebook.com → My Apps → {your app} → Settings → Basic.

3. Three ways to run

Mode When to use
npm (npx) Easiest for end users — no clone, no build
stdio (from source) Hacking on the server locally
Docker (Ubuntu) Shared server, multiple devices, mobile, teammates

A. Install from npm

claude mcp add meta \
  --env FB_ACCESS_TOKEN=<your-token> \
  --env FB_APP_ID=<your-app-id> \
  --env FB_APP_SECRET=<your-app-secret> \
  -- npx -y meta-mcp

Or manually in ~/.claude.json:

{
  "mcpServers": {
    "meta": {
      "command": "npx",
      "args": ["-y", "meta-mcp"],
      "env": {
        "FB_ACCESS_TOKEN": "EAA...",
        "FB_APP_ID": "<your-app-id>",
        "FB_APP_SECRET": "<your-app-secret>"
      }
    }
  }
}

In Claude Code: /mcp → meta: connected.

B. Local — stdio from source

git clone https://github.com/nourgithub/meta-mcp.git
cd meta-mcp
cp .env.example .env
# edit .env — set FB_ACCESS_TOKEN at minimum
# (also FB_APP_ID + FB_APP_SECRET for debug_token / appsecret_proof)
npm install
npm run build
claude mcp add meta -- node "$(pwd)/dist/index.js"

C. Remote — Docker on Ubuntu

Everything ships in deploy/:

  • deploy/Dockerfile — multi-stage Node 20 alpine build, runs as non-root with tini for clean signals
  • deploy/docker-compose.yml — two services: the app + Caddy as TLS-terminating reverse proxy
  • deploy/Caddyfile — auto-HTTPS via Let's Encrypt, proxies /mcp (SSE-aware) and /health

Pre-requisites: Ubuntu server with public IP and a DNS A-record pointing your domain at it.

# 1) On the server — install Docker
ssh root@SERVER_IP
apt-get update
apt-get install -y ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo $VERSION_CODENAME) stable" \
  > /etc/apt/sources.list.d/docker.list
apt-get update
apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# 2) Open ports 80 and 443 (skip if no ufw)
ufw allow 80/tcp
ufw allow 443/tcp

From your laptop, push the project to the server:

tar -czf - -C /d/meta-mcp \
  --exclude='./node_modules' --exclude='./dist' --exclude='./.env' --exclude='./.git' . \
  | ssh root@SERVER_IP "mkdir -p /opt/meta-mcp && tar -xzf - -C /opt/meta-mcp"

Back on the server, prepare .env:

ssh root@SERVER_IP
cd /opt/meta-mcp
cp .env.example .env
nano .env

Fill at minimum:

FB_ACCESS_TOKEN=EAA...
FB_APP_ID=...
FB_APP_SECRET=...

MCP_TRANSPORT=http
MCP_HTTP_PORT=8765
MCP_HTTP_AUTH_TOKEN=<openssl rand -hex 32>
MCP_HTTP_ALLOWED_HOSTS=meta-mcp.example.com

META_MCP_DOMAIN=meta-mcp.example.com
ACME_EMAIL=you@example.com

chmod 600 .env. Build and start:

cd /opt/meta-mcp/deploy
docker compose build
docker compose up -d
docker compose ps      # both services should be "running" / "healthy"
docker compose logs -f # watch Caddy fetch the cert

Verify:

curl https://meta-mcp.example.com/health
# {"ok":true,"name":"meta-mcp"}

curl -i -X POST https://meta-mcp.example.com/mcp
# 401 — missing bearer (expected)

Connect Claude Code:

claude mcp add --transport http meta https://meta-mcp.example.com/mcp \
  --header "Authorization: Bearer <your MCP_HTTP_AUTH_TOKEN>"

Pagination

All *_list tools accept:

  • limit — page size (default 25)
  • auto_paginate=true — walk paging.next up to max_pages (default 4) times
  • max_pages — safety cap

When auto_paginate=true the response shape is:

{
  "items": [ ...flattened from all pages ],
  "pages": 3,
  "truncated": false,
  "next_cursor": "QVFIUjF..."
}

Cursors are short-lived (~30 min). Don't reuse a stale next_cursor after a long delay.

Rate limits

Meta's actual budget depends on app tier (Standard / Advanced), token type, and per-object usage — there is no single fixed RPS for Graph API. The server applies:

  • Client-side: soft cap of META_RPS_LIMIT requests / second (default 25, env-tunable).
  • Header-aware cooldown: after each response we parse X-App-Usage, X-Ad-Account-Usage, X-Business-Use-Case-Usage. If any bucket > 90%, the next request is delayed (using estimated_time_to_regain_access if present).
  • Retry: on HTTP 429 or Graph error codes 4, 17, 32, 613 the request is retried with exponential backoff (max 2 retries).

Security

  • FB_ACCESS_TOKEN is sent only as Authorization: Bearer header, never as a query parameter — keeps it out of proxy / CDN logs.
  • If FB_APP_SECRET is set, every request includes appsecret_proof (HMAC-SHA256 of token with secret). Token replay from another machine fails.
  • Graph error bodies are scrubbed before being returned: occurrences of the token, app secret and appsecret_proof are replaced with *** to prevent leakage via tool output.
  • HTTP mode: MCP_HTTP_AUTH_TOKEN is mandatory, compared with constant-time. MCP_HTTP_ALLOWED_HOSTS enables DNS-rebinding protection.
  • HTTPS in Docker mode handled by Caddy automatically.

Caveats

  • Insights async jobs not supported. For huge Ads Insights ranges Meta recommends POST /insights → poll report_run_id. This server is GET-only; use shorter ranges or export from Ads Manager.
  • Webhook subscriptions out of scope. MCP is a request/response model; subscribing to realtime updates needs a separate server.
  • Page-token cache is per-process. Restarting the server clears it. First IG/Page-Insights call after restart triggers one extra /me/accounts round-trip.

Project layout

meta-mcp/
├── src/
│   ├── index.ts          # entry: picks transport, registers tools
│   ├── config.ts         # loads .env, validates required vars
│   ├── client.ts         # fetch wrapper, rate limiter, paginator, page-token cache
│   ├── http-server.ts    # Express + StreamableHTTPServerTransport + bearer auth
│   └── tools/
│       ├── raw.ts        # graph_get
│       ├── debug.ts      # debug_token
│       ├── pages.ts      # Facebook Pages
│       ├── marketing.ts  # Ads
│       ├── instagram.ts  # Instagram Graph
│       └── whatsapp.ts   # WhatsApp Business
├── deploy/
│   ├── Dockerfile
│   ├── docker-compose.yml
│   └── Caddyfile
├── .env.example
├── package.json
└── tsconfig.json

Smoke test without Claude

stdio:

echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | node dist/index.js

HTTP:

curl -sS -X POST https://meta-mcp.example.com/mcp \
  -H "Authorization: Bearer $MCP_HTTP_AUTH_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"curl","version":"0"}}}' \
  -i

License

MIT.

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
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
E2B

E2B

Using MCP to run code via e2b.

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