whatsapp-mcp
Provides tools for interacting with WhatsApp, including sending and receiving messages, managing chats and contacts, reacting to messages, and downloading media, enabling agents to monitor and participate in conversations.
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., "@whatsapp-mcpsend a WhatsApp message to Mom saying I'll be home by 6"
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.
WhatsApp MCP Server
WhatsApp as an MCP server. Runs as a long-lived Docker daemon, accessed over HTTPS with Bearer auth, and pushes ntfy notifications when your session needs attention (QR expired, connection dropped). Built on Baileys via the @amiticia/baileys-client wrapper, which is vendored in this repository as a workspace package under packages/baileys-client/ — there is no private dependency to resolve.
▶ Start here:
src/stream/follow.ts— the smallest file that shows what this server is actually for: turning an inbound WhatsApp chat into a stream an agent can be woken by, instead of a mailbox it has to poll.
Look at first
src/stream/follow.ts— thefollow_chattool. An agent that must "be present" in a conversation for hours cannot hold a turn open and cannot afford to poll; this hands it a stream URL its harness subscribes to, and the agent is woken per message. The three-way choice between a bounded block, a session-length stream and a deployment-length webhook is the whole design question for a reactive messaging tool, and this file is where it is answered.docs/spec-agent-presence-stream.md— the spec behind that file: why presence is a distinct lifetime from request/response, and what the stream must guarantee so a woken agent never silently drops a message.docs/account-restrictions.md— the unglamorous one, and the one worth reading. An unofficial WhatsApp client can get a real account banned. This documents the constraints that shaped the send path — pacing, typing simulation, a send blocklist, a cold-contact guard — which is whysrc/send-pacer.ts,src/send-guard.ts,src/send-blocklist.tsandsrc/cold-contact.tsexist at all.
Related MCP server: WhatsApp MCP Server (Docker Edition)
Who this is for
You want your personal WhatsApp account reachable as a set of tools from Claude Code, Claude Desktop, Cursor, or any custom MCP/HTTP client — from any machine — with the WhatsApp connection surviving client restarts, multiple clients sharing one socket, and a push telling you on your phone when you need to re-scan a QR.
Features
HTTP MCP endpoint (
httpStreamtransport) — connect from anywhere, share the session across multiple clients without Baileys fighting for the socketBearer-token auth on the MCP endpoint
Public QR web page (protected by paired-number check) — tap the ntfy push and scan directly from your phone browser
ntfy push on: first QR after disconnect, every 2min while still waiting, connection drop, reconnect after drop, and unexpected pairings
Bad-pairing protection — if someone else scans the public QR, the app auto-logs out and purges credentials (
EXPECTED_WA_NUMBER)23 MCP tools — search contacts/messages, list chats, send text/media, react, delete, mark read, download media, plus webhook subscriptions for real-time inbound push (see table below)
Persistent SQLite (chats/messages/contacts) and Baileys multi-file auth stored in a Docker volume
Architecture
https (Bearer)
MCP clients ───────────────────▶ Traefik ──▶ :39001 (FastMCP httpStream)
(Claude Code, Desktop, │
Cursor, custom agents) │
▼
https (public) whatsapp-mcp
Phone browser ───────────────▶ Traefik ──▶ :39002 (QR page)
│
▼
Baileys
│ WA Web API
▼
WhatsApp servers
outbound only ▲
│
POST
│
ntfy.sh
│ push
▼
Your phoneOne container exposes two HTTP servers on different ports. Traefik terminates TLS (Let's Encrypt) and routes by hostname.
Quick start for MCP clients
The canonical deployment exposes:
https://mcp.example.com/mcp— MCP endpoint, requiresAuthorization: Bearer <MCP_AUTH_TOKEN>https://wa.example.com/— QR web page
If you run your own instance, replace hostnames accordingly.
Claude Code
Edit ~/.claude.json, in the top-level mcpServers object:
"whatsapp": {
"type": "http",
"url": "https://mcp.example.com/mcp",
"headers": {
"Authorization": "Bearer ${MCP_AUTH_TOKEN}"
}
}Export MCP_AUTH_TOKEN in your shell (or put the token literally — ~/.claude.json is 0600). Restart Claude Code, run /mcp — should show whatsapp: ✓ Connected.
Claude Desktop
~/.config/Claude/claude_desktop_config.json (Linux) / ~/Library/Application Support/Claude/claude_desktop_config.json (macOS):
{
"mcpServers": {
"whatsapp": {
"type": "http",
"url": "https://mcp.example.com/mcp",
"headers": { "Authorization": "Bearer your-token-here" }
}
}
}Cursor
~/.cursor/mcp.json — same shape as Claude Desktop above.
Other clients / custom code
See examples/ for a raw HTTPS JSON-RPC transcript (curl), a Python client, and a custom TypeScript agent using StreamableHTTPClientTransport.
MCP tools
The server exposes 23 tools. Full details are in CLAUDE.md.
Category | Tools |
Connection / Auth |
|
Contacts |
|
Messages |
|
Reactive monitoring |
|
Chats |
|
Groups |
|
Sending |
|
Actions |
|
Media |
|
Webhooks |
|
Deployment
deploy/README.md describes the reference topology: the two
HTTP servers, the four Traefik routes, the volumes and the auth surface.
What is deliberately not here. The host-specific operations runbook — SSH
targets, DNS records, backup and restore procedures, credential rotation — is not
part of this public repository, and neither is the private container registry the
image is normally published to. deploy/docker-compose.yaml is a sanitised
topology reference, not a deployable manifest for anyone else's host.
The image builds from this repository alone; packages/baileys-client is a
workspace package, so no sibling checkout and no build context are needed:
docker build -t whatsapp-mcp:latest .Local development
For development without Docker, keep the default stdio transport:
pnpm install
pnpm test # vitest — 687 pass, 4 skipped; must stay green before commits (extreme TDD)
pnpm typecheck
pnpm start # node --experimental-strip-types src/main.tsRequires Node.js >= 23.10.0 for --experimental-strip-types and native better-sqlite3.
For local HTTP mode (same as production minus Traefik):
MCP_TRANSPORT=httpstream MCP_AUTH_TOKEN=dev pnpm start
# then: curl -H 'Authorization: Bearer dev' http://127.0.0.1:39001/mcp ...See scripts/smoke-test.sh for the auth matrix.
Environment variables
See the full table in CLAUDE.md#environment-variables. Highlights:
Variable | Purpose |
| Bearer token required by the HTTP MCP endpoint (mandatory in production) |
| Unset = no push notifications; set to enable |
| Prefix allowed to pair; wrong scan → auto-logout + purge (strongly recommended when |
| Base dir for |
| Whisper provider for |
| Transcription route: |
| Required for |
Data storage & privacy
Credentials:
WHATSAPP_MCP_DATA_DIR/auth_info/(Baileys multi-file auth state)Messages / chats / contacts:
WHATSAPP_MCP_DATA_DIR/data/whatsapp.db(SQLite via Drizzle +better-sqlite3)Media: served from a RustFS sidecar on the same VPS, behind Traefik at
https://mcp.example.com/media/<key>. Thedownload_mediatool returns an MCPresource_linkpointing at that URL (publicly fetchable, no Bearer needed) plus inlineimageContent/audioContenton the first call. Cache hits return the URL only.Audio → text: by default,
download_mediaon an audio/ptt message transcribes via OpenRouter Whisper (openai/whisper-large-v3) after preprocessing to 16 kHz mono FLAC. The response is wrapped in an<transcription>XML block. Passtranscribe: falseto get raw audio bytes instead. RequiresOPENROUTER_API_KEY. Groq and OpenAI remain as rollback routes viaAUDIO_PROVIDER, but both accounts are scheduled for closure — once they are, those routes stop working and this line should say so.Image → text: opt-in via
download_media({ ..., describe: true }). Sends bytes to Gemini 2.5 Flash; response wrapped in an<image_description>XML block. RequiresGEMINI_API_KEY.Logs:
WHATSAPP_MCP_DATA_DIR/{wa,mcp}-logs.txt(pino JSON lines)
Everything stays on the VPS (Docker bind mount in production, filesystem in dev). Data leaves the VPS only when an MCP client explicitly invokes a tool.
All data directories are .gitignored. Treat them as sensitive — anyone with auth_info/ can impersonate your WhatsApp session.
About this public export
This repository is published as a single squashed commit rather than with its development history, and some content was removed rather than redacted:
No session credentials, no message database, no logs.
auth_info/,data/whatsapp.dband the*-logs.txtfiles were never in the tree or in any commit, and remain gitignored. Anyone holdingauth_info/can impersonate the WhatsApp session it belongs to.No host-specific deployment runbook — see the Deployment section above.
Phone numbers, group ids and
@lididentifiers in tests, fixtures and examples are synthetic placeholders. They keep the real wire format so the identifier-canonicalisation tests still parse them, but they identify nobody.deploy/.env.exampleis a template: every variable is empty, with theopenssl randcommand that generates it. No secret material.
Credits
Conceptual origin: lharries/whatsapp-mcp (Go + Python).
Fork history: started from
jlucaso1/whatsapp-mcp-ts, then heavily rewritten.
License
MIT — see LICENSE, matching package.json.
This server cannot be deployed
Maintenance
Related MCP Connectors
Drive WhatsApp from any MCP client: pair devices, send text and media, manage contacts and groups.
WhatsApp (Web + Business API), SMS, contacts, and call records via 2Chat's MCP server.
Unified messaging MCP server: WhatsApp, Instagram, Telegram, SMS, Messenger & email support inbox
Give your AI agents a real WhatsApp number to send and receive messages.
Related MCP Servers
- AlicenseBqualityDmaintenanceEnables sending messages, images, documents and more on WhatsApp directly from any MCP-compatible AI, with tools for chat management, groups, and webhooks.371MIT
- FlicenseNot gradedqualityDmaintenanceEnables AI clients to interact with WhatsApp via MCP tools for searching contacts, sending/receiving messages, and managing chats, running in a Docker container with HTTP/SSE transport.-
- AlicenseNot gradedqualityBmaintenanceEnables sending WhatsApp messages from MCP clients using a personal WhatsApp account via WebSocket protocol, without needing the Business API or browser automation.13 npmMIT
- AlicenseNot gradedqualityBmaintenanceA self-hosted WhatsApp gateway that exposes messaging capabilities via MCP, allowing AI agents to send, receive, and manage WhatsApp messages through a single-command setup with SQLite storage.1MIT