facebook-mcp  / Pages MCP server pre-1.0 · not on npm
Model Context Protocol · Facebook Pages

Drive your Facebook Page from your AI assistant.

facebook-mcp is a local-first MCP server for the Meta Graph API. Publish posts, read live insights, and moderate comments and messages — from any MCP client, with least-privilege tokens and writes you have to approve.

MIT licensed TypeScript · ESM Node.js 22+ MCP SDK 1.29 Graph API v25.0 No telemetry
assistant · facebook-mcp live
you › Publish today's launch post and pin it.
▸ facebook_create_post (plan)
  preview: "We just shipped…" · link · no media
  ⚠ nothing was published — awaiting apply
you › Looks good — apply.
▸ facebook_create_post (apply) → post 102…847
▸ facebook_get_insights (read)
post_impressions1,204
post_reactions_by_type86

Pre-1.0, in active development. The design is complete and documented; implementation is in progress. Interfaces and scope may change until the first tagged release, and the package is not yet published to npm — for now you run it from source (see Quick start).

4/35tools live today
7planned tool packages
4layers · core←api←mcp←tools
3allow-listed Meta hosts
0telemetry calls
See it in action

Three things it does, in one place

Your assistant calls a small, curated set of tools. Each one wraps a real, verified Graph API capability — not every raw edge. The three below are designed and scheduled, not yet shipped — they land in v0.2.0 and v0.3.0.

Publish a post

Text, link, photo, video or Reels — with scheduling, edits and deletes. The write is previewed first; nothing hits your Page until you say apply.

facebook_create_post write
# assistant → tool call (dry-run preview)
{
  "message": "We just shipped v1 🎉",
  "link": "https://example.com/launch",
  "published": true
}

→ PREVIEW · resolves Page, checks perms
→ "The post was NOT published."
→ call again with { "apply": true }

Read insights

Page and post reads with cursor pagination and live-verified metric names — no guessing at deprecated fields. Reads never mutate anything.

facebook_get_insights read
# assistant → tool call
{
  "object": "post",
  "metrics": ["post_impressions",
              "post_reactions_by_type"]
}

→ post_impressions            1,204
→ post_reactions_by_type        86
→ paging cursors stripped of tokens

Moderate a comment

Hide, unhide or delete comments; read and reply to Page messages. Moderation is reversible where the platform allows, so it can default to a lighter confirmation posture.

facebook_hide_comment write
# assistant → tool call
{
  "comment_id": "102…847_9911",
  "hidden": true
}

→ PREVIEW · before-state: visible
→ apply → comment hidden
→ recorded to local write journal
    (metadata only, secrets redacted)
Background

What is the Model Context Protocol?

The Model Context Protocol (MCP) is an open standard that lets AI assistants call external tools through a uniform interface. An MCP server exposes a set of typed tools; an MCP client (your assistant) discovers them and calls them on your behalf.

facebook-mcp is one such server. It runs on your own machine, talks only to Meta's Graph API, and turns Page operations — publishing, insights, moderation — into tools your assistant can use. Because it runs locally with your token, there is no third-party service in the middle: your credentials never leave your machine, and the server never phones home.

Standard interface

Works with any MCP client over stdio — Claude Desktop, Claude Code, VS Code, Cursor and others.

Runs where you do

A local process using your own Meta developer app and token. No hosted middleman, no account linking.

Curated tools

A deliberately small surface — each tool wraps a verified capability rather than mirroring every Graph edge.

What it does

Capabilities

Grouped into packages you can enable or restrict. The default profile is publishing, reading, insights, moderation and messages — with ads deliberately left off. The Ships in column is the honest part: only core is live today, the rest is designed and scheduled.

Area What it covers Default Ships in
Core & diagnostics Identity, Page listing, rate-limit usage, doctor pre-flight on live
Reading Page & post reads, Reels, reactions, cursor pagination on v0.2.0
Publishing Text, link, photo, video & Reels posts; scheduling; edit & delete on v0.2.0
Insights & moderation Live-verified metrics; comment hide / unhide / delete; blocking on v0.3.0
Messaging Conversation reads and replies inside the 24-hour window on v0.4.0
Ads Campaign / ad-set / ad reads plus status & budget control opt-in v0.5.0

