whats-mcp

whats-mcp

MCP server that turns WhatsApp into agent-callable tools, enabling search contacts, send/receive messages, read chats, handle media, and monitor calls via the WhatsApp Web multi-device protocol.

Category
Visit Server

README

whats-mcp

MCP server that turns your WhatsApp into agent-callable tools.

Link your WhatsApp account once by scanning a QR code (the official "Linked Devices" flow — your phone keeps working normally), and the server keeps the session alive across restarts. Then any MCP-capable agent (Claude Desktop, Hermes, Cursor, …) can search your contacts, send messages, read chats, read unread messages, mark things read, send media, and monitor incoming calls.

Built on Baileys 6.7.24 (the WhatsApp Web multi-device protocol) — a pure Node.js implementation. No browser, no Puppeteer, no Chromium.

⚠️ Unofficial client disclaimer: this uses WhatsApp's Web protocol via an unofficial library. WhatsApp/Meta can ban accounts that abuse unofficial clients. Use it for your own account, at normal human volumes, and avoid bulk/spammy automation. No warranty — use at your own risk.


Features

Area Tools
Linking whatsapp_get_qr (scan to link), whatsapp_get_pairing_code (link without QR), whatsapp_get_status, whatsapp_logout
Contacts whatsapp_search_contacts (by name or number)
Sending whatsapp_send_message (text / reply), whatsapp_send_media (image, audio/voice note, document)
Reading whatsapp_read_chat (recent messages), whatsapp_read_unread (unread chats + messages), whatsapp_mark_read (one chat), whatsapp_list_chats, whatsapp_mark_all_read (batch read receipts, clears phone badges)
Calls whatsapp_recent_calls, whatsapp_reject_call, whatsapp_call (honest explainer — see Limitations)

Key properties:

  • Persistent session — auth lives in auth_info/ (git-ignored). Restart the server → reconnects with no re-scan.
  • Persistent indexes — contacts (contacts.json) and unread messages (unread.json) are saved to the auth dir, so a daemon restart loses nothing.
  • Auto-reconnect — exponential backoff on drops; only a logout stops it.
  • No browser — pure WebSocket protocol implementation.
  • Stdio-safe — QR codes are returned as tool results (raw + ASCII), never printed to stdout; all logs go to stderr so the JSON-RPC stream stays clean.

Quick start

Full step-by-step install guide for Windows, macOS and Linux (Node setup, QR linking, 24/7 service for each OS): docs/INSTALL.md.

# 1. install
npm install

# 2. run the server (or: npm start)
node src/index.js

# 3. ask your MCP client to link the device:
#    call whatsapp_get_qr → scan the QR in WhatsApp → Settings →
#    Linked devices → Link a device
#    (or call whatsapp_get_pairing_code with your number and type the code)

The server connects to WhatsApp immediately on boot. While unlinked it keeps a fresh QR ready. Once linked, creds.json is persisted — every later start reconnects automatically.

Registering in an MCP client

Standard mcpServers config (Claude Desktop / Cursor / etc.):

{
  "mcpServers": {
    "whatsapp": {
      "command": "node",
      "args": ["/absolute/path/to/whats-mcp/src/index.js"],
      "env": {
        "WHATSAPP_AUTH_DIR": "/absolute/path/to/whats-mcp/auth_info"
      }
    }
  }
}

Hermes Agent

Connect Hermes to the daemon over HTTP (recommended — the systemd service owns the WhatsApp connection, see below):

hermes config set mcp_servers.whatsapp.url http://127.0.0.1:8787/mcp

or spawn the server per Hermes session (stdio):

hermes config set mcp_servers.whatsapp.command node
hermes config set mcp_servers.whatsapp.args '["/absolute/path/to/whats-mcp/src/index.js"]'
hermes config set mcp_servers.whatsapp.env.WHATSAPP_AUTH_DIR /absolute/path/to/whats-mcp/auth_info

Then restart Hermes — tools appear as mcp_whatsapp_whatsapp_get_qr, etc. (One instance per auth dir: either the daemon or a spawned child, never both — the single-instance lock enforces this.)

24/7 daemon (systemd)

Keep the WhatsApp connection alive across reboots and logins:

# 1. install the unit (see ~/.config/systemd/user/whats-mcp.service in this repo's setup)
systemctl --user daemon-reload
systemctl --user enable --now whats-mcp
loginctl enable-linger "$USER"   # start at boot, even before login

The daemon serves MCP on http://127.0.0.1:8787/mcp (plus GET /health), logs to journald (journalctl --user -u whats-mcp -f), and never unlinks the device on shutdown. Contacts and unread-message state are persisted inside the auth dir, so restarts lose nothing.

Environment variables

Variable Default Purpose
WHATSAPP_AUTH_DIR ./auth_info Where the linked-device credentials live (keep private!)
WHATSAPP_LOG_LEVEL warn silent | error | warn | info | debug — always to stderr
WHATSAPP_MARK_ONLINE true false = don't mark online (phone keeps receiving its own push notifications)
WHATSAPP_MCP_PORT (unset) Set to run as a daemon: StreamableHTTP on 127.0.0.1:<port>/mcp instead of stdio
WHATSAPP_CONNECT_TIMEOUT 30 Seconds send/read tools wait for the connection to be open

Tool reference

whatsapp_get_qr

Returns the current linking QR as a raw string and an ASCII rendering, plus seconds until it rotates. Scan with WhatsApp → Settings → Linked devices → Link a device. QR rotates every ~20–60s — scan promptly.

whatsapp_get_pairing_code

phone (digits with country code, e.g. 919876543210) → returns an 8-digit code. On the phone: Link a device → Link with phone number instead, then enter the code. Fails gracefully if the account doesn't support pairing.

whatsapp_get_status

Connection state, linked flag, QR availability, contact/chat/unread counts, last disconnect reason. Use this first whenever something seems off.

whatsapp_search_contacts

query (name substring or number digits, empty = list all) + limit → matches with jid, name, notify, number. The jid can be passed to any tool that takes a contact.

whatsapp_send_message

contact + text, optional quoted_message_id (reply). contact is resolved in order: full JID → phone number (verified via onWhatsApp) → saved contact name.

whatsapp_send_media

contact + media_type (image | audio | document) + source (local path or http(s) URL), optional caption, file_name, as_voice_note.

whatsapp_read_chat

contact + limit → most recent messages seen for that chat (since server start), plus its unread count.

whatsapp_read_unread

per_chat + max_chats → chats with unreadCount > 0, sorted by unread count, with the newest incoming messages for each.

whatsapp_mark_read

contact → sends read receipts for that chat's tracked messages (respects the account's read-receipt privacy setting).

whatsapp_recent_calls / whatsapp_reject_call

Incoming call events (offer/ringing/accept/reject/timeout, with video flag) since server start; reject a live call by id.

whatsapp_logout

Removes the linked device from your account (like tapping "Log out" on the phone). The auth folder is kept; scan a fresh QR to re-link.

Limitations (read this — it's honest)

  • Voice/video calls cannot be placed. This is a hard WhatsApp protocol limitation: call media flows over a separate signaling path that the linked-device (Web) protocol does not expose. Verified against the Baileys 6.7.24 API surface — there is no send-side call content; missed-call "bubbles" are inbound-only server constructs. whatsapp_call exists to explain exactly this. What IS possible: monitor incoming calls (whatsapp_recent_calls) and reject them (whatsapp_reject_call). (Future: Baileys v7 adds createCallLink — sending a tappable call link — tracked in docs/ARCHITECTURE.md.)
  • History is event-based. Chats/messages received after the server connects are available immediately; older history arrives via WhatsApp's messaging-history.set sync (contacts + chat metadata, unread counts).
  • Message content: text, captions and file names are extracted; media blobs are not downloaded (yet).
  • 4 linked devices max (phone + 3). Scanning a 5th bumps the oldest.
  • The phone must keep WhatsApp installed; uninstalling or renaming the number kills the linked session.

Project layout

whats-mcp/
├── src/
│   ├── index.js      # entry: boot client, expose over MCP stdio
│   ├── server.js     # MCP tool definitions (zod schemas)
│   └── whatsapp.js   # Baileys wrapper: QR, auth, reconnect, indexes
├── scripts/
│   └── smoke-test.mjs # stdio end-to-end test (npm run smoke)
├── docs/
│   ├── ARCHITECTURE.md # design decisions + upgrade paths
│   └── AGENTS.md       # conventions for agent contributors
├── .env.example
├── package.json
└── LICENSE (MIT)

Testing

npm run smoke   # spawns the real server over stdio, asserts handshake+tools

License

MIT — see LICENSE. Baileys is MIT; the MCP SDK is MIT.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured