Skip to main content
Glama
cascodigital

WhatsApp MCP Server

by cascodigital
README.md
# WhatsApp MCP Server

A local-first WhatsApp message collector built on [Baileys](https://github.com/WhiskeySockets/Baileys),
paired with a [Model Context Protocol](https://modelcontextprotocol.io) (MCP) server that lets
LLM clients (Claude, Codex, etc.) **read and search your own WhatsApp history** stored in a local
SQLite database.

Nothing leaves your machine: messages are captured by your own linked device, persisted locally,
and exposed only over MCP stdio.

> **Heads up:** 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.

## Features

- **Live capture** of new messages from the moment the device is paired (no history backfill).
- **Deleted-message retention**: if a captured message is later revoked, the text is kept and the
  record is flagged instead of being lost.
- **Group / direct awareness**, push names, attachments and links indexing.
- **SQLite storage** — easy to inspect, back up, or query directly.
- **MCP tools** for status, listing chats, recent messages, full-text search, date ranges,
  attachments, links, deleted messages and chat summaries.
- **Optional import** of WhatsApp `.txt` chat exports.
- Runs natively (Node) or in **Docker**.

## Architecture

Two processes share one SQLite database:

| Process     | File              | Role                                                        |
|-------------|-------------------|-------------------------------------------------------------|
| `collector` | `src/collector.js`| Stays connected to WhatsApp, writes incoming messages to DB |
| `mcp`       | `src/index.js`    | Stdio MCP server, read-only queries against the same DB     |

By default everything lives under `~/.local/share/whatsapp-mcp/`:

```
~/.local/share/whatsapp-mcp/
├── auth/              # Baileys credentials (pairing)
├── messages.sqlite    # the message database
├── collector.log
└── collector.pid
```

Override the location with `WHATSAPP_MCP_HOME`.

## Requirements

- Node.js 22+ (or Docker)
- A WhatsApp account on your phone for pairing

## Quick start (native)

```bash
npm install

# 1. Run the collector in the foreground to display the pairing QR code
npm run collector
```

On your phone: **Settings → Linked devices → Link a device**, then scan the QR code.

Once paired, you can run the collector in the background via tmux:

```bash
bash bin/start-collector.sh                 # start
tmux attach -t whatsapp-mcp-collector       # inspect  (detach: Ctrl+B then D)
bash bin/stop-collector.sh                  # stop
```

The device will appear on your phone as `macOS` (the collector uses
`Browsers.macOS('Desktop')`).

## Quick start (Docker)

```bash
docker compose up -d --build collector
docker compose logs -f collector
```

When you see `Scan the QR code in WhatsApp > Linked devices.`, scan it on your phone.

Persistent data lives in `./data` next to `compose.yml`:

- auth: `./data/auth/`
- database: `./data/messages.sqlite`
- pidfile: `./data/collector.pid`

Common operations:

```bash
docker compose ps
docker compose logs --tail=50 collector
docker compose stop|start|restart collector

# reset pairing
docker compose stop collector && rm -rf data/auth && docker compose up -d collector
```

## Using the MCP server

The MCP server speaks **stdio**, not HTTP. Point your MCP client at one of:

**Native:**

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

**Docker:**

```bash
docker compose run --rm -T mcp
```

**Remote Docker over SSH** — `bin/mcp-remote-stdio.sh` runs the stdio MCP on another host.
Configure it with environment variables (no values are hardcoded):

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

For quick manual testing without writing JSON-RPC by hand:

```bash
bash bin/mcp-run-list-tools.sh
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":"hello","limit":10}'
```

### Available MCP tools

| Tool                          | Description                          |
|-------------------------------|--------------------------------------|
| `whatsapp_status`             | Collector / connection status        |
| `whatsapp_list_chats`         | List known chats                     |
| `whatsapp_find_chat`          | Resolve a chat by name/JID           |
| `whatsapp_recent_messages`    | Most recent messages                 |
| `whatsapp_search_messages`    | Full-text search                     |
| `whatsapp_messages_by_date`   | Messages within a date range         |
| `whatsapp_list_attachments`   | Attachments index                    |
| `whatsapp_list_links`         | Links index                          |
| `whatsapp_deleted_messages`   | Messages revoked after capture       |
| `whatsapp_summarize_chat`     | Summarize a chat                     |

## Deleted messages

This server tries to keep the text of messages that are deleted **after** they were received:

- If the message was persisted first and the revoke event arrived later, the text stays in the DB.
- The record is marked `isRevoked=true`, with `revokedAt`, `revokedBy`, `revokedByMe` and
  `revokeSourceMessageId`.

**Limitation:** if the delete event arrives *before* the original message is persisted, there is no
text to recover. The collector logs that it received a revoke for an unknown message.

## Importing WhatsApp exports

To import a `.txt` chat export:

```bash
npm run import-export -- "/path/to/exported/chat/folder"
```

The importer:

- ignores `.vcf` files
- handles multi-line messages
- marks records with `source=import`
- uses synthetic chat IDs so imports never mix with live capture

## Configuration

| Variable                        | Default                                | Purpose                          |
|---------------------------------|----------------------------------------|----------------------------------|
| `WHATSAPP_MCP_HOME`             | `~/.local/share/whatsapp-mcp`          | Base dir for auth/db/logs        |
| `WHATSAPP_MCP_TMUX_SESSION`     | `whatsapp-mcp-collector`               | tmux session name                |
| `WHATSAPP_MCP_SYSTEMD_SERVICE`  | `whatsapp-mcp-collector.service`       | systemd user unit name           |
| `WHATSAPP_BAILEYS_LOG_LEVEL`    | `warn`                                 | Baileys log verbosity            |
| `WHATSAPP_MCP_REMOTE_HOST`      | —                                      | SSH target for remote stdio MCP  |
| `WHATSAPP_MCP_REMOTE_STACK_DIR` | —                                      | Remote compose stack directory   |

## License

MIT — see [LICENSE](LICENSE).