whatsapp-mcp
by nelcolon
README.md
# whatsapp-mcp
An MCP server that gives Claude read, search, and reply access to your **personal**
WhatsApp account, by linking itself as an extra device the same way WhatsApp Web does.
- **Read** — transcripts of any chat or group, paged backwards through history
- **Search** — full-text across everything stored, diacritic-insensitive
- **Context** — pull the messages surrounding any hit
- **Reply** — send text, quote a specific message, send files, mark chats read
- **Media** — download attachments to local files so Claude can look at them
- **Link** — pair by scanning a QR, or by phone-number code for headless/SSH setups
## How it fits together
```
Claude Code ──stdio/MCP──▶ src/mcp.js ──HTTP──▶ src/bridge.js ──▶ WhatsApp
│ │
└──── data/whatsapp.db ┘
```
Two processes, on purpose. The bridge is a long-lived daemon that owns the WhatsApp
websocket and mirrors every message into SQLite. The MCP server is short-lived — it
starts and stops with your MCP client — and answers reads straight from SQLite, so
searching and reading history keep working even when the bridge is down.
## Requirements
Node 22.5+ (uses the built-in `node:sqlite`, so there is nothing to compile).
## Setup
```bash
npm install
npm run bridge # prints a QR code
```
On your phone: **WhatsApp → Settings → Linked devices → Link a device**, scan the QR.
### Link with a phone number instead of the QR
Handy when you can't point the phone's camera at the terminal (headless box, SSH):
```bash
node src/bridge.js --phone 18091234567 # your full number, country code, digits only
```
Instead of a QR the bridge prints an 8-character pairing code. On the phone:
**WhatsApp → Settings → Linked devices → Link a device → Link with phone number
instead**, then type the code. (The number can also come from `WA_MCP_PAIR_PHONE`.)
Either way, the bridge then backfills whatever history WhatsApp hands a newly linked
device and keeps running. Leave it running. The phone number is only used for this
first link — once the device is registered it's ignored.
Register the MCP server with Claude Code:
```bash
claude mcp add whatsapp -- node /absolute/path/to/whatsapp-mcp/src/mcp.js
```
Then ask things like *"what did Ana send me about the inverter quote?"* or
*"summarise the Projeto Solar group since Monday and draft a reply."*
## Tools
| Tool | What it does |
|---|---|
| `whatsapp_status` | Connection state, stored message counts, history range |
| `list_chats` | Chats by recency, filterable by name and dm/group |
| `read_chat` | Transcript of one chat, pageable with `before`/`after` |
| `search_messages` | Full-text search, optionally scoped to a chat or sender |
| `get_message_context` | Messages surrounding a given message id |
| `list_contacts` | Contact lookup by name or number |
| `send_message` | Send text, optionally quoting a message |
| `send_file` | Send an image, video, audio file, or document |
| `download_media` | Fetch an attachment to a local path |
| `mark_read` | Clear a chat's unread badge |
Chats are referenced by **name, phone number, or JID**. A name that matches more than
one chat is rejected with the list of candidates rather than guessed at — the one
irreversible mistake here is sending a message to the wrong person.
## Configuration
Copy `.env.example` to `.env`. Everything is optional. Notable knobs:
- `WA_MCP_READONLY=1` — the four writing tools are never registered. Claude cannot
send anything; useful if you only want it reading context.
- `WA_MCP_BLOCKLIST=Therapist,5511999998888` — chats matching these substrings are
never written to the database at all.
- `WA_MCP_FULL_HISTORY=1` — request the largest history dump WhatsApp will give.
- `WA_MCP_DATA` — move the data directory somewhere else.
## Sharing this
It's self-contained and has no hardcoded paths, so it clones and runs. What must
**not** be shared is `data/` — `data/auth/` holds credentials that are equivalent to
a logged-in session on your account, and `data/whatsapp.db` is your message history in
plaintext. Both are gitignored. If you publish this, publish the code only.
## Things worth knowing
**This uses an unofficial client.** Baileys is a reverse-engineered implementation of
the WhatsApp Web multi-device protocol. It is against WhatsApp's terms of service, and
accounts do occasionally get banned — most often for bulk or automated sending to
people who did not message first. Reading your own chats and replying at human volume
is the low-risk end of this; blasting messages is the high-risk end. If you ever need
this for a business, use the official WhatsApp Business Cloud API instead.
**History is limited.** WhatsApp only pushes a window of recent history to a newly
linked device — typically weeks to months, not years. Everything from link time
forward accumulates in full, so the database gets more useful the longer it runs.
**The bridge must be running to send.** Reads work offline from SQLite; sends,
downloads, and read receipts need the daemon. Run it under systemd or `pm2` if you
want it always up.
**Your message history ends up in a model's context.** That is the entire point, but
it is worth saying out loud: anything Claude reads here leaves your machine. The
blocklist and read-only mode exist for the chats you would rather it never touch.
## License
MIT
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues