Skip to main content
Glama
eusoubrasileiro

whatsapp-mcp

WhatsApp MCP Server

CI

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.

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.

Related MCP server: whatsapp-mcp

Features

  • HTTP MCP endpoint (httpStream transport) — connect from anywhere, share the session across multiple clients without Baileys fighting for the socket

  • Bearer-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 reactive monitoring (cursor delta, long-poll, a follow_chat WebSocket stream) and 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

flowchart LR
  subgraph clients[MCP clients]
    CC[Claude Code / Desktop / Cursor / custom agents]
  end
  PB[Phone browser]
  CC -- "https + Bearer" --> T[Traefik]
  PB -- "https (public)" --> T
  T -- ":39001" --> MCP[FastMCP httpStream]
  T -- ":39002" --> QR[QR page]
  subgraph container[whatsapp-mcp container]
    MCP
    QR
    BA[Baileys]
  end
  MCP --> BA
  QR --> BA
  BA -- "WA Web API" --> WA[(WhatsApp servers)]
  container -- "outbound POST" --> NT[ntfy.sh] -- push --> PH[Your phone]

One container exposes two HTTP servers on different ports. Traefik terminates TLS (Let's Encrypt) and routes by hostname.

Quick start for MCP clients

A deployment exposes two hostnames of your choosing (example.com below — substitute your own):

  • https://mcp.example.com/mcp — MCP endpoint, requires Authorization: Bearer <MCP_AUTH_TOKEN>

  • https://wa.example.com/ — QR web page

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 reference: docs/tools.md.

Category

Tools

Connection / Auth

get_connection_status, logout

Contacts

search_contacts, list_contacts

Messages

list_messages, get_messages_today, search_messages, get_message_context

Reactive monitoring

get_new_messages (cursor delta), wait_for_messages (bounded long-poll for a reply expected within minutes), follow_chat (WebSocket presence stream — woken per inbound message while doing other work; see docs/agent-presence-stream-recipe.md)

Chats

list_chats, get_chat

Groups

get_group_info

Sending

send_message, send_file

Actions

react_to_message, delete_message, mark_chat_read

Media

download_media (audio → transcription by default; image → opt-in description)

Webhooks

register_webhook, deregister_webhook, list_webhooks (real-time inbound push to a reactive agent; allow-listed chats; HMAC-signed)

Deployment

Full deploy / update / rotate-secrets / troubleshoot runbook: deploy/README.md. The production compose file is deploy/docker-compose.yaml; hostnames and the send policy come from deploy/.env (template: deploy/.env.example).

This repo depends on its sibling baileys-client (link:../baileys-client), so clone both side by side. Build recipe (BuildKit):

git clone https://github.com/eusoubrasileiro/baileys-client.git
git clone https://github.com/eusoubrasileiro/whatsapp-mcp.git
cd whatsapp-mcp
DOCKER_BUILDKIT=1 docker build \
  --build-context baileys=../baileys-client \
  -t whatsapp-mcp:latest .

Local development

For development without Docker, keep the default stdio transport. Build the sibling baileys-client checkout first (see Deployment):

(cd ../baileys-client && pnpm install && pnpm build)
pnpm install
pnpm test       # vitest — git hooks enforce it on every commit
pnpm typecheck
pnpm start      # node --experimental-strip-types src/main.ts

Requires Node.js 24 (.nvmrc; engines asks for >= 24) 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, and docs/development.md for tests, hooks and conventions.

Environment variables

Full table: docs/configuration.md. Highlights:

Variable

Purpose

MCP_AUTH_TOKEN

Bearer token required by the HTTP MCP endpoint (mandatory in production)

NTFY_TOPIC_URL

Unset = no push notifications; set to enable

EXPECTED_WA_NUMBER

Prefix allowed to pair; wrong scan → auto-logout + purge (strongly recommended whenever the QR page is public)

WHATSAPP_MCP_DATA_DIR

Base dir for auth_info/, data/, and logs (defaults to ., Docker uses /data)

OPENROUTER_API_KEY

Powers download_media audio transcription (Whisper) and image description (vision model)

AUDIO_PROVIDER

Transcription route: openrouter (default) | groq | openai. Rollback lanes only — the route is chosen by this var, never by which key happens to be set

VISION_MODEL

OpenRouter model for image description (default openai/gpt-6-luna)

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 in the same compose stack, behind Traefik at https://mcp.example.com/media/<key>. The download_media tool returns an MCP resource_link pointing at that URL (publicly fetchable, no Bearer needed) plus inline imageContent/audioContent on the first call. Cache hits return the URL only.

  • Audio → text: by default, download_media on 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. Pass transcribe: false to get raw audio bytes instead. Requires OPENROUTER_API_KEY. Groq and OpenAI remain as rollback routes via AUDIO_PROVIDER (each needs its own key).

  • Image → text: opt-in via download_media({ ..., describe: true }). Sends the image to an OpenRouter vision model (VISION_MODEL, default openai/gpt-6-luna); response wrapped in an <image_description> XML block. Requires OPENROUTER_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.

Credits

  • Conceptual origin: lharries/whatsapp-mcp (Go + Python).

  • Fork history: started from jlucaso1/whatsapp-mcp-ts, since heavily rewritten (HTTP transport, send guards, media plane, reactive monitoring).

  • Maintained by eusoubrasileiro.

License

MIT — see LICENSE, which also carries the ISC notice for the portions derived from jlucaso1/whatsapp-mcp-ts.

Not affiliated with WhatsApp or Meta. Baileys is an unofficial WhatsApp Web client; automating a WhatsApp account can get it restricted — read docs/account-restrictions.md before sending from a number you care about.

Related MCP Connectors

  • WhatsMCP connects Claude and other MCP-compatible AI agents directly to WhatsApp. Send and receive text, images, documents, and voice notes; manage groups (create, add/remove members, promote admins); look up contacts and profiles; follow channels; and read call and message history — all through a standard MCP interface. For voice use cases, WhatsMCP offers SIP-based calling plans (inbound-only, or full inbound/outbound) so AI voice agents can answer and place WhatsApp calls, plus low-latency WebSocket integrations with voice agent providers like ElevenLabs. Multiple WhatsApp accounts can be paired and managed per workspace, with webhook support for real-time inbound message delivery to your own infrastructure.

  • Drive WhatsApp from any MCP client: pair devices, send text and media, manage contacts and groups.

  • Your own WhatsApp as an MCP server: read, search and send from any MCP client.

  • WhatsApp (Web + Business API), SMS, contacts, and call records via 2Chat's MCP server.

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables 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.
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables sending WhatsApp messages from MCP clients using a personal WhatsApp account via WebSocket protocol, without needing the Business API or browser automation.
    36 npm
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    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.
    6 npm
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables connecting a personal WhatsApp number to any MCP client, providing tools to send, search, and manage WhatsApp messages, with an optional auto-reply feature.
    23 PyPI
    4
    MIT