mcp-whatsapp
Single-binary Go MCP server that wraps whatsmeow to expose a personal WhatsApp account as 42 MCP tools (messaging, groups, polls, media, privacy).
Install / Use
claude mcp add Sealjay -- npx -y github:Sealjay/mcp-whatsappIf the server publishes to npm under a different name, use that package instead — check the repo README.
MCP Server
Model Context Protocol server
Quality Score
Category
CommunicationSupported Platforms
Our assessment of mcp-whatsapp
mcp-whatsapp scores 76/100 on our quality scale, 406th of 431 Communication skills we index.
Its MCP Server is 23 KB long, well organised into 29 sections with 13 code examples: a thorough specification that gives an agent plenty to work with.
It has 10 GitHub stars, so there is little community track record yet; judge it on its content.
Maintenance, license and trust
- The repository was last updated 10 days ago, so mcp-whatsapp is actively maintained.
- It is released under the MIT license, a permissive license that allows use, modification and commercial use with attribution.
- Its trust signals score 97/100, with no cautions. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.
mcp-whatsapp compared with similar skills
All 4 of these similar skills score higher than mcp-whatsapp; compare them before choosing.
| Skill | Score | Stars | Updated | Format |
|---|---|---|---|---|
| mcp-whatsapp (this skill)by Sealjay | 76 | 10 | 10d ago | MCP Server |
| claude-memby thedotmack | 100 | 96.6k | today | CLAUDE.md |
| Agent-Reachby Panniantong | 100 | 91.8k | 20d ago | CLAUDE.md |
| headroomby headroomlabs-ai | 100 | 74.5k | today | CLAUDE.md |
| CowAgentby zhayujie | 100 | 47.2k | today | CLAUDE.md |
Frequently asked questions
- How do I install mcp-whatsapp?
- Run
claude mcp add Sealjay -- npx -y github:Sealjay/mcp-whatsapp. The install tabs above show the steps for each supported agent. - Which AI agents does mcp-whatsapp work with?
- It is written for Claude Code and Claude Desktop, as a MCP Server file. Other agents that read the same format can often use it too.
- Is mcp-whatsapp safe to use?
- It is MIT-licensed and scores 97/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
- Is mcp-whatsapp still maintained?
- The repository was last updated 10 days ago, so mcp-whatsapp is actively maintained.
Skill content
View source on GitHubWhatsApp MCP Server
A single-binary Go MCP server that wraps whatsmeow to expose a personal WhatsApp account to LLMs. whatsapp-mcp serve runs as a lightweight HTTP daemon on 127.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, or whatsmeow. "WhatsApp" is a trademark of Meta Platforms, Inc., used here nominatively to describe interoperability.
This started as a fork of lharries/whatsapp-mcp and 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 the
request_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 — a
flock(2)onstore/.lockprevents twoserveprocesses racing on the same SQLite files.
Setup
Prerequisites
- 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 for
send_audio_messagewhen the input is not already.oggOpus. Without it, usesend_fileto send raw audio. - Windows: CGO must be enabled — see docs/windows.md.
Install
git clone https://github.com/Sealjay/mcp-whatsapp.git
cd mcp-whatsapp
make build # writes ./bin/whatsapp-mcp
Pair your phone (first run only)
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 /pair again and re-scan.
Alternative (headless / CI): ./bin/whatsapp-mcp login renders the QR in the terminal. Use this when a browser isn't available.
Connect your MCP client
whatsapp-mcp serve is an HTTP daemon on 127.0.0.1:8765 (or $WHATSAPP_MCP_ADDR). MCP clients connect to it over HTTP:
Claude Desktop's claude_desktop_config.json doesn't support a bare url/type: http entry the way Claude Code and Cursor do — it only launches stdio servers via command/args. Bridge it with mcp-remote instead:
// Claude Desktop — ~/Library/Application Support/Claude/claude_desktop_config.json
{
"mcpServers": {
"whatsapp": {
"command": "npx",
"args": ["-y", "mcp-remote", "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.
Sending and receiving files
WHATSAPP_MCP_MEDIA_ROOT is an allowlist root and gates both directions of file movement:
- Sending —
send_fileandsend_audio_messageaccept amedia_pathargument pointing at the file to send. The path must live under the allowed root. - Receiving —
download_mediawrites decrypted media to the daemon cache at<store>/<chat_jid>/<hex(message_id)>/<safe_filename>. The message-ID directory prevents distinct messages with the same filename from sharing cached bytes; cache hits are checked against the stored size and SHA-256 when available. 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 -store directory). On first run, serve creates it automatically; drop files you intend to send into it and point output_path here if you want to read incoming media from the same place.
To allow a different directory, set WHATSAPP_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, point WHATSAPP_MCP_MEDIA_ROOT at a directory the client's sandbox can also read (a Cowork workspace mount, a shared volume, etc.), and tell the client to pass output_path on every download_media call into that root. A copy-pasteable system instruction:
When calling the WhatsApp MCP's
download_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.
Architecture
One binary, seven internal packages:
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
Process lifecycle
serve runs as a long-lived HTTP daemon. MCP clients connect and disconnect freely; the daemon stays up and continues receiving WhatsApp events. A flock(2) on store/.lock prevents 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 SQLite only while serve is running. If the daemon stops, the WhatsApp connection closes. On the next start, whatsmeow emits events.HistorySync events 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, the request_sync tool triggers a per-chat backfill on demand.
Data storage
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.
Data flow
- The client sends a JSON-RPC
tools/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.
Running the daemon
The daemon is designed to run independently of any MCP client. Three supported lifecycle models:
macOS — launchd. Template at docs/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 at docs/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, drop docs/hooks/setup.sh into your project's .claude/hooks/ and configure settings.json to invoke it. The hook is idempotent — safe to run alongside launchd/systemd.
Manual. ./bin/whatsapp-mcp serve -addr 127.0.0.1:8765 in any terminal. Ctrl-C to stop.
Docker. A multi-stage Dockerfile builds the binary and ships it on debian:bookworm-slim with ffmpeg and CA certs. ENTRYPOINT bakes in -store /home/app/store; CMD defaults to serve and is a normal Docker command override (docker run whatsapp-mcp smoke, ... login, ... serve -addr ...). Persist /home/app/store or you lose the paired session on every restart:
docker build -t whatsapp-mcp --build-arg VERSION=$(git describe --tags --always) .
Pair once, before starting the long-running daemon — login and serve both take an exclusive lock on the store, so running login via docker exec against an already-running serve container fails with another whatsapp-mcp instance is already running. A one-off container sharing the same volume avoids that: no serve is running yet, so there's nothing to contend with, and the QR renders straight to your terminal with no browser or auth header involved.
docker run --rm -it -v whatsapp-mcp-store:/home/app/store whatsapp-mcp login
Then start the daemon proper:
docker run -d --name whatsapp-mcp -v whatsapp-mcp-store:/home/app/store whatsapp-mcp
The image binds 127.0.0.1:8765 inside the container by default, same as the binary — a plain -p 8765:8765 publish won't reach it, since
Truncated for display — read the full file on GitHub.
Related Skills
claude-mem
96.6kPersistent Context Across Sessions for Every Agent – Captures everything your agent does during sessions, compresses it with AI, and injects relevant context back into future sessions. Works with Claude Code, OpenClaw, Codex, Gemini, Hermes, Copilot, OpenCode + More
Agent-Reach
91.8kGive your AI agent eyes to see the entire internet. Read & search Twitter, Reddit, YouTube, GitHub, Bilibili, XiaoHongShu — one CLI, zero API fees.
headroom
74.5kCompress tool outputs, logs, files, and RAG chunks before they reach the LLM. 20% fewer tokens for coding agents, 60-95% fewer tokens for JSON, same answers. Library, proxy, MCP server.
CowAgent
47.2kOpen-source personal AI assistant & Agent Harness. Plans tasks, runs tools and skills, self-evolves with memory and knowledge. Multi-agent, multi-model, multi-channel. Lightweight, extensible, one-line install.
Languages
Trust signals
From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.
