A Model Context Protocol server for wacrm — the self-hostable WhatsApp CRM. It lets MCP clients (Claude Desktop, Claude Code, Cursor, and others) drive your CRM in natural language:
"How many conversations are still open?" "Find the contact for +1 415 555 0123 and show the last few messages." "Draft and send an order-update template to Jane."
It's a thin wrapper over wacrm's public /api/v1
REST API. All auth, scoping, and rate limiting are enforced by your
wacrm instance — this server just exposes the API as MCP tools.
- A running wacrm instance (your own self-hosted deploy).
- An API key: in the dashboard go to Settings → API keys → New API key and grant only the scopes you need. The key is shown once.
The server reads two required environment variables and two optional write guards:
| Variable | Required | Purpose |
|---|---|---|
WACRM_BASE_URL |
yes | Your instance URL, e.g. https://crm.example.com |
WACRM_API_KEY |
yes | An API key from the dashboard |
WACRM_ENABLE_WRITES |
no | true to expose contact writes + message sending |
WACRM_ENABLE_BROADCASTS |
no | true to expose mass broadcasts (needs WACRM_ENABLE_WRITES) |
Add to your MCP client config (e.g. claude_desktop_config.json, or
.mcp.json for Claude Code):
That configuration is read-only — the safe default. To let the assistant change data or send messages, add the write guards:
"env": {
"WACRM_BASE_URL": "https://crm.example.com",
"WACRM_API_KEY": "wacrm_live_xxxxxxxxxxxxxxxxxxxxxxxx",
"WACRM_ENABLE_WRITES": "true",
"WACRM_ENABLE_BROADCASTS": "true"
}Read tools are always available. Write and broadcast tools appear only when their guard is set.
| Tool | Group | Scope needed | What it does |
|---|---|---|---|
whoami |
read | (any valid key) | Show the account + scopes the key carries |
list_contacts |
read | contacts:read |
List/search contacts (paginated) |
get_contact |
read | contacts:read |
Read one contact |
list_conversations |
read | conversations:read |
List conversations, filter by status/contact |
get_conversation |
read | conversations:read |
Read one conversation |
list_messages |
read | messages:read |
List a conversation's messages |
get_broadcast |
read | broadcasts:send |
Poll a broadcast's delivery status |
send_message |
write | messages:send |
Send a WhatsApp message (text/template/media) |
create_contact |
write | contacts:write |
Create (find-or-create) a contact |
update_contact |
write | contacts:write |
Update a contact / replace its tags |
send_broadcast |
broadcast | broadcasts:send |
Launch a template broadcast (requires confirm) |
Sending WhatsApp messages through an LLM is a real-world side effect, so the server layers three guards:
- Read-only by default. Write and broadcast tools are not even
registered — the model can't see them — unless you opt in via
WACRM_ENABLE_WRITES/WACRM_ENABLE_BROADCASTS. - API-key scopes. Whatever the guards allow, your wacrm instance
still enforces the key's scopes. A call without the right scope
returns a clean
forbiddenerror. Issue a read-only key for a read-only assistant. - Explicit broadcast confirmation.
send_broadcastrefuses to run unless called withconfirm: true, and is markeddestructiveso compliant clients prompt the user first.
npm install
npm run build # compile to dist/
npm run typecheck
npm start # run the compiled server (needs the env vars)Logs go to stderr — stdout is reserved for the MCP protocol.
MIT — same as wacrm.
{ "mcpServers": { "wacrm": { "command": "npx", "args": ["-y", "wacrm-mcp"], "env": { "WACRM_BASE_URL": "https://crm.example.com", "WACRM_API_KEY": "wacrm_live_xxxxxxxxxxxxxxxxxxxxxxxx" } } } }