mcp-whatsapp

by sealjay

Not rated
GitHub

About

Local MCP server for a personal WhatsApp account. Single Go binary wrapping whatsmeow. Adds LID resolution, sent-message storage, disappearing-message timers, targeted history sync. Personal-use; Meta ToS applies.

Details

Author
sealjay
Categories
Communication, Other

Setup

Install mcp-whatsapp in your MCP client (Claude Desktop, Cursor, Windsurf, and others).

Repository: https://github.com/sealjay/mcp-whatsapp

Follow the installation instructions in the repository README, then restart your MCP client.

A single-binary GoMCPserver that wrapswhatsmeowto expose a personal WhatsApp account to LLMs.whatsapp-mcp serveruns as a lightweight HTTP daemon on127.0.0.1:8765; MCP clients (Claude Desktop, Cursor, Claude Code, etc.) connect to it via HTTP — no process spawning, no stdin/stdout juggling. Messages are cached in local SQLite and only travel to the model when the agent calls a tool.

Unaffiliated.This is an independent open-source project. It is not affiliated with, endorsed by, or otherwise associated with Meta Platforms, Inc., WhatsApp, orwhatsmeow. "WhatsApp" is a trademark of Meta Platforms, Inc., used here nominatively to describe interoperability.

This started as a fork oflharries/whatsapp-mcpand has since been rewritten as a single Go binary. What it adds over the original:

- LID resolution— normalises@lidJIDs to real phone numbers for accurate contact matching.
- Sent-message storage— outgoing messages are persisted locally so conversation history stays complete.
- Disappearing-message timers— outgoing messages inherit the group chat's ephemeral timer automatically.
- Targeted history sync— on-demand per-chat backfill via therequest_synctool.
- Extended tool surface— 42 tools (see below): reactions, replies, edits, revoke, mark-read, typing, is-on-whatsapp, full group admin, blocklist, polls (create + vote + tally), contact cards, view-once flag, presence, privacy settings, and the profile "About" text.
- Single-instance enforcement— aflock(2)onstore/.lockprevents twoserveprocesses racing on the same SQLite files.

- Go 1.25+ (build-time only; runtime needs just the compiled binary).
- An MCP client that speaks HTTP (Claude Desktop, Cursor, Claude Code, etc.).
- FFmpeg (optional) — required only forsend_audio_messagewhen the input is not already.oggOpus. Without it, usesend_fileto send raw audio.
- Windows:CGO must be enabled — see
docs/windows.md.

git clone https://github.com/Sealjay/mcp-whatsapp.git cd mcp-whatsapp make build # writes ./bin/whatsapp-mcp

Start the daemon, then open the pairing page in a browser:

./bin/whatsapp-mcp serve # starts on 127.0.0.1:8765 open http://127.0.0.1:8765/pair # macOS; or visit the URL manually

Scan the QR code with WhatsApp on your phone (Settings → Linked Devices → Link a Device). The pairing persists to./store/whatsapp.db. When WhatsApp invalidates the session (roughly every 20 days), visit/pairagain and re-scan.

Alternative (headless / CI):./bin/whatsapp-mcp loginrenders the QR in the terminal. Use this when a browser isn't available.

whatsapp-mcp serveis an HTTP daemon on127.0.0.1:8765(or$WHATSAPP_MCP_ADDR). MCP clients connect to it over HTTP:

// Claude Desktop — ~/Library/Application Support/Claude/claude_desktop_config.json { "mcpServers": { "whatsapp": { "url": "http://127.0.0.1:8765/mcp" } } }
// Claude Code — .claude/mcp.json (project) or ~/.claude/mcp.json (user) { "mcpServers": { "whatsapp": { "type": "http", "url": "http://127.0.0.1:8765/mcp" } } }
// Cursor — ~/.cursor/mcp.json { "mcpServers": { "whatsapp": { "type": "http", "url": "http://127.0.0.1:8765/mcp" } } }

Restart the client. WhatsApp appears as an available integration. Closing and reopening the client reconnects to the daemon — no process spawn, no per-session handshake, no stdin/stdout juggling.

WHATSAPP_MCP_MEDIA_ROOTgates both directions of file movement:

- Sendingsend_fileandsend_audio_messageaccept amedia_pathargument pointing at the file to send. The path must live under the allowed root.
- Receivingdownload_mediawrites decrypted media to the daemon cache at<store>/<chat_jid>/. Passing the optionaloutput_pathargument additionally places the file at a caller-chosen location, which must also live under the allowed root. If a file already exists atoutput_paththe call is a no-op.

By default the allowed root is./store/uploads/(resolved relative to your-storedirectory). On first run,servecreates it automatically; drop files you intend to send into it and pointoutput_pathhere if you want to read incoming media from the same place.

To allow a different directory, setWHATSAPP_MCP_MEDIA_ROOT(absolute path) when starting the daemon:

WHATSAPP_MCP_MEDIA_ROOT=/Users/me/whatsapp-shared ./bin/whatsapp-mcp serve

