Skip to main content
Glama
README.md
<p align="center">
  <img src="https://img.shields.io/badge/WhatsApp-25D366?style=for-the-badge&logo=whatsapp&logoColor=white" alt="WhatsApp" />
  <img src="https://img.shields.io/badge/MCP-000000?style=for-the-badge&logo=anthropic&logoColor=white" alt="MCP" />
  <img src="https://img.shields.io/badge/TypeScript-3178C6?style=for-the-badge&logo=typescript&logoColor=white" alt="TypeScript" />
  <img src="https://img.shields.io/badge/Docker-2496ED?style=for-the-badge&logo=docker&logoColor=white" alt="Docker" />
</p>

<h1 align="center">🟒 WA MCP</h1>

<p align="center">
  <strong>The first WhatsApp integration built natively for AI Agents.</strong>
  <br />
  <em>Full MCP server exposing WhatsApp as discoverable tools, resources, and real-time notifications.</em>
</p>

<p align="center">
  <a href="#-quick-start">Quick Start</a> β€’
  <a href="#-features">Features</a> β€’
  <a href="#-tools">Tools</a> β€’
  <a href="#-architecture">Architecture</a> β€’
  <a href="#%EF%B8%8F-configuration">Configuration</a> β€’
  <a href="#-docker">Docker</a> β€’
  <a href="#-contributing">Contributing</a>
</p>

<p align="center">
  <a href="https://github.com/delltrak/wamcp/actions/workflows/ci.yml"><img src="https://github.com/delltrak/wamcp/actions/workflows/ci.yml/badge.svg" alt="CI" /></a>
  <img src="https://img.shields.io/github/license/delltrak/wamcp?style=flat-square" alt="License" />
  <img src="https://img.shields.io/badge/node-%3E%3D22-brightgreen?style=flat-square" alt="Node" />
  <img src="https://img.shields.io/badge/MCP-Streamable%20HTTP-blue?style=flat-square" alt="Transport" />
</p>

---

## πŸ€– What is WA MCP?

