facebook-mcp
Provides tools for interacting with Facebook profiles, posts, and search: retrieve a user's latest post publish time, fetch recent posts with text/time/permalink, and search for people or pages by keyword.
Enables sending messages through Facebook Messenger by driving the real Messenger web UI via browser automation.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@facebook-mcpwhat time did exampleuser last post on Facebook?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
facebook-mcp
Facebook automation exposed as an MCP (Model Context Protocol) server.
Capabilities:
get_user_latest_post_time— a user's latest post publish time (e.g.exampleuser)get_user_recent_posts— recent posts with text, time and permalinksearch_people— keyword search for people (/search/people?q=...)search_pages— keyword search for pages (/search/pages?q=...)send_message— send a Messenger message
Design docs: ARCHITECTURE.en.md (English) · ARCHITECTURE.md (中文).
Status
M0 scaffolding — done
M1 transport (curl_cffi + proxy + retry/throttle) — done
M2 session + routes + profile client +
get_user_latest_post_time— done, verified liveM3 search (
search_people/search_pages) — done, verified live over pure HTTPM4 CDP transport (cookie bootstrap + packet capture) — done
M5
send_message— done, verified live (browser path)
All five tools work against the live site.
Why send_message needs a browser
Messenger's web app issues the send from its service worker, and typing/sync
traffic runs over a binary Lightspeed WebSocket whose frames contain no readable
message body. There is no page-level GraphQL mutation to replay, and the legacy
/ajax/mercury/send_messages.php endpoint is gone (404). So send_message drives
the real Messenger UI through CDP (type → click send → confirm the composer clears).
See ARCHITECTURE.en.md §8.3 for the evidence.
Related MCP server: Facebook MCP Server
Install
/opt/homebrew/bin/python3.11 -m venv .venv
.venv/bin/pip install -e ".[dev]"Requires mcp>=1.2,<2 (official MCP Python SDK, mcp.server.fastmcp).
⚠️ This project intentionally pins
mcp<2.
Configure
cp .env.example .env
# fill in FB_COOKIE / FB_COOKIE_FILE for authenticated operationsA proxy is often required to reach Facebook. The transport resolves it automatically:
FB_PROXY→HTTPS_PROXYenv → macOS system proxy.
Tools
Tool | Needs login | Description |
| no | Latest post publish time (UTC) for a username |
| no | Recent posts (text, time, permalink) |
| yes | Keyword search for people |
| yes | Keyword search for pages |
| yes (+ browser) | Send a Messenger message |
Credentials: ~/.facebook-mcp/
Cookies live outside the repository, one directory per Facebook account:
~/.facebook-mcp/ # 0700
└── accounts/
└── default/ # 0700
├── cookies.txt # 0600, Netscape format
└── account.json # 0600, metadata + per-account overridesWhich tools need credentials — measured in an incognito Chrome with zero
Facebook cookies (ARCHITECTURE.en.md §8.1):
Tool | Needs cookies | Evidence when logged out |
| no | 200 + full timeline |
| yes | 404 on the search page; GraphQL replies "Rate limit exceeded" |
| no (but needs a browser) | uses Chrome's own session |
Populate an account
# A. Export from a logged-in Chrome (one time)
bash tools/launch_chrome_debug.sh
.venv/bin/python tools/export_cookies.py --account default
# B. Or decrypt straight from your Chrome profile
.venv/bin/python tools/import_cookies.py --account default
# Inspect
.venv/bin/python tools/export_cookies.py --listThen run without a browser:
FB_TRANSPORT_MODE=http .venv/bin/facebook-mcp # uses accounts/defaultOr let the server borrow your live Chrome (cookies bootstrapped lazily):
FB_TRANSPORT_MODE=auto .venv/bin/facebook-mcpMultiple accounts
Per process (fully isolated, recommended):
{
"mcpServers": {
"facebook-default": {
"command": ".../.venv/bin/facebook-mcp",
"env": { "FB_ACCOUNT": "default", "FB_TRANSPORT_MODE": "http" }
},
"facebook-work": {
"command": ".../.venv/bin/facebook-mcp",
"env": { "FB_ACCOUNT": "work", "FB_TRANSPORT_MODE": "http" }
}
}
}Per call — every tool takes an optional account argument:
search_pages(q="pest control", account="work")
send_message(recipient="exampleuser", text="hi", account="work")Each account can bind its own browser via
cdp_urlin itsaccount.json(e.g.{"cdp_url": "http://127.0.0.1:9223"}), so two accounts never fight over the same Chrome tab.
Maintenance: Facebook ships a new frontend build
GraphQL doc_ids and variables templates change. Re-capture them:
.venv/bin/python tools/sniff.py --navigate "https://www.facebook.com/search/pages?q=pest%20control" \
--seconds 20 --save-templatesHelpers
Script | Purpose |
| Ad-hoc live check of a service |
| Capture GraphQL |
| Export Chrome cookies into |
| Decrypt cookies straight from the Chrome profile |
| Launch Chrome with DevTools + dedicated profile |
| Verify the layered import rules (CI-friendly) |
Development
make install # .venv (Python 3.11) + dev dependencies
make hooks # commit-msg hook + commit template
make check # everything CI runs: lint, format, layers, tests, MCP smokeTarget | What it does |
|
|
|
|
|
|
| verifies the layered import rules + no cycles |
|
|
| MCP stdio handshake + |
| validate commit messages on the current branch |
| per-account Chrome: |
| all of the above |
CI (.github/workflows/ci.yml)
Job | Runs |
| ruff lint + format, |
| pytest on Python 3.11/3.12/3.13 (Ubuntu) and 3.11 (macOS) + MCP smoke |
|
|
Tests are fully offline — a local http.server and a mock DevTools
(WebSocket) server stand in for Facebook and Chrome, so CI needs no network or
credentials.
Verify against the live site
.venv/bin/python tools/probe.py profile exampleuser
.venv/bin/python tools/probe.py search pages "pest control"Run
.venv/bin/facebook-mcp # stdio transport (default)
# or
.venv/bin/python -m facebook_mcpHTTP transports are available too (the SDK supports them):
# streamable-http on 127.0.0.1:8000/mcp
.venv/bin/python -c "from facebook_mcp.server import mcp; mcp.run('streamable-http')"MCP client config (example)
{
"mcpServers": {
"facebook": {
"command": "/Users/jin/Documents/GitHub/facebook-mcp/.venv/bin/facebook-mcp",
"env": { "FB_COOKIE_FILE": "/path/to/cookies.txt" }
}
}
}Commit convention
Conventional Commits, enforced locally by
make hooks and in CI by tools/commit_msg.py:
feat(search): paginate results with page_info.end_cursor
fix(accounts): keep cookies out of the repository
docs: explain why send_message needs a browserTypes: feat fix docs test refactor perf build ci chore revert.
Scopes: core transport session routes clients services server accounts cdp http proxy profile post search message tools tests ci docs deps release.
Subject: imperative, lowercase, no trailing period, header ≤ 72 chars.
See CONTRIBUTING.md for the full rules and examples.
License
MIT © facebook-mcp contributors
Not affiliated with, endorsed by, or supported by Meta/Facebook. Use it only with accounts you own or are authorized to automate, and respect Facebook's terms of service and local anti-spam / privacy law.
All usernames, page names and ids in this repository are placeholders (
exampleuser,100000000000001, …). See CONTRIBUTING.md → Documentation privacy.
Available Tools
5 toolsget_user_latest_post_timeA
Get the publish time (UTC) of a user's latest post by username. Example username: 'exampleuser' (no URL, no leading '@'). Optional account name selecting the credential set under ~/.facebook-mcp/accounts//. Defaults to the configured account.
| Name | Required | Description | Default |
|---|---|---|---|
| account | No | ||
| username | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | Whether the lookup succeeded |
| error | No | Error message when ok=False |
| post_url | No | Permalink of the latest post |
| username | Yes | Requested username |
| post_text | No | Snippet of the latest post |
| latest_post_time | No | Publish time (UTC) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It usefully discloses that the value is UTC, where account credentials live (~/.facebook-mcp/accounts/<account>/), and that the account defaults to the configured one, but it says nothing about auth failures, private/nonexistent users, or rate limits.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three compact sentences, front-loaded with the resource and return value before the input-format and account caveats. No filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return-value details need not be repeated, and both parameters are covered. The only gap is behavior on failure cases (unknown user, private profile), which is minor for a simple read-only lookup.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must carry the parameter meaning, and it does: it specifies the username format (no URL, no leading '@') with an example, and explains that account selects the credential set under ~/.facebook-mcp/accounts/<account>/ and defaults to the configured account.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: the publish time (UTC) of a user's latest post, keyed by username. The 'latest post' scoping implicitly distinguishes it from the sibling get_user_recent_posts.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied by the 'latest post' phrasing; there is no explicit statement of when to pick this over get_user_recent_posts or any other sibling. It does give input-format guidance (username, account), but that is parameter help rather than when/when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_user_recent_postsB
List a user's recent posts (newest first), including text, UTC publish time and permalink. Optional account name selecting the credential set under ~/.facebook-mcp/accounts//. Defaults to the configured account.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| account | No | ||
| username | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It usefully discloses ordering (newest first) and the credential-set semantics of the account path plus its default, but says nothing about auth requirements, rate limits, or failure behavior when an account is absent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the primary action and return contents. The second sentence is long but each clause carries real information about account resolution.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return values need not be restated, and the description does cover ordering and account resolution. However, with no annotations and 0% schema coverage it leaves the limit parameter and any failure/edge behavior undocumented.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It does explain the account parameter well (credential set under ~/.facebook-mcp/accounts/<account>/, default configured account), but limit and its default of 10 go entirely unexplained in both schema and description.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (List) and resource (a user's recent posts) plus ordering and the fields returned, which implicitly separates it from get_user_latest_post_time. It never names that sibling explicitly, so the differentiation is left for the agent to infer.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no when-to-use guidance, no conditions, and no mention of the obvious alternative get_user_latest_post_time. The only contextual remark is about the account default, which is parameter behavior rather than usage routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_pagesB
Search Facebook pages by keyword, e.g. 'pest control'. Requires a logged-in session. Optional account name selecting the credential set under ~/.facebook-mcp/accounts//. Defaults to the configured account.
| Name | Required | Description | Default |
|---|---|---|---|
| q | Yes | ||
| limit | No | ||
| account | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden. It does disclose meaningful traits — a logged-in session is required and which credential set gets selected — but says nothing about pagination, rate limits, or failure behavior, and 'search' gives no indication of read scope beyond the implicit read.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with the purpose, then prerequisite, then the optional parameter detail. No filler, though the ~/.facebook-mcp/accounts/<account>/ path spelling is verbose for what it conveys.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values needn't be explained, and the auth prerequisite is covered. The notable gap is the undocumented 'limit' parameter, which appears in neither the description nor the schema, and no indication of how many results or pagination behavior to expect.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It documents 'q' (with an example) and 'account' (credential path plus default), which is worthwhile, but 'limit' is never mentioned and neither 'q' nor 'account' syntax is fully specified beyond the example.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Search Facebook pages by keyword') and gives a concrete example query. The resource 'pages' implicitly separates it from search_people, but the description never names that sibling or other alternatives, so differentiation is left to inference.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the purpose plus the stated prerequisite ('Requires a logged-in session'), but there is no explicit when-to-use/when-not guidance and no pointer to alternatives like search_people for a different entity type.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_peopleA
Search Facebook people by keyword, e.g. 'pest control'. Requires a logged-in session. Optional account name selecting the credential set under ~/.facebook-mcp/accounts//. Defaults to the configured account.
| Name | Required | Description | Default |
|---|---|---|---|
| q | Yes | ||
| limit | No | ||
| account | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden; it usefully discloses the auth requirement (logged-in session) and how credentials resolve via ~/.facebook-mcp/accounts/<account>/ with a configured default. Beyond that it says nothing about result volume, pagination, or rate limits, so disclosure is partial.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with purpose, then prerequisites and the optional account detail. Nothing is wasted, though the long filesystem path could be trimmed for readability.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained. Purpose, auth prerequisite, and account selection are covered; the only gap is the undocumented 'limit' parameter and any result-count behavior, which is minor for this tool's complexity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the schema provides no parameter documentation. The description does compensate for 'account' by explaining its credential-directory semantics and default, and it illustrates 'q' with an example, but 'limit' is entirely unaddressed despite its default of 10.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Search Facebook people by keyword') and reinforces it with a concrete query example. It implicitly distinguishes itself from the sibling search_pages, but never names that alternative to remove the ambiguity between searching people vs pages.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage context is implied by the resource ('Search Facebook people') and a prerequisite is stated ('Requires a logged-in session'), but there is no explicit statement of when to choose this over search_pages or the get_user_* siblings, and no exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send_messageA
Send a Messenger message to a user or page. 'recipient' accepts a numeric uid, a username/vanity, or a profile URL. Requires a logged-in browser (FB_TRANSPORT_MODE=auto or cdp). Optional account name selecting the credential set under ~/.facebook-mcp/accounts//. Defaults to the configured account.
| Name | Required | Description | Default |
|---|---|---|---|
| text | Yes | ||
| account | No | ||
| recipient | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | Whether the message was sent |
| error | No | Error message when ok=False |
| thread_id | No | Messenger thread id |
| message_id | No | Sent message id |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. It usefully discloses the auth/transport prerequisite and where account credentials live, which is real context the schema cannot express. But for a mutation (message-send) tool it omits delivery semantics — immediacy, failure modes, rate limits, or irreversibility — leaving the behavioral picture incomplete.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action, then recipient syntax, then prerequisites and account default — a logical ordering with little waste. It is slightly verbose (three clauses on transport/account paths) but each clause conveys usable information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be described, and the description covers prerequisites, recipient formats, and account selection for a 3-parameter tool. The remaining gap is mutation-side behavior (rate limits, failure handling), which keeps it short of fully complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate and largely does: it explains that 'recipient' accepts a numeric uid, username/vanity, or profile URL, and that 'account' selects a credential set under ~/.facebook-mcp/accounts/<account>/ and defaults to the configured account. Only 'text' is left undocumented, but its meaning is self-evident.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a concrete verb+resource ('Send a Messenger message to a user or page'), leaving no ambiguity about the operation. It does not reference any sibling tool, but the action is inherently distinct from the read-only siblings (search_people, get_user_recent_posts), so differentiation is implicit rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives prerequisites ('Requires a logged-in browser (FB_TRANSPORT_MODE=auto or cdp)') which effectively tells the agent when the tool can be invoked. However, it never states when to prefer this over alternatives, nor any exclusions (e.g., unsolicited/spam messaging limits or rate limits). Usage is only implied by the tool's obvious purpose.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
5 tool updates
v0.1.0- First observed
get_user_latest_post_time - First observed
get_user_recent_posts - First observed
search_pages - First observed
search_people - First observed
send_message
TDQS
Scored across 5 tools
search_people, search_pages, and send_message are clearly distinct, and the two retrieval tools target different scopes. However, get_user_latest_post_time is essentially a subset of get_user_recent_posts (which returns newest-first posts with publish times), so an agent may struggle to justify choosing one over the other.
All five tools follow a consistent snake_case verb_noun pattern (get_user_*, search_*, send_message). No mixed conventions or vague verbs; the naming is predictable and self-explanatory.
Five tools is a reasonable, well-scoped surface for a Facebook read/search/messaging server. It is on the lean side but each tool earns its place, with no filler.
The surface covers reading posts, searching people/pages, and sending messages, but lacks any content-creation (posting, commenting, liking) or message/conversation retrieval, leaving notable gaps for a Facebook interaction server.
Maintenance
Related MCP Connectors
Create, schedule, and publish social posts, manage accounts, and read analytics as MCP tools.
Discover MCP servers and A2A agents; verify, message, post, follow, react, and receive webhooks.
Search people and companies, enrich profiles, and find email and phone over MCP.
Hosted Meta ads MCP with OAuth, bounded reads, and prepare/confirm writes.
Related MCP Servers
- -licenseNot gradedqualityNot gradedmaintenanceEnables posting text messages to Facebook business pages through MCP. Supports OAuth authentication and manual connection methods for managing Facebook page content.-
- FlicenseAqualityDmaintenanceA Model Context Protocol (MCP) server implementation that provides Facebook Page interaction and management capabilities. This server enables automated posting, comment moderation, and content retrieval.777-
- AlicenseBqualityCmaintenanceEnables MCP-based interaction with the Meta Graph API for Facebook Pages and linked Instagram Business accounts, including posting, commenting, and reading page details.66 npmMIT
- AlicenseAqualityAmaintenanceEnables MCP clients to query public Facebook pages and profiles by handle, retrieving like counts, contact details, owner info, and recent posts with reactions, comments, and shares as structured JSON.140 npm46 PyPI11MIT