Or add it to your launchd plist / systemd unit / shell profile so it persists across restarts.

Paths outside the allowed root are rejected with a clear error so Claude can ask you to move the file or update the env var. Symlinks inside the root are resolved before the check, so a symlink that points out of the root is also rejected. Do not place secrets inside the allowed root — the allowlist bounds what the tool can read or write, but anything inside is fair game.

Sandboxed clients (Claude.ai with Cowork, etc.)

Sandboxed MCP clients cannot read the daemon's local cache. To make downloaded media visible to them, pointWHATSAPP_MCP_MEDIA_ROOTat a directory the client's sandbox can also read (a Cowork workspace mount, a shared volume, etc.), and tell the client to passoutput_pathon everydownload_mediacall into that root. A copy-pasteable system instruction:

When calling the WhatsApp MCP'sdownload_media, always passoutput_pathset to a path under your shared workspace. Without it the decrypted file lands only in the daemon's local cache, which is outside your sandbox and unreadable.output_pathmust live underWHATSAPP_MCP_MEDIA_ROOTon the daemon side; the basename is yours to pick.

cmd/whatsapp-mcp/ login / serve / smoke subcommands internal/client/ whatsmeow client wrapper (send, download, events, history, features) internal/daemon/ HTTP server, pairing state machine, /pair endpoint internal/mcp/ mark3labs/mcp-go server + tool registrations internal/media/ ogg parsing, waveform synthesis, ffmpeg shell-out internal/security/ path allowlisting, filename sanitisation, log redaction internal/store/ SQLite cache, LID resolution, query layer

serveruns as a long-lived HTTP daemon. MCP clients connect and disconnect freely; the daemon stays up and continues receiving WhatsApp events. Aflock(2)onstore/.lockprevents two instances racing on the same store (WhatsApp would kick one of the two linked-device connections anyway).

The trade-off: events are persisted to SQLiteonly whileserveis running. If the daemon stops, the WhatsApp connection closes. On the next start, whatsmeow emitsevents.HistorySyncevents that backfill conversations into SQLite, but the recovery window is governed by WhatsApp's server-side retention for multidevice clients — not by this codebase. Messages that arrive during a gap long enough to outlast WhatsApp's retention are not recoverable. For shorter, known gaps, therequest_synctool triggers a per-chat backfill on demand.

Everything lives under./store/(override with-store DIR):

- store/messages.db— local chat/message cache, indexed for search.
- store/whatsapp.db— whatsmeow's own device/session state.
- store/.lock— ephemeral advisory lock for single-instanceserve.
- The client sends a JSON-RPCtools/calltoserveover HTTP.
- The MCP layer dispatches to an internal handler.
- The handler either queries the local SQLite store or calls whatsmeow directly (send, download, reactions, etc.).
- Incoming WhatsApp events are persisted to the store in a background goroutine inside the same process, so query tools always see current state.

The daemon is designed to run independently of any MCP client. Three supported lifecycle models:

macOS — launchd.Template atdocs/launchd/com.sealjay.whatsapp-mcp.plist. Copy to~/Library/LaunchAgents/, replace{{PATH_TO_REPO}}/{{STORE_DIR}}placeholders,launchctl load. Daemon runs from login onwards.

Linux — systemd user unit.Template atdocs/systemd/whatsapp-mcp.service. Copy to~/.config/systemd/user/, replace placeholders,systemctl --user enable --now whatsapp-mcp.

Claude Code SessionStart hook.For project-scoped lifetimes, dropdocs/hooks/setup.shinto your project's.claude/hooks/and configuresettings.jsonto invoke it. The hook is idempotent — safe to run alongside launchd/systemd.

Manual../bin/whatsapp-mcp serve -addr 127.0.0.1:8765in any terminal. Ctrl-C to stop.

First-time pairing happens in a browser: start the daemon, openhttp://127.0.0.1:8765/pair, scan the QR with your phone. No terminal required. WhatsApp's multidevice protocol rotates the linked-device session roughly every 20 days; when that happens, the/pairpage serves a fresh QR automatically — visit it again and re-pair. The/pair/endpoints are rate-limited (5 GET/min, 1 POST/min on/pair/reset) and CSRF-protected.

Flags and environment variables forserve:

- -addr host:port(envWHATSAPP_MCP_ADDR, default127.0.0.1:8765).
- -allow-remote(explicit opt-in to bind a non-loopback address; requiresWHATSAPP_MCP_TOKEN).
- WHATSAPP_MCP_TOKEN— bearer token for/mcpand/pair/
when-allow-remoteis set. Required;serveexits if missing.
- WHATSAPP_MCP_MEDIA_ROOT— allowed root forsend_file/send_audio_messagemedia_pathanddownload_mediaoutput_path.
- WHATSAPP_MCP_DEBUG=1— enable verbose logging with partial phone-number redaction (last 5 digits visible).

