WhatsApp MCP Server
Integrates with WhatsApp to enable AI agents to send messages, search chats, share media, manage approval workflows, and receive intelligent activity summaries.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@WhatsApp MCP Serversend a message to John saying I'll be late"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
WhatsApp MCP Server
WhatsApp integration for AI agents — Send messages, search chats, share media, approval workflows, and intelligent activity summaries via any MCP client. Designed to run as a containerized MCP server through Docker MCP Toolkit.
Acknowledgment: The author is well aware of kapso.ai, which provides a more robust and feature-complete WhatsApp integration solution. This project is what happens when a hobbyist coder with too much curiosity, decent system design instincts, and modern AI assistance decides to see how far they can push their weekend project. It's a learning exercise in MCP servers, containerization, and WhatsApp protocol integration — the kind of thing that would have been unreasonable to attempt alone a few years ago, but is now very much within reach thanks to better tooling and a lot of help from AI.
Note: This project requires Docker Desktop with MCP Toolkit enabled. Alternatively, you can run it with Docker Engine + Docker Compose (without the MCP Gateway features).
Why Docker MCP Toolkit?
This server runs inside a Docker container managed by Docker MCP Toolkit, rather than directly on your host machine.
Benefit | Docker MCP Toolkit | Running on Host |
Isolation | WhatsApp session keys, messages, and media are confined to Docker volumes — not mixed with your regular files | Session data ends up somewhere in your home directory |
Security boundary | Non-root, read-only filesystem, capabilities dropped | Runs with your full user permissions |
Multi-client gateway | One server instance serves all your MCP clients (Cursor, Claude Code, VS Code) simultaneously through the MCP Gateway | Each client needs its own server configuration |
Secrets management | Encryption keys stored in OS Keychain via | Must manage |
Host dependencies | No Node.js, native compilation, or Go binary management required on your machine | Must install Node.js 18+, build tools for native addons, and manage platform-specific binaries |
Portability | Works on Windows, macOS, and Linux (in theory — tested primarily on Windows) | Platform-specific issues with native dependencies |
Lifecycle management | Health checks, auto-restart, graceful shutdown — all handled by Docker | Manual process management |
Clean teardown |
| Must manually find and clean up data files, sessions, and processes |
Related MCP server: MCP WPPConnect Server
Features
34 MCP Tools — Full WhatsApp control: messaging, media, search, contacts, groups, message actions, approvals, status, live interaction, session management, and layered tool documentation
Fuzzy Name Matching — Say "John" or "book club" and the server finds the right chat via Levenshtein distance
Media Support — Download received media and send images, videos, audio, and documents
Full-Text Search — SQLite FTS5 indexes all messages with keyword, phrase, and boolean operators
Intelligent Catch-Up — One tool that summarizes active chats, pending questions, and unread highlights
Approval Workflows — Send approval requests via WhatsApp; recipients reply APPROVE or DENY
Pairing Code Auth — Text-based 8-digit code authentication with QR code image fallback (rendered in-container, viewable in any browser via data URI)
Encryption at Rest — AES-256-GCM field-level encryption for message bodies, sender names, and media metadata
Auto-Purge — Automatic deletion of messages and media older than a configurable retention period
Read Receipts & Presence — Delivery receipts (double checkmarks), read receipts (blue checkmarks), and online presence — all configurable
Session Resilience — Automatic reconnection on transient disconnects, startup retry with exponential backoff, 60-second health heartbeat, and MCP notifications on session expiry
Session Persistence — WhatsApp session survives container restarts via Docker named volumes
Long-Lived Containers — The server keeps the WhatsApp WebSocket connection alive across tool calls
Welcome Group — Optionally creates a WhatsApp group and sends a hello message on first connection
Quick Start
🚀 Minimal Viable Setup (5 Minutes)
Want to try it fast? No clone or build needed — the image is pulled automatically from Docker Hub.
PowerShell Users: Replace
\(backslash) with`(backtick) for line continuation in the commands below.Example:
docker mcp catalog create my-mcp --title "My MCP Servers" ` --server file://./whatsapp-mcp-docker-server.yaml
# 0. Find your profile name (Docker Desktop creates "default" on install)
docker mcp profile list
# 1. Download the server definition file (no full clone needed)
curl -O https://raw.githubusercontent.com/Malaccamaxgit/whatsapp-mcp-docker/main/whatsapp-mcp-docker-server.yaml
# 2. Create catalog (one-time setup)
docker mcp catalog create my-mcp --title "My MCP Servers" \
--server file://./whatsapp-mcp-docker-server.yaml
# 3. Add to your profile (replace "default" with your profile name from step 0)
docker mcp profile server add default \
--server file://./whatsapp-mcp-docker-server.yaml
# 4. Connect your MCP client (replace "cursor" with your client — see table below)
docker mcp client connect cursor --profile default
# 5. Restart / reload your MCP client so it picks up the new tools
# 6. In your client, say: "Authenticate WhatsApp with +1234567890"Supported clients for step 4: cursor, claude-code, claude-desktop, vscode, gemini, goose, and more. Run docker mcp client connect --help to see the full list.
That's it! You're now connected to WhatsApp. The image (malaccamax/whatsapp-mcp-docker:latest) is pulled automatically from Docker Hub on first use — no build step required.
Note: After connecting, you must restart or reload your MCP client before the WhatsApp tools appear (see Step 5 in the Full Setup below for client-specific instructions). Running
docker mcp tools lsin the terminal shows only 8 MCP Toolkit meta-tools — the 34 WhatsApp tools appear inside your client after the gateway starts the container on first use.Important: In some MCP sessions, you may need to explicitly activate the profile before tools are available. If you get
Error: Tool 'get_connection_status' not found in current session, run:docker mcp profile activate <your-profile>Or inside an MCP client session, use the
mcp-activate-profilemeta-tool. This is a known gap in the Docker MCP Gateway auto-loading behavior.
Next steps: Set up encryption and recommended configuration (below) for secure use.
📋 Full Setup (Recommended Secure Configuration)
0. Find Your Profile Name
Docker Desktop creates a profile named default on install. Check yours before proceeding:
docker mcp profile listUse the name shown there wherever <your-profile> appears in the steps below.
Need a dedicated profile? In Docker Desktop go to MCP Toolkit → Profiles and click + to create one, then use that name.
1. Get the Project
Option A — Just the server YAML (recommended for most users):
The image is pulled automatically from Docker Hub. You only need the server definition file:
curl -O https://raw.githubusercontent.com/Malaccamaxgit/whatsapp-mcp-docker/main/whatsapp-mcp-docker-server.yamlOption B — Full clone + local build (for developers or self-hosters):
Clone and build locally if you want to modify the source or run without Docker Hub:
git clone https://github.com/Malaccamaxgit/whatsapp-mcp-docker.git
cd whatsapp-mcp-docker
docker compose build --no-cacheWhy
--no-cache? BuildKit's layer caching can incorrectly cache TypeScript compilation even when source files change. Always use--no-cacheto ensure the latest compiled code is used.
Stay in the directory containing
whatsapp-mcp-docker-server.yamlfor all subsequent commands — thefile://./path in catalog and profile commands is relative to your working directory.
2. Set the Encryption Key
Set the encryption key (stored in OS Keychain — no .env files needed):
# Option A: Using Node.js (if installed on host) — bash/zsh only
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))" | docker mcp secret set whatsapp-mcp-docker.data_encryption_key
# Option B: Using Docker (no Node.js required on host) — bash/zsh only
docker run --rm node:22-alpine node -e "console.log(require('crypto').randomBytes(32).toString('base64'))" | docker mcp secret set whatsapp-mcp-docker.data_encryption_keyWindows PowerShell users: The pipe (
|) and redirect (<) operators do not work withdocker mcp secret seton PowerShell. Use this two-step approach instead:# Option A: Using Python (recommended — avoids require() escaping issues) $key = docker run --rm python:3-alpine python3 -c "import base64,os; print(base64.b64encode(os.urandom(32)).decode())" docker mcp secret set "whatsapp-mcp-docker.data_encryption_key=$key" # Option B: Using Node.js — requires careful quoting; base64 chars + / = may cause issues $key = docker run --rm node:22-alpine node -e "console.log(require('crypto').randomBytes(32).toString('base64'))" docker mcp secret set "whatsapp-mcp-docker.data_encryption_key=$key"If you see a "logon session does not exist" error but the key still appears in
docker mcp secret ls, the key was stored successfully in thedocker-passbackend — the error is a misleading warning from a secondary Windows Credential Manager backend and can be safely ignored.
Verify the key was stored (docker mcp secret set produces no confirmation on success):
# bash/zsh
docker mcp secret ls | grep whatsapp
# PowerShell
docker mcp secret ls | findstr whatsappYou should see a line containing whatsapp-mcp-docker.data_enc….
Tip: Keep the generated key safe! If you lose it, encrypted messages cannot be recovered. Back it up to a password manager.
Security posture: Running without
DATA_ENCRYPTION_KEYis an insecure mode. Only do this with an explicit operator override and documented risk acceptance.
3. Create a Custom Catalog
Register the server in a custom catalog so it appears in Docker Desktop's Catalog tab alongside the official Docker MCP Catalog:
PowerShell Users: On Windows PowerShell, use backtick (
`) instead of backslash (\) for line continuation.docker mcp catalog create my-custom-mcp-servers ` --title "My Custom MCP Servers" ` --server file://./whatsapp-mcp-docker-server.yaml
docker mcp catalog create my-custom-mcp-servers \
--title "My Custom MCP Servers" \
--server file://./whatsapp-mcp-docker-server.yamlIn Docker Desktop, go to MCP Toolkit → Catalog — the WhatsApp MCP server now appears under your custom catalog with all 34 tools, configuration options, and secrets.
Tip: To update the catalog after code changes, re-run the same command — it replaces the existing entry. To add more servers later, use multiple
--serverflags.
4. Add to a Profile and Apply Configuration
Add the server to a profile so MCP clients can use it.
Option A — From the Catalog UI:
In MCP Toolkit → Catalog, find WhatsApp MCP under your custom catalog.
Select the checkbox on the server card.
Choose a profile from the drop-down and confirm.
Option B — CLI:
docker mcp profile server add <your-profile> \
--server file://./whatsapp-mcp-docker-server.yamlOption C — Docker Desktop Profiles tab:
Open Docker Desktop and go to MCP Toolkit → Profiles.
Select an existing profile (or create a new one).
In the Servers section, click + and add the server.
All options register the server with longLived: true (persistent container), secrets (encryption key from OS Keychain), and all 34 tools.
After adding, apply the recommended configuration:
PowerShell Users: Use backtick (
`) instead of backslash (\) for line continuation.docker mcp profile config <your-profile> ` --set whatsapp-mcp-docker.rate_limit_per_min=60 ` --set whatsapp-mcp-docker.message_retention_days=90 ` --set whatsapp-mcp-docker.send_read_receipts=true ` --set whatsapp-mcp-docker.auto_read_receipts=true ` --set whatsapp-mcp-docker.presence_mode=available ` --set whatsapp-mcp-docker.welcome_group_name=WhatsAppMCP ` --set whatsapp-mcp-docker.auth_wait_for_link=false ` --set whatsapp-mcp-docker.auth_link_timeout_sec=120 ` --set whatsapp-mcp-docker.auth_poll_interval_sec=5
docker mcp profile config <your-profile> \
--set whatsapp-mcp-docker.rate_limit_per_min=60 \
--set whatsapp-mcp-docker.message_retention_days=90 \
--set whatsapp-mcp-docker.send_read_receipts=true \
--set whatsapp-mcp-docker.auto_read_receipts=true \
--set whatsapp-mcp-docker.presence_mode=available \
--set whatsapp-mcp-docker.welcome_group_name=WhatsAppMCP \
--set whatsapp-mcp-docker.auth_wait_for_link=false \
--set whatsapp-mcp-docker.auth_link_timeout_sec=120 \
--set whatsapp-mcp-docker.auth_poll_interval_sec=5Or configure via Docker Desktop: MCP Toolkit → WhatsApp MCP → Configuration / Secrets.
This populates the configuration fields in Docker Desktop so you can see and adjust them from the UI. Without this step, the server still works (defaults are applied at runtime), but the UI fields appear blank.
The auth_* keys set defaults for the authenticate tool when you omit waitForLink, linkTimeoutSec, or pollIntervalSec: whether to wait for the device to link after showing the pairing code or QR, the maximum wait time (seconds), and how often to poll (seconds). auth_wait_for_link=false is the default and recommended setting for most clients — it returns the pairing code immediately without blocking, avoiding tool-call timeouts. Set auth_wait_for_link=true only in environments that have no tool-call timeout and where you want the tool to automatically confirm once the device links.
5. Connect Your MCP Client
Connect your AI client to the profile with one command, substituting your client name:
docker mcp client connect <your-client> --profile <your-profile>Supported client names: cursor, claude-code, claude-desktop, vscode, gemini, goose, and others. Run docker mcp client connect --help to see the full list.
This automatically writes the MCP Gateway entry to your client's config file. After connecting, restart or reload your client so it picks up the new server:
Client | How to reload |
Cursor |
|
Claude Desktop | Quit and reopen the app |
Claude Code | Run |
VS Code | Reload the window or restart the MCP extension |
Goose / Gemini CLI | Restart the session |
Why doesn't
docker mcp tools lsshow my 34 tools? That command shows only the 8 MCP Toolkit meta-tools (e.g.mcp-add,mcp-find). The 34 WhatsApp tools appear inside your MCP client after the gateway starts thewhatsapp-mcp-dockercontainer on the first tool call. They are not visible from the terminal.
To connect manually instead, add the MCP Gateway entry directly to your client's config file. Ready-made snippets for every supported client are in examples/client-configs.md. Each client stores its config in a different location — consult your client's documentation for the exact path. The entry format is:
{
"mcpServers": {
"MCP_DOCKER": {
"command": "docker",
"args": ["mcp", "gateway", "run", "--profile", "<your-profile>"]
}
}
}Windows users: The
docker mcp client connectcommand automatically injects required Windows environment variables (LOCALAPPDATA,ProgramData,ProgramFiles). If you edit the config file manually, you must add them yourself or the gateway cannot locate credentials:{ "mcpServers": { "MCP_DOCKER": { "command": "docker", "args": ["mcp", "gateway", "run", "--profile", "<your-profile>"], "env": { "LOCALAPPDATA": "C:\\Users\\<you>\\AppData\\Local", "ProgramData": "C:\\ProgramData", "ProgramFiles": "C:\\Program Files" } } } }
6. Authenticate
From your MCP client:
Authenticate WhatsApp with my number +1234567890The server returns an 8-digit pairing code. Enter it in: WhatsApp → Settings → Linked Devices → Link a Device → Link with phone number instead
If pairing code fails (rate-limited or 400 error), the server falls back to QR code authentication:
MCP image block — displayed inline by clients that support image rendering (e.g., Cursor, Claude Desktop)
Data URI — a
data:image/png;base64,...string included in the text response; paste it into any browser's address bar to view the QR code — no host tools needed
The session persists across container restarts in the whatsapp-sessions Docker volume.
Compatible Clients: Claude Code, Claude Desktop, Cursor, VS Code, Gemini CLI, Goose, Cline, Gordon, Codex, and any client supporting the Model Context Protocol. Run docker mcp client connect --help to see the full list.
Available Tools (34)
Authentication & Status
Tool | Description |
| Log out and disconnect from WhatsApp, clearing the session |
| Link device via 8-digit pairing code (QR image fallback with data URI) |
| Connection state + database statistics |
Messaging
Tool | Description |
| Send text with fuzzy contact/group name matching |
| Send image, video, audio, or document with optional caption |
| Get messages from a chat with date range filtering and pagination |
| Full-text search across all messages (SQLite FTS5) |
Contacts & Chats
Tool | Description |
| List conversations sorted by recent activity |
| Find contacts/groups by name or phone number |
| Export complete chat history for a contact or group (JSON or CSV) |
Media
Tool | Description |
| Download media from a received message to persistent storage |
Intelligence
Tool | Description |
| Activity summary: active chats, questions, unread highlights |
| Mark messages as read in a chat |
Approval Workflows
Tool | Description |
| Send approval request — recipient replies APPROVE/DENY |
| Check specific approval or list all pending |
Group Management
Tool | Description |
| Create a new group with a name and list of participants |
| Get participants, admins, description, and settings for a group |
| List all groups this account belongs to |
| Get the shareable invite link for a group (admin only) |
| Join a group via invite link or code |
| Leave a group permanently |
| Add, remove, promote, or demote participants (admin only) |
| Rename a group (admin only) |
| Set or clear the group description (admin only) |
Message Actions
Tool | Description |
| React to a message with an emoji, or remove an existing reaction |
| Edit a previously sent message (own messages, within ~15 min) |
| Delete a sent message for everyone (revoke) |
Contacts & User Info
Tool | Description |
| Get profile information for one or more phone numbers (optional |
| Check whether phone numbers have WhatsApp accounts |
| Get the profile picture URL for a contact or group |
| Set a local custom display name for a JID or phone number (shown in lists and search) |
| Fetch WhatsApp profile names and store them for chats that still show as raw JIDs |
Interactive Workflows
Tool | Description |
| Block until an incoming message arrives — use during interactive tests so the AI detects phone messages automatically without user prompting |
Tool Documentation
Tool | Description |
| Get structured docs for any tool (usage, examples, response format, errors, related tools, pitfalls) |
Example Usage
# Authenticate
Authenticate WhatsApp with +1234567890
# Send a message (fuzzy name matching)
Send "I'll be 10 minutes late" to John
# Send a photo
Send the file /data/sessions/media/image/photo.jpg to the Engineering group as an image
# Search across all chats
Search my WhatsApp messages for "project deadline"
# Get a summary
Catch me up on today's WhatsApp activity
# View a conversation
Show me the last 20 messages with the Engineering group
# Find a contact
Search for contacts named "Sarah"
# Download media from a message
Download media from message ID abc123
# Approval workflow
Send an approval request to Sarah: "Deploy v2.1 to production?"
Check approval status for approval_1234567890_abcProject Structure
whatsapp-mcp-docker/
├── src/
│ ├── index.ts # Entry point — stdio transport + lifecycle
│ ├── server.ts # Server factory — wires tools, store, security
│ ├── whatsapp/
│ │ ├── client.ts # whatsmeow-node wrapper + media operations
│ │ └── store.ts # SQLite persistence + FTS5 search + media metadata
│ ├── tools/
│ │ ├── auth.ts # disconnect, authenticate
│ │ ├── status.ts # get_connection_status
│ │ ├── messaging.ts # send_message, list_messages, search_messages
│ │ ├── chats.ts # list_chats, search_contacts, catch_up, mark_messages_read, export_chat_data
│ │ ├── media.ts # download_media, send_file
│ │ ├── approvals.ts # request_approval, check_approvals
│ │ ├── groups.ts # create_group, get_group_info, get_joined_groups, get_group_invite_link, join_group, leave_group, update_group_participants, set_group_name, set_group_topic
│ │ ├── reactions.ts # send_reaction, edit_message, delete_message
│ │ ├── contacts.ts # get_user_info, is_on_whatsapp, get_profile_picture, set_contact_name, sync_contact_names
│ │ ├── wait.ts # wait_for_message
│ │ └── tool-info.ts # get_tool_info + layered documentation helpers
│ ├── security/
│ │ ├── audit.ts # SQLite audit logging
│ │ ├── crypto.ts # AES-256-GCM field-level encryption
│ │ ├── file-guard.ts # Path confinement, extension/magic checks, quota
│ │ └── permissions.ts # Whitelist, rate limiting, tool disabling, auth throttle
│ └── utils/
│ ├── fuzzy-match.ts # Levenshtein + substring matching
│ └── phone.ts # E.164 validation + JID conversion
├── docs/
│ ├── README.md # Documentation index
│ ├── API.md # Full MCP tool API reference (all 34 tools)
│ ├── TROUBLESHOOTING.md # Symptom → cause → fix guide
│ ├── architecture/
│ │ └── OVERVIEW.md # Architecture overview
│ ├── guides/
│ │ ├── DEVELOPER.md # Build, test, deploy procedures
│ │ └── ERRORS.md # Error taxonomy and recovery
│ ├── testing/
│ │ └── TESTING.md # Test strategy, structure, and commands
│ └── bugs/ # Bug reports and fixes
├── scripts/
│ ├── diagnostics.js # Health check and diagnostic script
│ ├── cleanup.ps1 # Full teardown script (Windows — git-ignored)
│ ├── cleanup.sh # Full teardown script (Linux/macOS — git-ignored)
│ ├── test.ps1 # Test runner (Windows)
│ └── test.sh # Test runner (Linux/macOS)
├── examples/
│ └── client-configs.md # Manual MCP client config snippets (Cursor, Claude, VS Code, Gemini, Goose, Cline)
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ └── workflows/
│ └── security-audit.yml
├── test/
│ ├── unit/ # Unit tests (node:test)
│ ├── integration/ # MCP protocol tests (mock WhatsApp client)
│ └── e2e/ # Live session tests (persistent auth)
├── Dockerfile # 4-stage (prod-deps → builder → test → runtime), ~80 MB runtime
├── docker-compose.yml # Main + tester-container (Compose profiles)
├── whatsapp-mcp-docker-server.yaml # Docker MCP Toolkit server definition
├── recommended-config.yaml # Reference config values for docker mcp profile config
├── .env.example # Environment variable template (docker-compose fallback)
├── package.json
├── package-lock.json
├── CHANGELOG.md
├── CONTRIBUTING.md
├── CODE_OF_CONDUCT.md
├── SECURITY.md
└── PRIVACY.mdSecurity
Non-root user (UID 1001, all capabilities dropped)
Read-only root filesystem (only
/datavolumes and/tmptmpfs writable)TLS transport — direct WhatsApp protocol (whatsmeow-node), no browser automation or TLS bypasses
Encryption at rest — AES-256-GCM for sensitive database fields (
DATA_ENCRYPTION_KEY)Secrets in OS Keychain — encryption key stored via
docker mcp secret set, never in config filesAuto-purge — messages and media auto-deleted after retention period (
MESSAGE_RETENTION_DAYS)File security — upload path confinement, extension blocklist, magic bytes verification, 512 MB media quota
Contact whitelist — restrict who can receive messages (
ALLOWED_CONTACTS)Rate limiting — outbound messages, media downloads, and authentication attempts
Input validation — Zod schemas with max-length limits on all tool parameters
Audit trail — all tool invocations logged to SQLite with timestamps
See SECURITY.md for the full security policy and vulnerability reporting.
Configuration
Configuration is managed through Docker MCP Toolkit (preferred) or docker-compose.yml environment variables.
Docker MCP Toolkit (Preferred)
Settings and secrets are managed via Docker Desktop UI or CLI:
Recommended initial setup (run all commands when first deploying):
# 1. Set encryption key (stored in OS Keychain)
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))" | \
docker mcp secret set whatsapp-mcp-docker.data_encryption_key
# 2. Apply complete recommended configuration to your profile
# Replace <your-profile> with your profile name (e.g., default-with-portainer)
docker mcp profile config <your-profile> \
--set whatsapp-mcp-docker.rate_limit_per_min=60 \
--set whatsapp-mcp-docker.message_retention_days=90 \
--set whatsapp-mcp-docker.send_read_receipts=true \
--set whatsapp-mcp-docker.auto_read_receipts=true \
--set whatsapp-mcp-docker.presence_mode=available \
--set whatsapp-mcp-docker.welcome_group_name=WhatsAppMCP \
--set whatsapp-mcp-docker.auth_wait_for_link=false \
--set whatsapp-mcp-docker.auth_link_timeout_sec=120 \
--set whatsapp-mcp-docker.auth_poll_interval_sec=5Or configure via Docker Desktop: MCP Toolkit → WhatsApp MCP → Configuration / Secrets.
Environment Variables
Variable | Description | Default |
| Container timezone — affects log timestamps and time-based features (e.g. |
|
| Session + message database directory |
|
| Audit log database path |
|
| Max outbound messages per minute |
|
| Max media downloads per minute |
|
| Passphrase for AES-256-GCM field encryption | (set via |
| Auto-delete messages/media older than N days (0 = keep forever) |
|
| Comma-separated phone whitelist (empty = allow all) |
|
| Comma-separated tool names to disable |
|
| Send read receipts to WhatsApp when |
|
| Auto-read incoming messages (senders see blue checkmarks immediately) |
|
| Online presence: |
|
| WhatsApp group created on first connection (empty = disable) |
|
| Default: after |
|
| Default max seconds to wait for link when waiting (15–600) |
|
| Default seconds between connection checks when waiting (2–60) |
|
Variable Details
DATA_ENCRYPTION_KEY — Encrypts sensitive fields (message bodies, sender names, media metadata, approval details) using AES-256-GCM. Store it via docker mcp secret set whatsapp-mcp-docker.data_encryption_key (OS Keychain) or in .env for docker-compose. Generate a strong key: node -e "console.log(require('crypto').randomBytes(32).toString('base64'))". If you lose the key, encrypted data becomes unrecoverable. Running without this key is an insecure mode and should only be done through an explicit operator override with documented risk acceptance.
MESSAGE_RETENTION_DAYS — Runs on startup and then hourly. Deletes messages, associated media files, and expired approvals older than the configured number of days. Set to 0 to disable.
RATE_LIMIT_PER_MIN — Applies to outbound messages (send_message, send_file). Default is 60 (1/sec sustained), comfortable for AI assistant conversations.
DOWNLOAD_RATE_LIMIT_PER_MIN — Applies to media downloads (download_media). Default is 30/min. Authentication attempts are separately limited to 5 per 30 minutes with exponential backoff.
ALLOWED_CONTACTS — Comma-separated E.164 phone numbers (e.g. +15145551234,+353871234567). When set, only these contacts can receive outbound messages.
DISABLED_TOOLS — Comma-separated tool names (e.g. send_file,download_media). Disabled tools return an error when invoked.
SEND_READ_RECEIPTS — When true, calling mark_messages_read sends actual read receipts to WhatsApp (blue double checkmarks visible to senders), in addition to updating the local database. Set to false to only update the local database.
AUTO_READ_RECEIPTS — When true, incoming messages are automatically marked as read on WhatsApp (senders see blue checkmarks immediately). Since the server is an automated agent, this is enabled by default. Set to false to control read receipt timing manually via mark_messages_read.
PRESENCE_MODE — Controls the online/offline status of the linked device. Set to available (default) so the device appears online and delivery receipts (grey double checkmarks) are sent automatically. Set to unavailable to appear offline.
WELCOME_GROUP_NAME — On first connection, the server creates a WhatsApp group with this name and sends a hello message. Set to empty string to disable.
AUTO_CONNECT_ON_STARTUP — When true (default), the server automatically reconnects to WhatsApp at container startup if a valid session exists, without needing to call authenticate. Set to false to start in disconnected mode and connect manually. Note: This variable is not exposed in the Docker MCP Toolkit profile config schema and cannot be set via Docker Desktop UI or docker mcp profile config. Set it via .env or the environment: block in docker-compose.yml only.
AUTH_WAIT_FOR_LINK, AUTH_LINK_TIMEOUT_SEC, AUTH_POLL_INTERVAL_SEC — Defaults for the authenticate tool when the client omits waitForLink, linkTimeoutSec, or pollIntervalSec. In Docker MCP Toolkit they are driven by profile config whatsapp-mcp-docker.auth_wait_for_link, auth_link_timeout_sec, and auth_poll_interval_sec. Tool arguments always override these for that call.
DEBUG — When set to true, emits verbose diagnostic output to stderr. Useful when diagnosing connection or protocol issues. Don't leave it on permanently unless you enjoy reading walls of text.
Data Persistence
Docker MCP Toolkit automatically provisions named volumes for session persistence:
Data | Volume | Mount | Description |
Session + Messages |
|
| WhatsApp session DB, message DB, downloaded media |
Audit |
|
| Audit log SQLite DB |
Session data survives container restarts. Use docker volume rm whatsapp-sessions whatsapp-audit to delete all data.
Data Management
Backup Your Data
Backup WhatsApp sessions and messages:
bash/zsh:
mkdir -p whatsapp-backup
docker run --rm \
-v whatsapp-sessions:/data \
-v $(pwd)/whatsapp-backup:/backup \
alpine tar czf /backup/sessions-$(date +%Y%m%d).tar.gz /data
# Backup audit volume (optional)
docker run --rm \
-v whatsapp-audit:/data \
-v $(pwd)/whatsapp-backup:/backup \
alpine tar czf /backup/audit-$(date +%Y%m%d).tar.gz /dataPowerShell:
New-Item -ItemType Directory -Force -Path whatsapp-backup
$date = Get-Date -Format "yyyyMMdd"
docker run --rm `
-v whatsapp-sessions:/data `
-v "${PWD}\whatsapp-backup:/backup" `
alpine tar czf /backup/sessions-$date.tar.gz /data
# Backup audit volume (optional)
docker run --rm `
-v whatsapp-audit:/data `
-v "${PWD}\whatsapp-backup:/backup" `
alpine tar czf /backup/audit-$date.tar.gz /dataBackup encryption key:
# If using docker mcp secrets, export from OS Keychain manually
# On macOS: security find-generic-password -s "docker-mcp" -a "whatsapp-mcp-docker.data_encryption_key" -w
# On Windows: Stored in Windows Credential Manager (search for "docker/mcp/whatsapp-mcp-docker")
# On Linux: Stored in secret-service (GNOME Keyring or KWallet)
# Save to password manager - DO NOT commit to git!Restore from Backup
bash/zsh:
docker compose down
docker run --rm \
-v whatsapp-sessions:/data \
-v $(pwd)/whatsapp-backup:/backup \
alpine tar xzf /backup/sessions-20260331.tar.gz -C /
docker compose up -dPowerShell:
docker compose down
docker run --rm `
-v whatsapp-sessions:/data `
-v "${PWD}\whatsapp-backup:/backup" `
alpine tar xzf /backup/sessions-20260331.tar.gz -C /
docker compose up -dMigrate to New Host
# On old host: create backup (see above)
# Copy backup files to new host (scp, rsync, etc.)
# On new host:
# 1. Install Docker Desktop and enable MCP Toolkit
# 2. Restore volumes (see above)
# 3. Set encryption key
docker mcp secret set whatsapp-mcp-docker.data_encryption_key
# 4. Register catalog and add to profile
# 5. Start container - session should resume automaticallyDelete All Data
# Stop container and remove volumes
docker compose down -v
# Verify volumes are gone (bash/zsh)
docker volume ls | grep whatsapp
# Verify volumes are gone (PowerShell)
docker volume ls | findstr whatsapp
# Both should return nothingWarning: This permanently deletes all WhatsApp sessions, messages, and audit logs. You'll need to re-authenticate.
Tech Stack
Category | Technology |
Runtime | Node.js 22 (Alpine) |
WhatsApp Protocol | whatsmeow-node (Go binary) |
MCP SDK | @modelcontextprotocol/sdk |
Database | SQLite (better-sqlite3) with FTS5 |
QR Code | qrcode (in-container PNG generation) |
Validation | Zod |
Container | Docker (4-stage, ~80 MB runtime) |
Orchestration | Docker MCP Toolkit + MCP Gateway |
Documentation
docs/API.md — Full MCP tool API reference (all 34 tools)
docs/TROUBLESHOOTING.md — Symptom → cause → fix guide
docs/guides/DEVELOPER.md — Build, test, and deploy procedures
docs/architecture/OVERVIEW.md — Architecture overview
docs/guides/ERRORS.md — Error taxonomy and recovery
docs/testing/TESTING.md — Test strategy and commands
examples/client-configs.md — Manual MCP client config snippets (Cursor, Claude, VS Code, Gemini, Goose, Cline, direct Compose)
recommended-config.yaml — Reference config values for
docker mcp profile configCHANGELOG.md — Release history
PRIVACY.md — Privacy policy and data handling
SECURITY.md — Security policy and vulnerability reporting
CONTRIBUTING.md — Contribution guidelines
CODE_OF_CONDUCT.md — Community standards
Common Pitfalls & Troubleshooting
⚠️ Authentication Issues
Problem: Pairing code returns 400 error
Cause: WhatsApp rate-limits pairing attempts (5 per 30 minutes)
Solution: Wait 10-15 minutes, then retry. The server automatically falls back to QR code.
Prevention: Use QR code authentication if pairing codes frequently fail.
Problem: QR code expired
Cause: QR codes expire in ~20 seconds
Solution: Call
authenticateagain for a fresh QR codePrevention: Have WhatsApp open and ready before calling authenticate
Problem: "Already authenticated" but messages not sending
Cause: Session may have expired (20 days of inactivity) or WhatsApp disconnected
Solution:
Check status:
docker compose logs --tail 50 whatsapp-mcp-dockerLook for "logged_out" or "session expired" messages
Call
authenticateagain to re-link
Problem: Can't scan QR code in time
Cause: QR codes expire quickly and you need to navigate WhatsApp menus
Solution:
Open WhatsApp → Settings → Linked Devices before calling authenticate
Tap "Link a Device" and have the camera ready
Then call
authenticateto generate QR code
Alternative: Use pairing code instead (lasts 60 seconds)
⚠️ Rate Limiting
Problem: "Rate limit exceeded" for messages
Default: 60 messages per minute
Solution: Wait for the window to reset, or adjust
RATE_LIMIT_PER_MINWarning: Sending too many messages too quickly can get your account banned by WhatsApp
Problem: "Authentication cooldown active"
Cause: Failed auth attempts trigger exponential backoff (60s → 120s → 240s → 480s → 900s)
Solution: Wait for the cooldown period to expire
Prevention: Ensure phone number is correct before calling authenticate
⚠️ Session & Data Issues
Problem: Session lost after container restart
Cause: Docker volume not persisting
Check:
docker volume ls | grep whatsapp-sessionsSolution: Ensure
whatsapp-sessionsvolume exists and is mounted
Problem: Messages not appearing in search
Cause: FTS5 index may be out of sync or messages lack text body
Solution:
Check if messages exist: Use
list_messagesfor the chatVerify search query: Try simpler keywords
FTS5 limitation: Media-only messages (no text) aren't searchable
Problem: Media download fails
Cause 1: Media expired on WhatsApp servers (30-day limit)
Cause 2: Message ID invalid or from before metadata tracking
Solution: Download media soon after receiving; old media may be unavailable
⚠️ Contact & Name Resolution
Problem: Wrong contact matched by fuzzy search
Cause: Multiple contacts have similar names
Solution: Use exact JID instead of name:
send_message({ to: "1234567890@s.whatsapp.net", ... })Prevention: Use
search_contactsfirst to find the exact JID
Problem: Contact name shows as phone number
Cause: Name resolution from WhatsApp may take time or fail
Solution: Names are resolved asynchronously; wait for messages to arrive
Note: This is cosmetic; messaging still works with JIDs
⚠️ Backup & Restore
Problem: Need to backup/restore sessions
Backup (bash/zsh):
docker run --rm -v whatsapp-sessions:/data -v $(pwd):/backup alpine \ tar czf /backup/whatsapp-backup.tar.gz /dataBackup (PowerShell):
docker run --rm -v whatsapp-sessions:/data -v "${PWD}:/backup" alpine ` tar czf /backup/whatsapp-backup.tar.gz /dataRestore (bash/zsh):
docker run --rm -v whatsapp-sessions:/data -v $(pwd):/backup alpine \ tar xzf /backup/whatsapp-backup.tar.gz -C /data --strip-components 1Restore (PowerShell):
docker run --rm -v whatsapp-sessions:/data -v "${PWD}:/backup" alpine ` tar xzf /backup/whatsapp-backup.tar.gz -C /data --strip-components 1
📞 Getting Help
If issues persist:
Check logs:
docker compose logs --tail 100 whatsapp-mcp-dockerRun diagnostics:
node scripts/diagnostics.js --verboseSearch issues: GitHub Issues
Report bug: Include logs, Docker version, and steps to reproduce
Testing
Tests run inside Docker via tester-container — no local build tools needed. The npm test scripts are intentionally blocked on the host; use the container's default CMD instead.
# Build the test image (tester-container is behind the 'test' Compose profile)
docker compose --profile test build tester-container
# Run all unit + integration tests (uses container default CMD)
docker compose --profile test run --rm tester-container
# Run a specific test file
docker compose --profile test run --rm tester-container npx tsx --test test/unit/crypto.test.ts
# One-time WhatsApp auth for e2e tests
docker compose --profile test run --rm tester-container npx tsx test/e2e/setup-auth.ts
# Run e2e tests with live session
docker compose --profile test run --rm tester-container npx tsx --test test/e2e/live.test.tsLayer | What's covered |
Unit | phone, fuzzy-match, crypto, file-guard, permissions, audit, store, reconnect, receipts |
Integration | Full MCP protocol round-trip with mock WhatsApp client |
E2E | Live WhatsApp session (read-only, requires auth) |
See docs/guides/DEVELOPER.md for the full testing guide.
Troubleshooting
🔍 Diagnostic Commands
Run the diagnostic script to check system health:
Requires Node.js on the host. If you don't have Node.js installed locally, use the manual diagnostics below instead — the server itself runs Node inside Docker and needs no host installation for normal use.
# Quick status check
node scripts/diagnostics.js
# Verbose output with full logs
node scripts/diagnostics.js --verbose
# JSON output for automation
node scripts/diagnostics.js --jsonManual diagnostics:
# Check if container is running
docker compose ps
# View last 50 lines of logs
docker compose logs --tail 50 whatsapp-mcp-docker
# Check volumes exist (bash/zsh)
docker volume ls | grep whatsapp
# Check volumes exist (PowerShell)
docker volume ls | findstr whatsapp
# Verify encryption key is set (bash/zsh)
docker mcp secret ls | grep whatsapp-mcp-docker
# Verify encryption key is set (PowerShell)
docker mcp secret ls | findstr whatsapp-mcp-docker
# Check catalog registration
docker mcp catalog ls
# List all servers across all profiles
docker mcp profile server ls
# List servers for a specific profile (--profile flag does not exist; use --filter)
docker mcp profile server ls --filter profile=<your-profile>
# Test WhatsApp connection status (from MCP client)
get_connection_statusCommon Pitfalls & Solutions
1. Authentication Issues
Problem: Pairing code returns 400 error or expires
Cause: WhatsApp rate-limits pairing attempts or code expires in 60 seconds
Solution:
Wait 10-15 minutes between attempts if rate-limited
Have WhatsApp mobile app ready before calling
authenticateIf pairing code fails, server automatically falls back to QR code
QR codes expire in ~20 seconds — request a fresh one if expired
Prevention: Open WhatsApp → Settings → Linked Devices → "Link a Device" before calling authenticate, so you're ready to enter the code immediately. Pass waitForLink: true if you want the tool to poll until linked (note: this can exceed tool-call timeouts on some MCP clients — see auth_wait_for_link config).
Problem: "Already authenticated" but messages aren't sending
Cause: Session may be stale or WhatsApp disconnected
Solution:
# Check connection status
get_connection_status
# If disconnected, check logout reason
# If reason is "revoked", "banned", or "unlinked" → re-authenticate
authenticate({ phoneNumber: "+1234567890" })2. Session Expiry
Problem: "WhatsApp not connected" after period of inactivity
Cause: WhatsApp linked device sessions expire after ~20 days of inactivity
Solution:
Call
authenticateagain with the same phone numberSession will resume (no need to re-link if still within 20 days)
If expired, you'll need to re-link with pairing code or QR
Prevention: Send a message or use the server at least once every 2 weeks.
3. Rate Limiting
Problem: "Rate limit exceeded (60 messages/min)"
Cause: WhatsApp may ban accounts that send too many messages too quickly
Solution:
Wait 60 seconds for the rate limit to reset
Reduce message frequency
Increase
RATE_LIMIT_PER_MINonly if you have legitimate high-volume use
Warning: Aggressive messaging can get your WhatsApp account banned.
Problem: "Too many authentication attempts (5 per 30 min)"
Cause: Authentication is limited to 5 attempts per 30 minutes
Solution:
Wait for the cooldown period (exponential backoff: 60s → 120s → 240s → 480s → 900s)
Don't retry immediately after failed attempts
If pairing code fails, wait for the QR code fallback instead of retrying
4. Contact Resolution Issues
Problem: "Could not resolve recipient" or wrong contact matched
Cause: Fuzzy matching found multiple candidates or no matches
Solution:
# Get exact JID from list_chats
list_chats()
# Use JID directly (bypasses fuzzy matching)
send_message({ to: "1234567890@c.us", message: "Hello" })Tip: Contact names may not resolve immediately after first message — wait a few seconds for name resolution.
5. Media Download Failures
Problem: "No media metadata stored for this message"
Cause: Media was received before metadata tracking was enabled, or media expired
Solution:
Media on WhatsApp servers expires after 30 days
Only media received after enabling the server can be downloaded
Check
has_mediaflag inlist_messagesto see if media is available
Problem: "Media storage quota exceeded"
Cause: Total media directory has reached 512 MB limit
Solution:
# Check media directory size
docker compose exec whatsapp-mcp-docker du -sh /data/sessions/media
# Delete old media files manually or wait for auto-purge
# Auto-purge runs hourly if MESSAGE_RETENTION_DAYS > 06. Search Returns No Results
Problem: search_messages finds nothing
Cause:
FTS5 index may not have caught up (delayed indexing)
Messages are encrypted but search index has plaintext
Query syntax error (boolean operators need capitalization)
Solution:
# Try simpler query without operators
search_messages({ query: "hello" }) # Instead of "hello AND world"
# Use quotes for exact phrases
search_messages({ query: "\"exact phrase\"" })
# Check if messages exist
list_messages({ chat: "Contact Name", limit: 10 })7. Container Issues
Problem: Container won't start
Solution:
# Check logs
docker compose logs whatsapp-mcp-docker
# Verify volumes exist
docker volume ls | grep whatsapp
# Rebuild image
docker compose build --no-cache
# Remove and recreate
docker compose down -v
docker compose up -dProblem: High memory usage
Cause: Message history sync loads many messages into memory
Solution:
Set
MESSAGE_RETENTION_DAYSto limit stored messagesUse pagination in
list_messages(limit: 50, page: 0, 1, 2...)Restart container periodically to clear memory
Authentication Fails
If pairing code returns a 400 error, the server automatically falls back to QR code authentication — the QR code is returned directly in the tool response as an image and a data URI (paste the URI into any browser to view it). Check container logs for details: docker compose logs whatsapp-mcp-docker.
Rate Limited (429)
WhatsApp rate-limits pairing attempts. Wait 10-15 minutes before retrying.
Session Expired
WhatsApp sessions expire after ~20 days of inactivity. The server detects this automatically: it sends a notifications/disconnected MCP notification to your client, cleans up the stale session file, and reports the reason in get_connection_status. Call authenticate again to re-link.
For transient disconnects (network blips), the server automatically attempts reconnection after 5 seconds. A 60-second health heartbeat detects silent connection drops. Startup retries 5 times with exponential backoff before giving up.
Container Won't Start
docker compose up -d
docker compose logs -f whatsapp-mcp-dockerLicense
Apache License 2.0 — see LICENSE for details.
Disclaimer
This project is not affiliated with WhatsApp or Meta. WhatsApp does not officially support unofficial API clients. Use at your own risk and in compliance with WhatsApp's Terms of Service.
Contact
AI Authors: Qwen3-Coder-Next • MiniMax-M2.7 • Qwen3.5 • Nemotron-3-Super
Director: Benjamin Alloul — Benjamin.Alloul@gmail.com
Issues: GitHub Issues
Discussions: GitHub Discussions
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Malaccamaxgit/whatsapp-mcp-docker'
If you have feedback or need assistance with the MCP directory API, please join our Discord server