Skip to main content
Glama
WhatsApp MCP Server

WhatsApp MCP Server

by cascodigital

whatsapp-mcp-server

A local WhatsApp message collector plus a Model Context Protocol (MCP) server that lets LLM clients read and send messages on your own WhatsApp account.

License Node.js Status

Overview

WhatsApp has no official API for reading a personal account's message history, and its built-in search is unavailable to AI assistants. This project links a companion device with Baileys, stores every incoming message in a local SQLite database, and exposes that database to MCP clients (Claude, Codex, and others) over stdio. Clients can also queue outgoing text or image messages, sent immediately or at a scheduled time. Messages stay on your machine: there is no cloud component and no HTTP listener.

This links a real WhatsApp account as a companion device. Use it only with an account you own and respect the privacy of everyone in your chats. It is not affiliated with or endorsed by WhatsApp/Meta.

Sending safety: whatsapp_send_message sends real messages from your personal WhatsApp account, to real people, and they cannot be unsent by this server. Configure your MCP client to require explicit user confirmation (recipient and content) before every call to this tool, and do not auto-approve it.

Related MCP server: whatsapp-profiles

Features

  • Captures new messages live from the moment the device is paired (full history sync is disabled).

  • Keeps the text of messages that are deleted after capture and flags them as revoked.

  • Tracks direct and group chats, push names, contacts, group subjects, attachments and links.

  • Stores everything in a single SQLite file that is easy to inspect, back up or query directly.

  • Exposes 12 MCP tools: 10 read-only tools (status, chat listing and lookup, recent messages, text search, date ranges, attachments, links, deleted messages, per-chat summaries) plus sending and outbox status.

  • Sends text, or a JPEG/PNG/WebP image (up to 10 MiB) with an optional caption, immediately or scheduled for a later time, through an outbox queue dispatched by the collector.

  • Self-healing collector: exits on disconnect (except logout) or when no connection is established within 120 s, so the supervisor (Docker restart: unless-stopped, systemd) restarts it cleanly; a heartbeat file drives the Docker healthcheck.

  • Imports WhatsApp .txt chat exports into the same database.

  • Runs natively (Node.js, optionally under tmux or systemd) or in Docker.

How it works

Two processes share one SQLite database:

 WhatsApp servers
       ^  |
 sends |  | receives
       |  v
 src/collector.js  (Baileys linked device, long-running)
       |  writes messages, reads/updates outbox
       v
 messages.sqlite  <-- src/import_whatsapp_export.js (one-shot .txt import)
       ^  reads messages, inserts into outbox
       |
 src/index.js      (MCP server over stdio, started on demand by the MCP client)

Process

File

Role

collector

src/collector.js

Stays connected to WhatsApp, writes messages to the DB and dispatches the outbox

mcp

src/index.js

Stdio MCP server; queries the DB and enqueues outgoing messages

importer

src/import_whatsapp_export.js

Parses exported .txt chats and inserts them

Design notes:

  • The database uses Node's built-in node:sqlite module, so there is no native addon to compile.

  • Deleted messages are detected both from protocolMessage REVOKE events and from revoke stub updates. The stored row is marked isRevoked=true with revokedAt, revokedBy, revokedByMe and revokeSourceMessageId; the original text is kept.

  • Imported messages get synthetic chat IDs (import:<hash>) and source=import, so they never mix with live-captured chats.

  • The MCP server never talks to WhatsApp directly. whatsapp_send_message inserts a row into the outbox table; the collector polls it every second and sends due messages (see Sending messages).

  • The collector identifies itself as Browsers.macOS('Desktop'), so the linked device appears on the phone as macOS.

By default all runtime data lives under ~/.local/share/whatsapp-mcp/:

~/.local/share/whatsapp-mcp/
├── auth/              # Baileys pairing credentials
├── messages.sqlite    # message database
├── collector.log
├── collector.pid
└── collector.connected  # heartbeat, touched every 30 s while connected

Requirements

  • Node.js 22.5 or later (for node:sqlite), or Docker with Compose

  • A WhatsApp account on a phone, for pairing

  • tmux (optional, for bin/start-collector.sh)

  • python3 (only for the bin/mcp-*.sh test helpers)