**WA MCP** is a WhatsApp MCP server built with TypeScript that gives AI agents full access to WhatsApp through the [Model Context Protocol](https://modelcontextprotocol.io). It supports both **Baileys** (WhatsApp Web) and **Meta Cloud API** as dual-channel backends, deployable with **Docker** in a single command.

Your agent connects once and auto-discovers **63 tools**, **10 resources**, and **12 real-time events** β€” zero configuration, zero REST wrappers, zero glue code.

```
Your AI Agent ←→ MCP Protocol ←→ WA MCP ←→ WhatsApp
```

Instead of writing HTTP clients, parsing webhook payloads, and mapping endpoints to tools manually β€” your agent just **connects and goes**. Works out of the box with **Claude**, **Google ADK**, **LangChain**, and any MCP-compatible AI agent framework.

> πŸ’‘ **MCP** (Model Context Protocol) is the open standard for connecting AI agents to tools and data. WA MCP speaks MCP natively via Streamable HTTP and stdio transports.

---

## πŸš€ Quick Start

### One command with Docker

```bash
docker compose up
```

That's it. WA MCP + Redis, ready on `http://localhost:3000/mcp`.

### Or run locally

```bash
# Prerequisites: Node.js >= 22, Redis running
npm install
cp .env.example .env

# Development (stdio transport)
npm run dev

# Production (HTTP transport)
npm run build && npm start
```

### Connect your agent

<details>
<summary>🐍 Google ADK (Python)</summary>

```python
from google.adk.tools.mcp_tool import McpToolset

tools = McpToolset(url="http://localhost:3000/mcp")

# Agent auto-discovers 63 WhatsApp tools
# wa_create_instance, wa_send_text, wa_send_image, ...
```

</details>

<details>
<summary>🦜 LangChain</summary>

```python
from langchain_mcp import McpToolkit

toolkit = McpToolkit(server_url="http://localhost:3000/mcp")
tools = toolkit.get_tools()
```

</details>

<details>
<summary>πŸ’» Claude Desktop</summary>

Add to your `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "whatsapp": {
      "command": "node",
      "args": ["path/to/wa-mcp/dist/index.js"],
      "env": {
        "WA_TRANSPORT": "stdio",
        "WA_REDIS_URL": "redis://localhost:6379"
      }
    }
  }
}
```

</details>

---

## ✨ Features

|     | Feature                | Description                                                                                               |
| --- | ---------------------- | --------------------------------------------------------------------------------------------------------- |
| πŸ”Œ  | **MCP-native**         | Streamable HTTP + stdio transports. No REST, no webhooks.                                                 |
| πŸ“±  | **Dual-channel**       | Baileys (WhatsApp Web) + Meta Cloud API β€” same interface.                                                 |
| πŸ”„  | **Multi-instance**     | Run 1–50 WhatsApp numbers from a single server.                                                           |
| πŸ“¨  | **Full messaging**     | Text, images, video, audio, documents, polls, reactions, replies, forwards, edits, deletes, view-once.    |
| πŸ‘₯  | **Groups**             | Create, manage members, promote/demote admins, settings, invite links, join requests, ephemeral messages. |
| πŸ‘€  | **Contacts & Profile** | Number check, block/unblock, business profiles, privacy, status updates.                                  |
| πŸ“‘  | **Real-time events**   | 12 notification types via SSE: messages, typing, groups, calls, connection status.                        |
| ⚑  | **Rate limiting**      | BullMQ queues prevent WhatsApp bans (20 msg/min Baileys, 80 msg/min Cloud).                               |
| πŸ”  | **Auto-reconnect**     | Automatic reconnection with exponential backoff.                                                          |
| πŸ—ƒοΈ  | **Persistent**         | SQLite storage for sessions, messages, contacts, groups.                                                  |
| 🐳  | **Single container**   | `docker compose up` β€” only Redis as external dependency.                                                  |

---

## πŸ› οΈ Tools

WA MCP exposes **63 tools** across 9 domains. All tools use the `wa_` prefix.

<details>
<summary>πŸ“‹ <strong>Instance Management</strong> (8 tools)</summary>

| Tool                       | Description                      |
| -------------------------- | -------------------------------- |
| `wa_create_instance`       | Create a new WhatsApp connection |
| `wa_connect_instance`      | Connect (generates QR code)      |
| `wa_disconnect_instance`   | Gracefully disconnect            |
| `wa_delete_instance`       | Permanently remove instance      |
| `wa_restart_instance`      | Disconnect + reconnect           |
| `wa_get_qr_code`           | Get QR as base64 (Baileys)       |
| `wa_get_pairing_code`      | Get pairing code (Baileys)       |
| `wa_set_cloud_credentials` | Set Cloud API token              |

</details>

<details>
<summary>πŸ’¬ <strong>Messaging</strong> (17 tools)</summary>

| Tool                   | Description             |
| ---------------------- | ----------------------- |
| `wa_send_text`         | Send text message       |
| `wa_send_image`        | Send image with caption |
| `wa_send_video`        | Send video with caption |
| `wa_send_audio`        | Send audio / voice note |
| `wa_send_document`     | Send file / document    |
| `wa_send_location`     | Send GPS location       |
| `wa_send_contact`      | Send vCard contact      |
| `wa_send_poll`         | Create a poll           |
| `wa_send_reaction`     | React with emoji        |
| `wa_send_link_preview` | Send URL with preview   |
| `wa_forward_message`   | Forward a message       |
| `wa_edit_message`      | Edit sent message       |
| `wa_delete_message`    | Delete message          |
| `wa_pin_message`       | Pin a message           |
| `wa_send_view_once`    | Send view-once media    |
| `wa_send_presence`     | Show typing / recording |
| `wa_mark_read`         | Mark messages as read   |

</details>

<details>
<summary>πŸ’­ <strong>Chat Management</strong> (6 tools)</summary>

| Tool              | Description              |
| ----------------- | ------------------------ |
| `wa_get_messages` | Get chat message history |
| `wa_archive_chat` | Archive / unarchive      |
| `wa_pin_chat`     | Pin / unpin chat         |
| `wa_mute_chat`    | Mute / unmute            |
| `wa_delete_chat`  | Delete chat              |
| `wa_clear_chat`   | Clear chat history       |

</details>

<details>
<summary>πŸ‘₯ <strong>Groups</strong> (14 tools)</summary>

| Tool                           | Description                   |
| ------------------------------ | ----------------------------- |
| `wa_create_group`              | Create group                  |
| `wa_group_add_participants`    | Add members                   |
| `wa_group_remove_participants` | Remove members                |
| `wa_group_promote`             | Promote to admin              |
| `wa_group_demote`              | Demote from admin             |
| `wa_group_update_subject`      | Change group name             |
| `wa_group_update_description`  | Change description            |
| `wa_group_update_settings`     | Change settings               |
| `wa_group_leave`               | Leave group                   |
| `wa_group_get_invite_code`     | Get invite link               |
| `wa_group_revoke_invite`       | Revoke invite link            |
| `wa_group_join`                | Join via invite code          |
| `wa_group_toggle_ephemeral`    | Toggle disappearing messages  |
| `wa_group_handle_request`      | Approve / reject join request |

</details>

<details>
<summary>πŸ“‡ <strong>Contacts</strong> (5 tools)</summary>

| Tool                      | Description                      |
| ------------------------- | -------------------------------- |
| `wa_search_contact`       | Search contacts by name or phone |
| `wa_check_number_exists`  | Check if number is on WhatsApp   |
| `wa_block_contact`        | Block contact                    |
| `wa_unblock_contact`      | Unblock contact                  |
| `wa_get_business_profile` | Get business profile             |

</details>

<details>
<summary>πŸ‘€ <strong>Profile</strong> (5 tools)</summary>

| Tool                        | Description             |
| --------------------------- | ----------------------- |
| `wa_update_profile_picture` | Set profile picture     |
| `wa_remove_profile_picture` | Remove profile picture  |
| `wa_update_profile_name`    | Change display name     |
| `wa_update_profile_status`  | Change status text      |
| `wa_update_privacy`         | Update privacy settings |

</details>

<details>
<summary>πŸ“’ <strong>Status / Stories</strong> (3 tools)</summary>

| Tool                   | Description       |
| ---------------------- | ----------------- |
| `wa_send_text_status`  | Post text status  |
| `wa_send_image_status` | Post image status |
| `wa_send_video_status` | Post video status |

</details>

<details>
<summary>πŸ“° <strong>Newsletter</strong> (3 tools)</summary>

| Tool                     | Description           |
| ------------------------ | --------------------- |
| `wa_newsletter_follow`   | Follow a newsletter   |
| `wa_newsletter_unfollow` | Unfollow a newsletter |
| `wa_newsletter_send`     | Send to newsletter    |

</details>

<details>
<summary>πŸ“ž <strong>Calls</strong> (1 tool)</summary>

| Tool             | Description          |
| ---------------- | -------------------- |
| `wa_reject_call` | Reject incoming call |

</details>

---

## πŸ“– Resources

Resources expose read-only WhatsApp state via `whatsapp://` URIs:

| URI                                           | Description                    |
| --------------------------------------------- | ------------------------------ |
| `whatsapp://instances`                        | List all instances             |
| `whatsapp://instances/{id}`                   | Instance details + queue stats |
| `whatsapp://instances/{id}/contacts`          | All contacts                   |
| `whatsapp://instances/{id}/chats`             | Active conversations           |
| `whatsapp://instances/{id}/groups`            | All groups                     |
| `whatsapp://instances/{id}/groups/{gid}`      | Group metadata                 |
| `whatsapp://instances/{id}/messages/{chatId}` | Message history                |
| `whatsapp://instances/{id}/profile`           | Own profile                    |
| `whatsapp://instances/{id}/privacy`           | Privacy settings               |
| `whatsapp://instances/{id}/blocklist`         | Blocked contacts               |

---

## πŸ“‘ Real-time Notifications

Events are pushed to agents via SSE (Server-Sent Events):

| Event                                 | Trigger                                        |
| ------------------------------------- | ---------------------------------------------- |
| `whatsapp/message.received`           | New incoming message                           |
| `whatsapp/message.updated`            | Status change (sent β†’ delivered β†’ read)        |
| `whatsapp/message.deleted`            | Message deleted                                |
| `whatsapp/message.reaction`           | Emoji reaction added/removed                   |
| `whatsapp/message.edited`             | Message edited                                 |
| `whatsapp/presence.updated`           | Typing / recording / online                    |
| `whatsapp/chat.updated`               | Chat metadata changed                          |
| `whatsapp/group.updated`              | Group info changed                             |
| `whatsapp/group.participants_changed` | Member add/remove/promote/demote               |
| `whatsapp/contact.updated`            | Contact info changed                           |
| `whatsapp/connection.changed`         | Instance status change (includes QR as base64) |
| `whatsapp/call.received`              | Incoming call                                  |

---

## πŸ—οΈ Architecture

```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              AI Agent Runtime               β”‚
β”‚    (Google ADK, Claude, LangChain, ...)     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                   β”‚  MCP Streamable HTTP
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              WA MCP Server                  β”‚
β”‚                                             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚  Layer 1 β€” MCP Transport (HTTP/stdio) β”‚ β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚
β”‚  β”‚  Layer 2 β€” MCP Core                   β”‚ β”‚
β”‚  β”‚  63 Tools β”‚ 10 Resources β”‚ 12 Events  β”‚ β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚
β”‚  β”‚  Layer 3 β€” Services                   β”‚ β”‚
β”‚  β”‚  Instance Manager β”‚ Queue β”‚ Dedup     β”‚ β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚
β”‚  β”‚  Layer 4 β€” Channel Abstraction        β”‚ β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚ β”‚
β”‚  β”‚  β”‚   Baileys    β”‚ β”‚   Cloud API    β”‚  β”‚ β”‚
β”‚  β”‚  β”‚  (WebSocket) β”‚ β”‚    (HTTPS)     β”‚  β”‚ β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚       SQLite (Drizzle)    BullMQ (Redis)    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                   β”‚
                   β–Ό  WebSocket / HTTPS
          WhatsApp Servers
```

### Dual-Channel Design

|            | Baileys                  | Cloud API                |
| ---------- | ------------------------ | ------------------------ |
| Protocol   | WhatsApp Web (WebSocket) | Meta Official (HTTPS)    |
| Auth       | QR Code / Pairing Code   | Access Token             |
| Cost       | Free                     | Per-conversation pricing |
| Compliance | Unofficial               | Meta-approved            |
| Best for   | Dev, testing, low volume | Production, enterprise   |

Both backends implement the same `ChannelAdapter` interface. Your agent doesn't know or care which one is active β€” the tools work identically.

---

## βš™οΈ Configuration

Copy `.env.example` to `.env` and configure:

| Variable                    | Default                  | Description                              |
| --------------------------- | ------------------------ | ---------------------------------------- |
| `WA_TRANSPORT`              | `http`                   | `http` (Streamable HTTP) or `stdio`      |
| `WA_MCP_API_KEY`            | β€”                        | Bearer token auth. Unset = no auth (dev) |
| `WA_MCP_PORT`               | `3000`                   | HTTP server port                         |
| `WA_REDIS_URL`              | `redis://localhost:6379` | Redis for BullMQ queues                  |
| `WA_LOG_LEVEL`              | `info`                   | `debug` \| `info` \| `warn` \| `error`   |
| `WA_BAILEYS_RATE_LIMIT`     | `20`                     | Messages/min per Baileys instance        |
| `WA_CLOUD_RATE_LIMIT`       | `80`                     | Messages/min per Cloud API instance      |
| `WA_MESSAGE_RETENTION_DAYS` | `30`                     | Auto-delete old messages                 |
| `WA_AUTO_RECONNECT`         | `true`                   | Auto-reconnect on disconnect             |
| `WA_MEDIA_CACHE_MAX_MB`     | `500`                    | Media cache size limit                   |
| `WA_CLOUD_WEBHOOK_SECRET`   | β€”                        | Meta webhook verification                |
| `WA_CLOUD_WEBHOOK_PORT`     | `3001`                   | Webhook receiver port                    |
| `WA_VERSION_CHECK`          | `true`                   | Daily WhatsApp Web version check         |

---

## 🐳 Docker

### Production

```bash
docker compose up -d
```

Services:

- **wa-mcp** β€” The MCP server on port `3000`
- **redis** β€” BullMQ backend with AOF persistence

### Health Check

```bash
curl http://localhost:3000/health
```

```json
{
  "status": "ok",
  "uptime": 3600,
  "instances": { "total": 3, "connected": 2, "disconnected": 1 },
  "version": "1.0.0"
}
```

### Resource Requirements

| Instances | RAM    | CPU      | Disk  |
| --------- | ------ | -------- | ----- |
| 1–5       | 256 MB | 0.5 vCPU | 1 GB  |
| 5–20      | 512 MB | 1 vCPU   | 5 GB  |
| 20–50     | 1 GB   | 2 vCPU   | 10 GB |

---

## πŸ“ Project Structure

```
src/
β”œβ”€β”€ index.ts                     # Entry point (HTTP/stdio)
β”œβ”€β”€ constants.ts                 # Defaults and limits
β”œβ”€β”€ server/mcp.ts                # MCP server setup
β”œβ”€β”€ tools/                       # πŸ”§ 63 MCP tools (9 files)
β”œβ”€β”€ resources/                   # πŸ“– 10 MCP resources (8 files)
β”œβ”€β”€ notifications/events.ts      # πŸ“‘ 12 event types
β”œβ”€β”€ channels/
β”‚   β”œβ”€β”€ channel.interface.ts     # ChannelAdapter contract
β”‚   β”œβ”€β”€ baileys/                 # Baileys implementation
β”‚   └── cloud-api/               # Cloud API implementation
β”œβ”€β”€ services/
β”‚   β”œβ”€β”€ instance-manager.ts      # Instance lifecycle
β”‚   β”œβ”€β”€ message-queue.ts         # BullMQ rate limiting
β”‚   β”œβ”€β”€ dedup.ts                 # Message deduplication
β”‚   └── media.ts                 # Media handling
β”œβ”€β”€ db/
β”‚   β”œβ”€β”€ schema.ts                # Drizzle table definitions
β”‚   └── client.ts                # SQLite connection
β”œβ”€β”€ schemas/                     # Zod validation (9 files)
└── types/                       # TypeScript definitions
```

---

## πŸ—ΊοΈ Roadmap

- [x] **Phase 1** β€” Foundation: Baileys adapter, text messaging, QR auth, instance management
- [x] **Phase 2** β€” Full messaging: all media types, dedup, reactions, edits, forwards
- [x] **Phase 3** β€” Groups, contacts, profile, status/stories, newsletters
- [x] **Phase 4** β€” Cloud API adapter: dual-channel unified interface
- [x] **Phase 5** β€” Hardening: error recovery, CI/CD, tests, docs, v1.0 release
- [x] **Phase 6** β€” Baileys v7 upgrade, LID support, contact sync, message persistence

---

## 🀝 Contributing

Contributions are welcome! Here's how the codebase is organized:

1. **One file per domain** β€” tools, resources, schemas, and channels each have domain-specific files
2. **Zod schemas for everything** β€” all tool inputs are validated with strict Zod schemas in `src/schemas/`
3. **Both adapters** β€” new features should be implemented in Baileys and stubbed in Cloud API
4. **Layered architecture** β€” tools β†’ services β†’ channels. No cross-layer imports.
5. **Structured logging** β€” use Pino, never `console.log`

```bash
# Development
npm run dev          # Start with stdio transport
npm run build        # Type-check + compile
npx tsc --noEmit     # Type-check only
```

---

## πŸ“„ License

MIT β€” do whatever you want.

---

<p align="center">
  <strong>Built for the agentic era.</strong>
  <br />
  <em>Stop writing REST wrappers. Let your agent discover WhatsApp.</em>
</p>