wamcp
wamcp is a WhatsApp MCP server that connects AI agents to WhatsApp through the Model Context Protocol, exposing 61 tools, 10 resources, and 12 real-time events that agents discover automatically on connect. It supports both Baileys (WhatsApp Web) and the Meta Cloud API behind a single interface, so the same agent code works against either backend. It's built for developers wiring WhatsApp into MCP-compatible frameworks like Claude, LangChain, or Google ADK without writing REST wrappers or webhook parsers. Written in TypeScript with Docker deployment and Redis-backed rate limiting to keep high-volume messaging within WhatsApp's limits.
Features
Transports
Agent ──MCP (Streamable HTTP | stdio)──▶ wamcp ──▶ Baileys / Cloud API ──▶ WhatsApp
Backend selection
Tool surface at a glance
wa_* tools grouped by domain:
• Messaging • Chats • Groups
• Contacts • Profile • Presence
• Media • Reactions • Polls
• ... (61 tools total)
- Agent-first design — every capability is a discoverable MCP tool or resource, not a hand-rolled REST wrapper.
- Live by default — 12 real-time events keep agent state in sync without polling.
- One interface, two channels — swap Baileys for Cloud API without rewriting agent logic.
How it works
wamcp sits between your AI agent and WhatsApp as a single MCP endpoint. Your agent speaks the Model Context Protocol — either over Streamable HTTP or over stdio — and the server does the rest: it manages the WhatsApp session, queues outgoing sends, persists what it sees, and pushes real-time signals back to the agent as they arrive.
┌──────────────┐ MCP (HTTP / stdio) ┌───────────┐ Baileys ┌────────────┐
│ AI Agent │ ◄────────────────────► │ wamcp │ ◄────────► │ WhatsApp │
│ (Claude, ...)│ tools / resources │ server │ Cloud API│ (anything) │
└──────────────┘ events / SSE └─────┬─────┘ └────────────┘
│
┌──────┴──────┐
│ Storage │
│ (sessions, │
│ messages) │
└─────────────┘
1. The agent connects
wamcp presents itself as an MCP server. On connect, the client discovers the full surface automatically:
No generated client library, no endpoint mapping. The agent asks what's available and gets the catalog.
2. Channel selection
wamcp supports two WhatsApp backends behind one interface. Pick the one that fits your deployment:
Both are driven through the same wa_* tool names, so an agent's tool calls stay stable when you switch channels. Where a capability exists only on one channel (e.g. QR linking on Baileys), the other channel returns a clear unsupported-operation error rather than failing silently.
3. A tool call travels through the stack
Agent calls wa_send_text({ chatId, text })
│
▼
┌─────────────────┐ validate input against the tool schema
│ MCP handler │
└────────┬────────┘
▼
┌─────────────────┐ authenticate + normalize to a channel-neutral form
│ Channel layer │
└────────┬────────┘
▼
┌─────────────────┐ enqueue the outbound action (rate-limited)
│ Send queue │
└────────┬────────┘
▼
┌─────────────────┐ deliver via Baileys or Cloud API
│ WhatsApp │
└────────┬────────┘
▼
response returned to agent (delivery status, message ID, ...)
Outgoing messages go through a queue so bursts are throttled to safe rates instead of tripping WhatsApp's abuse detection. The agent gets back a structured result — not a fire-and-forget acknowledgment.
4. Inbound messages and events
When something happens on the WhatsApp side, wamcp turns it into one of two things for the agent:
- Persisted state — messages, contacts, and group metadata are written to local storage so later reads (
wa_get_messages,wa_search_messages, resource reads) return real history rather than requiring a round trip to WhatsApp. - A real-time event — emitted over the MCP connection so the agent can react immediately without polling.
Incoming audio can optionally be transcribed, and outgoing voice notes can optionally be synthesized, both gated behind configuration so the default path stays dependency-light.
5. One server, many instances
A single wamcp process can host multiple WhatsApp instances — separate numbers or separate channels — each with its own session and its own state. Every tool and resource takes an instance identifier (implicit or explicit depending on call shape), so your agent manages them all through the same connection.
Transport and lifecycle
Sessions are durable: Baileys credentials persist across restarts, so a reconnecting instance resumes without re-pairing. When the WhatsApp connection drops, the server reconnects with exponential backoff on its own — the agent only needs to listen for connection events if it wants to surface them to the user.
Configuration
WA MCP is configured through environment variables, a JSON config file passed via WA_CONFIG_FILE, or CLI flags. Environment variables take precedence over the config file, and CLI flags take precedence over both. For the complete list of supported keys, see the API reference.
Configuration sources
Core variables
Channel backend
Select the backend used to talk to WhatsApp. Both backends expose the same MCP tool surface.
Multi-instance
Instances are created at runtime with wa_create_instance. This setting only caps how many can coexist.
Per-instance credentials and channel selection can also be supplied in the config file:
{
"instances": [
{
"id": "support",
"channel": "baileys"
},
{
"id": "sales",
"channel": "cloud",
"cloud": {
"phoneNumberId": "env:WA_SALES_PHONE_NUMBER_ID",
"wabaId": "env:WA_SALES_WABA_ID",
"accessToken": "env:WA_SALES_ACCESS_TOKEN"
}
}
]
}
Values of the form env:NAME are resolved from the process environment at startup, so secrets do not have to live in the JSON file.
Rate limiting
Outbound messaging is queued through BullMQ to reduce ban risk. Tune the limits if your workload is well below the defaults.
Gated writes
Some tools mutate WhatsApp app state (labels, communities, newsletters, catalog, certain privacy settings). These are disabled unless explicitly enabled.
Audio transcription (optional)
Text-to-speech (optional)
Real-time events
Example .env
WA_TRANSPORT=http
WA_HOST=0.0.0.0
WA_PORT=3000
WA_REDIS_URL=redis://redis:6379
WA_DB_PATH=/data/wamcp.db
WA_DATA_DIR=/data
WA_CHANNEL=baileys
WA_MAX_INSTANCES=5
WA_RATE_LIMIT_BAILEYS_PER_MIN=20
WA_RATE_LIMIT_CLOUD_PER_MIN=80
WA_APP_STATE_WRITES_ENABLED=false
WA_LOG_LEVEL=info
Claude Desktop (stdio)
When running under stdio, the same variables are passed through the client config; WA_TRANSPORT must be stdio.
{
"mcpServers": {
"wamcp": {
"command": "node",
"args": ["/path/to/wamcp/dist/index.js"],
"env": {
"WA_TRANSPORT": "stdio",
"WA_REDIS_URL": "redis://localhost:6379",
"WA_DB_PATH": "/path/to/wamcp/data/wamcp.db"
}
}
}
}
Notes
- Changing
WA_CHANNELafter instances exist does not migrate them; create new instances under the desired backend. WA_DB_PATHandWA_SESSION_DIRmust be writable by the server process. In Docker, mount them under/dataso state survives container restarts.WA_TOOL_ALLOWLISTandWA_TOOL_DENYLISTare applied at startup; restart the server after changing them.
Compatibility
MCP protocol & transports
Clients that implement the Model Context Protocol can discover the server's tools, resources, and notifications without a REST wrapper or custom glue code.
WhatsApp backends
The two backends share a single tool interface, so an agent can switch channels by changing configuration rather than tool names.
Runtime & deployment
Agent frameworks
Tested against MCP-compatible clients and frameworks, including:
- Claude (via MCP configuration)
- Google ADK (Python,
McpToolset) - LangChain (Python,
McpToolkit) - Any other client that speaks MCP over Streamable HTTP or stdio
Feature availability by channel
Gated write operations require WA_APP_STATE_WRITES_ENABLED=true; when disabled, the affected tools return an explicit error while read operations and non-gated writes continue to work.
Compatibility notes
- Baileys behavior tracks the upstream WhatsApp Web protocol; features marked Baileys-only in the tool reference are not emulated on Cloud API.
- Cloud API requires valid Meta credentials; instances return authentication errors until credentials are set.
- Multi-instance deployments support multiple numbers from one server, each with an independent channel and session.
- Rate limits differ by channel (per-minute message caps) and are enforced by the queue layer rather than by the agent.
- Node.js versions below the stated minimum are unsupported.
FAQ
How is this different from using the WhatsApp Business API directly?
The Cloud API is a REST interface: you get HTTP endpoints, webhooks, and you write the glue. This server exposes WhatsApp through the Model Context Protocol, so an agent discovers tools, resources, and events at connect time instead of being hand-wired to endpoints. Baileys support means you can also run against WhatsApp Web without a Meta business account.
Do I need a Meta Business account?
Only for the Cloud API channel. The Baileys channel links a regular WhatsApp account by QR code or pairing code and needs no Meta onboarding. Which channel an instance uses is decided when you create it.
Can I run multiple WhatsApp numbers at once?
Yes. Instances are independent — each has its own session, credentials, and connection state. Use wa_get_instance_status with no instance to list them all, or with an instanceId for one.
Where is session data stored?
Sessions, messages, contacts, and groups live in SQLite. Redis is used for the BullMQ send queues and rate limiting; it is not the source of truth for message history. Back up the SQLite file if you care about retained history.
Why are my messages being queued instead of sent immediately?
Sends are rate limited to avoid account bans — 20 msg/min on Baileys, 80 msg/min on Cloud API. When you exceed the budget, messages wait in the BullMQ queue and drain as capacity frees up. Check the queue backing up before assuming a send failed.
A tool returned "unsupported operation" — why?
Some operations exist only on one channel. Contact resync, privacy settings, presence, polls results, and most gated writes are Baileys-only; buttons and lists are Cloud-API-only with text fallbacks on Baileys. The error names the channel mismatch. See the tool tables for per-tool availability.
What does "gated write" mean in the tool list?
The operation is implemented but disabled by default because it mutates WhatsApp app-state or has a higher ban risk. Enable it deliberately with WA_APP_STATE_WRITES_ENABLED=true. Reads and ordinary messaging are unaffected.
How do real-time events reach my agent?
Over SSE via the MCP notification channel, plus optional outgoing webhooks. Events cover incoming messages, typing, group changes, calls, and connection status. No polling loop is needed — subscribe and react.
My instance keeps disconnecting.
Baileys sessions drop when the linked phone goes offline for long periods, when WhatsApp invalidates the session, or on protocol drift in the Baileys dependency. The server reconnects with exponential backoff. If it exhausts retries, call wa_restart_instance and re-pair if wa_get_qr_code returns a fresh code.
Can an agent send media it received earlier?
Yes. wa_download_media saves received media to disk or returns base64, and the send tools accept local paths or base64 input. Nothing is re-uploaded through a third party.
Does the server read my messages?
No. Everything runs in your process against your own Redis and SQLite. Message content is only sent upstream to WhatsApp, and to your configured transcription or TTS provider if you enable those optional features.
How do I report a bug or request a tool?
Open an issue with the tool name, the channel (Baileys or Cloud), and the input you used. Redact phone numbers and message content. Feature requests for new tools are welcome — include the underlying WhatsApp operation you need.
License
This project is released under the MIT License. See the LICENSE file for the full text.
In short, the MIT License permits you to:
- Use the software for any purpose, including commercial applications
- Modify the source code to suit your needs
- Distribute copies of the original or modified software
- Sublicense and incorporate it into larger works
- Publish without an obligation to open-source your own modifications
The only requirements are that the copyright notice and permission notice be included in all copies or substantial portions of the software, and that the software is provided "as is", without warranty of any kind, express or implied.
Third-party components
wamcp builds on upstream libraries and services that carry their own licenses and terms of service. Notable dependencies include:
Refer to each project's repository for the authoritative license text and version-specific terms. Using this software does not grant any rights to WhatsApp, Meta, or their trademarks; see the relevant sections of this repository for usage disclaimers.
Attribution
If you build on wamcp, a link back to this repository is appreciated but not required by the license.