Quick start

Native:

  1. Install dependencies:

    npm install
  2. Start the collector in the foreground to display the pairing QR code:

    npm run collector
  3. On the phone, open Settings > Linked devices > Link a device and scan the QR code.

  4. Check the result:

    npm run status

    Output includes auth=ready and the database path once pairing succeeded.

Docker:

  1. Build and start the collector:

    docker compose up -d --build collector
    docker compose logs -f collector
  2. When the log shows Scan the QR code in WhatsApp > Linked devices., scan it on the phone.

  3. List the MCP tools through the container:

    bash bin/mcp-run-list-tools.sh

With Docker, data is persisted in ./data next to compose.yml (./data/auth/, ./data/messages.sqlite, ./data/collector.pid).

Configuration

All configuration is through environment variables.

Variable / key

Required

Default

Description

WHATSAPP_MCP_HOME

No

~/.local/share/whatsapp-mcp

Base directory for auth, database, log and pid file (/data in Docker)

WHATSAPP_BAILEYS_LOG_LEVEL

No

warn

Baileys (pino) log level

WHATSAPP_MCP_TMUX_SESSION

No

whatsapp-mcp-collector

tmux session used by the start/stop/status scripts

WHATSAPP_MCP_SYSTEMD_SERVICE

No

whatsapp-mcp-collector.service

systemd user unit inspected by bin/status.sh and the status tool

WHATSAPP_MCP_APP_DIR

No

repository root

Directory bin/start-collector.sh runs the collector from

WHATSAPP_EXPORT_OWNER_NAME

No

empty

Sender name in .txt exports to mark as fromMe on import

WHATSAPP_DEFAULT_COUNTRY_CODE

No

55

Prefix added to bare 10/11-digit local numbers when sending; empty disables it

WHATSAPP_MCP_REMOTE_HOST

For remote

user@your-docker-host

SSH target used by bin/mcp-remote-stdio.sh

WHATSAPP_MCP_REMOTE_STACK_DIR

For remote

/opt/whatsapp-mcp

Compose stack directory on the remote host

Usage

MCP client configuration

The server speaks stdio, not HTTP.

Native:

{
  "command": "node",
  "args": ["src/index.js"],
  "cwd": "/path/to/whatsapp-mcp-server"
}

Docker (uses the mcp service in the manual profile):

docker compose run --rm -T mcp

Remote Docker host over SSH:

WHATSAPP_MCP_REMOTE_HOST=user@your-docker-host \
WHATSAPP_MCP_REMOTE_STACK_DIR=/opt/whatsapp-mcp \
bash bin/mcp-remote-stdio.sh

MCP tools

Tool

Description

whatsapp_status

Collector status, auth state, database stats and local paths

whatsapp_list_chats

Known chats, newest first

whatsapp_find_chat

Find chat IDs by contact name, group name or partial JID

whatsapp_recent_messages

Recent stored messages, optionally for one chat

whatsapp_search_messages

Case-insensitive substring search over message text

whatsapp_messages_by_date

Messages in a date/time range, globally or for one chat

whatsapp_list_attachments

Media/document messages, filterable by chat or type

whatsapp_list_links

Messages that contain URLs

whatsapp_deleted_messages

Messages captured and later revoked

whatsapp_summarize_chat

Statistical summary of a chat (participants, counts, links, media)

whatsapp_send_message

Sends (or schedules) text or an image with caption from your account; require confirmation

whatsapp_outbox_status

Status of one outbox entry, or the most recent entries

Sending messages

whatsapp_send_message arguments:

Argument

Description

recipient

Full JID (<number>@s.whatsapp.net, <id>@g.us), number with country code, or a 10/11-digit local number (prefixed with WHATSAPP_DEFAULT_COUNTRY_CODE)

message

Text, or the caption when an image is sent

image_base64

Optional JPEG, PNG or WebP as base64 or a data:image/...;base64, URL, up to 10 MiB decoded; the format is detected from the file bytes

scheduled_at

Optional ISO 8601 datetime (e.g. 2026-12-01T09:00:00-03:00); stored in UTC

wait_for_delivery

