Skip to main content
Glama
nelcolon

whatsapp-mcp

by nelcolon

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

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

npm install
npm run bridge          # prints a QR code

On your phone: WhatsApp → Settings → Linked devices → Link a device, scan the QR. The bridge then backfills whatever history WhatsApp hands a newly linked device and keeps running. Leave it running.

Register the MCP server with Claude Code:

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