Core & diagnostics live

Classify your token, list the Pages you administer, read Graph rate-limit usage and run doctor before you connect.

Publishing v0.2.0

Compose and schedule posts across every media type, then edit or delete them — each write previewed before it runs.

Reading & insights v0.2–0.3

Pull Page and post data and live-verified insight metrics with cursor pagination that never persists tokens.

Moderation & messages v0.3–0.4

Hide, unhide or delete comments and read and reply to Page conversations, keeping your community tidy.

Ads — opt-in v0.5.0

Read campaigns and control status and budget. Off by default (Meta ships an official ads MCP); enable it deliberately.

Local-first, no telemetry

Only three Meta hosts are ever reached. Nothing about your usage is collected or sent anywhere.

Safe, gated writes

Tiered plan-and-apply gating. Irreversible and spend actions always need an explicit, per-call confirmation.

Set up

Quick start

There is no npm package yet, so you run it from source. Three steps to a working server, then point your MCP client at it.

1 Clone & build

git clone https://github.com/IvanBBaev/facebook-mcp cd facebook-mcp npm install npm run build

2 Provide credentials

export FB_ACCESS_TOKEN=EAA… export FB_PAGE_ID=1234567890 export FB_APP_SECRET=… # appsecret_proof

3 Run it

node build/index.js

Speaks MCP over stdio. Usually you won't run it by hand — your MCP client launches it using the config on the right.

~/Library/Application Support/Claude/claude_desktop_config.json
{
  "mcpServers": {
    "facebook": {
      "command": "node",
      "args": ["/abs/path/facebook-mcp/build/index.js"],
      "env": {
        "FB_ACCESS_TOKEN": "EAA…",
        "FB_PAGE_ID": "1234567890",
        "FB_APP_SECRET": "…"
      }
    }
  }
}

After the first release — once facebook-mcp is published to npm — the same config becomes a one-liner, no clone or build required:

json
{
  "mcpServers": {
    "facebook": {
      "command": "npx",
      "args": ["-y", "@ivanbbaev/facebook-mcp"],
      "env": {
        "FB_ACCESS_TOKEN": "EAA…",
        "FB_PAGE_ID": "1234567890"
      }
    }
  }
}

Not available yet — shown here as the intended shape once the package ships. Track progress on GitHub.

Set up

Credentials

You bring your own Meta developer app and a token for a Page you administer. facebook-mcp uses the least privilege that works — and no App Review, because you operate your own assets.

Two token routes

System User token

A never-expiring token issued from Business Manager. Best for a stable, long-running setup where a Business owns the Page.

Long-lived Page token

A first-class fallback — no Business Manager required. Ideal when you simply administer a Page yourself.

Environment variables

Variable Purpose
FB_ACCESS_TOKEN Your System User or long-lived Page token. Sent as a Bearer header — never in a query string.
FB_PAGE_ID The default Page the tools operate on.
FB_APP_SECRET Used to compute appsecret_proof (HMAC-SHA256) on every call.
FB_API_VERSION Graph API version pin (defaults to a tested version).
FB_TOOL_PACKAGES Which tool packages to expose. Unset ⇒ the default profile (ads excluded).

Config is env-first: values passed by the client beat the env file. On-disk config lives under an XDG path and is written atomically with 0600 permissions. Your token is never logged and is stripped from any Graph response before it leaves the process.

No Meta App Review is required for an admin operating their own Page. Start read-only, confirm the topology, then enable writes when you are ready.

Under the hood

Architecture

A thin, lint-enforced stack. Each layer may only import the one below it, so tools can never reach around policy straight to the network.

tools ToolSpec[] per package — data, not code · facebook_<verb>_<noun> L3 mcp registry & packages · result shaper · write-mode + journal · transport L2 api Graph domain functions · posts · insights · comments · messaging · ads L1 core config & auth · HTTP client + upload protocols · host allowlist · redaction L0
core ← api ← mcp ← tools — enforced with ESLint no-restricted-imports. Tools never import core/http directly.

The three-host fence

There is exactly one vendor, so the HTTP client hard-codes a fixed host allowlist — there are no user-configurable hosts. Every request, including chunked media uploads, goes through one choke-point that can only reach these three:

graph.facebook.com graph-video.facebook.com rupload.facebook.com

One fbRequest() entry point covers all three wire protocols — JSON / query-string reads and simple writes, multipart FormData for direct binary uploads, and raw-binary rupload for chunked resumable video and Reels — so no media path can bypass auth, redaction or the host fence.

Under the hood

Security & safety

Publishing to a real audience is the most consequential thing this server does, so safe-by-default is non-negotiable.

Local-first, no telemetry

The server reaches only the three allow-listed Meta hosts. Nothing about your usage is collected, and nothing phones home.

Least-privilege tokens

A System User or long-lived Page token, sent as a Bearer header — never in a query string, so it can't leak into paging.next URLs.

Plan-and-apply writes

Every write previews first and mutates nothing. Delete and spend tiers always need a per-call apply — never bypassed by an env flag.

Single-choke-point redaction

One function scrubs raw secret values — tokens, app secret, appsecret_proof — across logs, errors, results and the journal.

Defense in depth

  • appsecret_proof (HMAC-SHA256) is attached to every Graph call.
  • Response scrubbing recursively strips every paging object and token-bearing URL before a payload leaves the process.
  • SSRF containment — the fixed host allowlist means no request can be steered to an arbitrary host; local file uploads are off unless you explicitly set FB_MEDIA_DIR (realpath-confined, no cross-host redirects).
  • HTTP transport fails closed — it refuses to start without FB_HTTP_TOKEN, binds 127.0.0.1 only, validates the Origin header, and constant-time checks the bearer on every request.
  • Ambiguous writes are never auto-retried — Graph has no idempotency keys, so a publish/send/delete whose outcome is unknown is surfaced for you to verify, never blindly replayed.

Because an assistant can ingest untrusted content (comments, messages) and also hold a write-capable token, the recommended posture for unattended runs is read-only. Irreversible and spend actions always require out-of-band confirmation that an environment flag can never satisfy.

Questions

FAQ

Is this affiliated with Meta?

No. This is an independent, community-built project and is not affiliated with, endorsed by, or sponsored by Meta Platforms, Inc. "Facebook" and "Meta" are used only nominatively, to indicate what the server is compatible with.

Which credentials does it need?

A Meta developer app plus one access token — either a never-expiring System User token from Business Manager, or a long-lived Page token. The app secret is used to compute appsecret_proof. Because you administer your own Page, no App Review is required.

Is it safe to let it write to my Page?

Writes are gated. Every write tool first returns a dry-run preview and performs zero network mutations; you approve with an explicit apply. Irreversible actions (delete) and spend actions (ads) always require a per-call confirmation and are never bypassed by an environment flag. Starting read-only is recommended.

What actually works today?

The foundation — HTTP client, auth, write gating, transports, tool registry — is implemented and tested, and the read-only core package ships four tools: facebook_whoami, facebook_list_pages, facebook_get_page and facebook_usage. Everything else on this page is designed and scheduled; see the roadmap board for what lands when.

When will it be published to npm?

Not yet. facebook-mcp is pre-1.0 and in active development — the design is complete and documented while implementation is in progress. An npm package will ship with the first tagged release; until then you run it from source. Progress is tracked in the milestones.

Which MCP clients does it work with?

Any client that speaks MCP over stdio — for example Claude Desktop, Claude Code, VS Code and Cursor. An optional loopback-only Streamable HTTP transport is available for advanced setups.

Keep it going

Support the project

facebook-mcp is MIT-licensed, free, collects nothing and is built by one maintainer in their own time. There is no paid tier and never will be — if it saves you an afternoon, a tip is what funds the next milestone.

GitHub Sponsors

One-off or recurring, no platform fee, and it shows up on the repository. The best option if you already have a GitHub account.

Ko-fi

A quick one-off tip, card or PayPal, no account needed. The fallback for anyone who does not use GitHub.

Buy me a coffee

Donatree

A single page collecting every donation method in one place — useful if you prefer a local payment option.

Open Donatree

Not in a position to donate? That is completely fine — starring the repository, filing a good bug report, or telling another Page admin about it helps just as much. Support questions go through SUPPORT.md; donating buys no priority and no SLA.