Default true: poll up to timeout_seconds for the collector to confirm

timeout_seconds

1 to 30, default 10

Flow:

  1. The MCP server validates the input (non-empty text or a valid image), normalizes the recipient and inserts a pending row into the outbox table.

  2. The collector, while connected, polls the outbox every second and takes up to 5 due messages (scheduled_at empty or in the past), marks each sending, and sends it.

  3. On success the row becomes sent with sent_at and the WhatsApp message_id, and the stored image bytes are discarded. On error it becomes failed with the error text. Failed messages are not retried automatically.

Statuses: pending (queued, or waiting for its schedule), sending, sent, failed. The tool returns scheduled for future messages, pending when not waiting or when the timeout elapsed before confirmation (the message is still queued and will go out once the collector is connected). Use whatsapp_outbox_status with outbox_id to follow up.

Helper scripts

Script

What it does

Changes state?

bin/start-collector.sh

Starts the collector in a detached tmux session

Yes

bin/stop-collector.sh

Kills the tmux session and the pid in collector.pid

Yes

bin/status.sh

Prints systemd/tmux/pid state and DB/auth presence

No

bin/mcp-list-tools.sh

Emits the JSON-RPC lines for tools/list

No

bin/mcp-call.sh

Emits the JSON-RPC lines for one tools/call

No

bin/mcp-run-list-tools.sh

Pipes mcp-list-tools.sh into docker compose run mcp

No

bin/mcp-run-tool.sh

Pipes mcp-call.sh into docker compose run mcp

No

bin/mcp-remote-stdio.sh

Runs the MCP container on a remote host over SSH

No

Examples:

bash bin/mcp-run-tool.sh whatsapp_recent_messages '{"limit":5,"include_from_me":true}'
bash bin/mcp-run-tool.sh whatsapp_search_messages '{"query":"invoice","limit":10}'
bash bin/mcp-run-tool.sh whatsapp_outbox_status '{"limit":5}'

# Native piping without Docker
bash bin/mcp-list-tools.sh | node src/index.js

Importing WhatsApp exports

WHATSAPP_EXPORT_OWNER_NAME="Your Name" npm run import-export -- "/path/to/exported/chats"

The importer walks the folder recursively, parses every .txt file (US date format M/D/YY, H:MM - Sender: text), handles multi-line messages, ignores other files such as .vcf, and prints a JSON summary.

Resetting the pairing (Docker)

docker compose stop collector && rm -rf data/auth && docker compose up -d collector

Limitations

  • No history backfill: only messages received after pairing are captured (plus .txt imports).

  • If a delete event arrives before the original message is stored, the text cannot be recovered; the collector logs the revoke for an unknown message.

  • Search is a SQL LIKE substring match, not ranked full-text search.

  • The .txt importer only understands the US-style export format (M/D/YY, H:MM - ). Exports from other locales are skipped or have day and month swapped.

  • Baileys is an unofficial client; WhatsApp protocol changes can break the collector until the dependency is updated.

  • Sending is fire-and-forget: there is no read receipt tracking, no automatic retry of failed messages and no way to cancel a scheduled message through MCP (delete or update the outbox row in SQLite instead). Scheduled messages only go out while the collector is connected.

  • The collector exits on disconnect instead of reconnecting in-process, so it needs a supervisor (Docker restart policy or systemd Restart=always). bin/start-collector.sh (tmux) does not restart it.

  • bin/mcp-remote-stdio.sh disables SSH host key checking (StrictHostKeyChecking=no).

License

MIT — see LICENSE.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI agents to interact with your personal WhatsApp account to search messages, list chats, and send messages. It stores all authentication and message data locally using SQLite for privacy and direct multi-device API connection.
    15 npm
    1
    ISC
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables local querying of WhatsApp message history via SQLite, with profile separation, media transcription, and operational summaries.
    1
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Lets AI agents search and read your personal Telegram and WhatsApp conversations through a self-hosted, read-only MCP server backed by a single SQLite file.
    2
    AGPL 3.0
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables AI assistants to read WhatsApp chat history from a SQLite archive, optionally scrape live chats, and send messages through a chain of safety guards.
    44 npm
    MIT