- Prompt-injection risk:as with many MCP servers, this one is subject tothe lethal trifecta. Prompt injection in incoming messages could lead to private data exfiltration — treat the tool surface accordingly.
- Re-authentication:WhatsApp may invalidate the linked-device session periodically; re-run./bin/whatsapp-mcp loginwhen that happens.
- Message gaps whenserveisn't running:events only flow into SQLite while the binary is alive. Messages sent during an offline window are recovered on next reconnect only if WhatsApp's multidevice retention still holds them; for longer gaps userequest_syncper chat, or accept the loss.
- Single instance per store:only onewhatsapp-mcp servecan hold the store lock. Parallel MCP clients must point at different-storedirectories (and therefore different paired sessions).
- Windows:requires CGO and a C compiler — see
docs/windows.md.
- Upstream bounds:message fetch/send is bounded by what
whatsmeowsupports against the WhatsApp web multidevice API.
- Log redaction is obfuscation, not anonymisation.Partial knowledge of your contacts allows correlation from the last 5 visible digits. Symlinks inside./store/uploads/are resolved before the path check so they cannot escape, but the root itself is a trust boundary — only place files you intend to send inside it.

make test # unit tests make test-race # with -race make vet # go vet make e2e # build + JSON-RPC smoke over HTTP (requires -tags=e2e) make smoke # boot-test the server without connecting to WhatsApp

Weekly CI runs an upstream upgrade probe. To do it manually:

This bumpsgo.mau.fi/whatsmeow@main, re-tidies, builds, and tests. If green, commit thego.mod/go.sumchanges.

scripts/mdtest-parity.shin CI fails the build early if upstream removes or renames any whatsmeow method we call — it's the canary for API drift.

- connect failed …onserve— the daemon is not paired. Openhttp://127.0.0.1:8765/pairin a browser and scan the QR. Alternatively, run./bin/whatsapp-mcp loginin a terminal.
- another whatsapp-mcp instance is already running— only oneservecan hold the store lock. Check for a stray process (ps aux | grep whatsapp-mcp) or another MCP client pointed at the same-storedirectory.
- QR doesn't display— the terminal doesn't render half-block Unicode. Try iTerm2, Windows Terminal, or similar.
- Device limit reached— WhatsApp caps linked devices. Remove one fromSettings → Linked Deviceson your phone.
- No messages loading— after initial auth, it can take several minutes for history to backfill. Userequest_syncto target a specific chat.
- WhatsApp out of sync— delete both database files (store/messages.dbandstore/whatsapp.db) and re-runlogin.
- ffmpeg not foundsend_audio_messageneeds ffmpeg onPATHto convert non-Opus audio. Usesend_filefor raw audio instead.

By default, JIDs in stderr logs are redacted to…<last-4-chars-of-user-part>and message bodies are summarised as[<length>B: text|url|command]. Media CDN URLs are collapsed to<scheme>://<host>/…. To see message content while actively debugging:

-

As a flag:./bin/whatsapp-mcp -debug serve

As an env var in your MCP client config:

"env": { "WHATSAPP_MCP_DEBUG": "1" }

Even with debug mode on, phone-number-shaped digit sequences in bodies and JIDs are partially masked — only the last 5 digits are visible (e.g.+15551234567*34567). This means debug logs are safe to share in bug reports without leaking full phone numbers.

Honesty disclaimer.*The partial-redaction scheme is obfuscation for log-reader convenience, not anonymisation. Someone with independent knowledge of your contacts can still correlate the last 5 digits with a specific phone number. Treat redacted logs as "probably safe to paste into a GitHub issue", not "anonymised".

For Claude Desktop integration issues, see theMCP documentation.

Contributions welcome via pull request. SeeCONTRIBUTING.md.

Manage your WhatsApp, SMS and Phone Calls using a single MCP connector

Send SMS, WhatsApp, and RCS messages programmatically with DLT compliance. Manage contacts, schedule campaigns, and track delivery reports.

Remote MCP server for managing WhatsApp and Telegram AI assistants: projects, prompts, conversations, leads and analytics, with no destructive tools by design.

143 local tools for Claude, Cursor & ChatGPT — Mail, iMessage, Teams, Slack, WhatsApp & files. 100% local, no API keys.

An MCP server for Claude that integrates with the Evolution API for WhatsApp automation.

Create AI-generated memes and convert them into stickers for Telegram and WhatsApp.

An MCP server integrating WhatsApp messaging and ElevenLabs AI voice capabilities into VS Code.

WhatsApp automation platform with 120+ MCP tools for AI chatbots, broadcasts, campaigns, contact management, knowledge bases, and newsletters

Salesforce MCP Server - Enhanced Edition

A Salesforce MCP server with automatic integrations for services such as WhatsApp, Slack, email, and custom webhooks.

Configure and train your TBit WhatsApp/Instagram AI agents from ChatGPT or Claude (remote, OAuth 2.1)

No reviews yet — be the first

Sign in to leave a review

Use Google, GitHub, or an email account so ratings stay tied to real people.

Email sign in

No reviews posted yet.