whatsapp-mcp-free
# whatsapp-mcp-free
Free WhatsApp MCP server for CLI AI agents — **no official API key needed**.
Built on [`@whiskeysockets/baileys`](https://github.com/WhiskeySockets/Baileys) (WhatsApp Web multi-device protocol).
Works with **any MCP-compatible AI CLI**: opencode, Claude Code, Codex, Cursor,
Qwen Code, Gemini CLI, Cline, Roo Code — stdio (default) or streamable HTTP.
Self-tested: standard `initialize` → `tools/list` (29 tools) → `tools/call`.
> ⚠️ Unofficial API. WhatsApp may ban numbers using unofficial clients.
> Use a **secondary number** first, send slowly (2s+ gap), avoid broadcasts.
> One WA session = one process. Never run two clients/bots on the same AUTH_DIR.
## Quick start
```bash
npm install
npm run build
npm start # prints QR to terminal (stderr)
```
1. Scan the QR with **WhatsApp > Settings > Linked Devices > Link a Device**
2. Auth saves to `./wa-auth/` (gitignored) — next starts need no QR
3. Wire it to your agent (below), then ask: *"check WhatsApp connection status"*
## Use with opencode
`~/.config/opencode/opencode.jsonc` (global) or project `opencode.json`:
```json
{
"mcp": {
"whatsapp-free": {
"type": "local",
"command": ["node", "E:/Personal/Coding/whatsapp-mcp-free/dist/index.js"],
"cwd": "E:/Personal/Coding/whatsapp-mcp-free",
"environment": {
"WHATSAPP_AUTH_DIR": "E:/Personal/Coding/whatsapp-mcp-free/wa-auth",
"WHATSAPP_AI_ENABLED": "1",
"WHATSAPP_AI_PREFIX": "/Wa.p",
"WHATSAPP_AI_COOLDOWN_S": "10",
"WHATSAPP_AI_ALLOW": "",
"WHATSAPP_AI_REACT_QUEUE": "👀",
"WHATSAPP_AI_REACT_DONE": "✅"
},
"enabled": true,
"timeout": 60000
}
}
}
```
> Wajib: `cwd` + `WHATSAPP_AUTH_DIR` absolut dan sama antara manual vs MCP.
> Tanpa ini MCP bikin sesi baru di folder lain (gejala: `connected:false`, `hasQr:true` terus).
Restart opencode after editing. First start prints the QR in opencode's MCP logs / terminal — scan within ~60s.
## Setup pertama kali (orang baru)
1. **Syarat**: Node.js ≥ 20, nomor WA kedua (jangan nomor utama — risiko ban), HP + laptop satu jaringan tidak wajib tapi HP harus online.
2. **Install & login manual** (sekali saja, untuk scan QR):
```bash
cd E:/Personal/Coding/whatsapp-mcp-free
npm install
npm run build
npm start
```
Scan QR di terminal via **WhatsApp > Linked Devices > Link a Device** (≤ 60 dtk).
Sukses ditandai `[whatsapp] connected`. Matikan dengan `Ctrl+C`.
3. **Pasang ke opencode**: copy blok JSON di atas ke `opencode.jsonc`, sesuaikan path.
4. **Restart opencode total**, lalu verifikasi dari chat agent:
- `ping` → harus `pong:true`
- `doctor` → `ok:true`, `connected:true`, `credsExists:true`
- `list_chats` → chat mulai muncul setelah ada pesan masuk
5. **Tes AI inbox**: dari WA kirim `/Wa.p halo`, lalu minta agent `cek ai_inbox` → jawab via `ai_reply confirm=true`.
6. **Jangan** jalankan `npm start` manual barengan dengan opencode (sesi rebutan → disconnect bolak-balik). Satu proses saja.
7. **Opsional**: isi `WHATSAPP_AI_ALLOW` dengan nomor full-akses (`62812..,62897..`), kosong = semua boleh.
## HTTP mode (one server, many clients)
```bash
WHATSAPP_MCP_TRANSPORT=http WHATSAPP_HTTP_HOST=127.0.0.1 WHATSAPP_HTTP_PORT=8787 WHATSAPP_HTTP_PATH=/mcp npm start
```
- MCP endpoint: `http://127.0.0.1:8787/mcp`
- Health: `http://127.0.0.1:8787/health`
- Codex: `codex mcp add whatsapp --url http://127.0.0.1:8787/mcp`
## Semua AI CLI (kompatibilitas)
Server ini MCP standar (stdio JSON-RPC di stdin/stdout, log+QR hanya ke stderr).
Semua pola di bawah memakai binary + auth yang sama — pilih SATU client aktif
dalam satu waktu per AUTH_DIR.
- **opencode** (`opencode.jsonc`, lihat blok lengkap di atas).
- **Claude Code**: `claude mcp add whatsapp-free --cwd E:/Personal/Coding/whatsapp-mcp-free -e WHATSAPP_AUTH_DIR=E:/Personal/Coding/whatsapp-mcp-free/wa-auth -- node E:/Personal/Coding/whatsapp-mcp-free/dist/index.js`
- **Codex**: `codex mcp add whatsapp-free --cwd E:/Personal/Coding/whatsapp-mcp-free --env WHATSAPP_AUTH_DIR=E:/Personal/Coding/whatsapp-mcp-free/wa-auth -- node E:/Personal/Coding/whatsapp-mcp-free/dist/index.js`
- **Cursor** (`.cursor/mcp.json`): `{ "mcpServers": { "whatsapp-free": { "command": "node", "args": ["E:/Personal/Coding/whatsapp-mcp-free/dist/index.js"], "cwd": "E:/Personal/Coding/whatsapp-mcp-free", "env": { "WHATSAPP_AUTH_DIR": "E:/Personal/Coding/whatsapp-mcp-free/wa-auth" } } } }`
- **Qwen Code / Gemini CLI** (`~/.qwen/settings.json` atau `~/.gemini/settings.json`): `qwen mcp add -s user -e WHATSAPP_AUTH_DIR=E:/Personal/Coding/whatsapp-mcp-free/wa-auth --timeout 60000 whatsapp-free node E:/Personal/Coding/whatsapp-mcp-free/dist/index.js`
- **HTTP (client apa pun)**: jalankan server sekali (lihat HTTP mode), lalu daftarkan URL `/mcp`-nya di client masing-masing — cocok untuk banyak client tanpa rebutan sesi.
## Cara kerja (teks)
```text
HP (WhatsApp) SERVER whatsapp-mcp-free AI CLI (opencode/claude/codex/qwen/...)
============= ======================== =========================================
(1) client spawn via stdio:
node dist/index.js
+ env WHATSAPP_AUTH_DIR
(2) QR sekali saat <---- stdout: JSON-RPC MCP (29 tools)
pertama: stderr: QR + log (tidak ganggu MCP)
Linked Devices
scan QR
\____________________ Baileys socket ____________________/
\/ (WA Web protocol, 1 sesi)
wa-auth/ <-- creds.json, keys, lid-mapping
+
store.json <-- chats, pesan, kontak, antrean AI
BACA (tidak perlu konek ulang, dari cache + live bila perlu):
<------ list_chats / list_groups / list_newsletters (nama live)
<------ list_messages / search_messages / search_contacts / resolve_lid
<------ list_status / fetch_status_text / group_metadata / newsletter_metadata
TULIS (semua confirm=true, jeda 2 dtk anti-ban):
------> send_message / send_file / post_status / delete_status
------> group_leave / newsletter_follow|unfollow|mute ------> WA
AI INBOX /Wa.p (MCP tidak bisa push -> agent POLL tiap giliran):
user ketik: /Wa.p tolong rangkum ini
----> socket tangkap -> cek ALLOW -> react 👀 -> antre di store
agent: ai_inbox (lihat antrean) -> mikir (boleh baca chat dulu)
-> ai_reply confirm=true -> terkirim ke chat asal + react ✅
bukan ALLOW: tetap tersimpan sebagai chat biasa, tanpa antre/balas
DIAGNOSTIK: ping (pong+jam) | doctor (creds/store/versi/antrean) | help (panduan)
connection_status | auth_qr
```
## Tools (v0.7)
| Tool | What it does |
|---|---|
| `connection_status` | connected? logged-in JID? |
| `auth_qr` | latest pairing QR text |
| `list_chats` | recent chats |
| `list_groups` | groups only (cache) |
| `group_list_live` | all participating groups with live subject/size |
| `group_metadata` | one group: subject, participants, admins |
| `group_leave` | leave a group (**needs `confirm=true`**) |
| `list_newsletters` | followed channels with live names |
| `newsletter_metadata` | one channel: name, desc, subscribers |
| `newsletter_follow` / `newsletter_unfollow` | follow/unfollow (**needs `confirm=true`**) |
| `newsletter_mute` | mute/unmute channel (**needs `confirm=true`**) |
| `list_messages` | history of one chat |
| `search_messages` | substring search in cache |
| `search_contacts` | find by name/phone (+pn bila LID) |
| `resolve_lid` | ubah LID acak jadi nowa + nama |
| `fetch_status_text` | contact About text |
| `list_status` | cached Status/stories |
| `post_status` | buat Status teks/media (**needs `confirm=true`**) |
| `delete_status` | hapus Status sendiri (**needs `confirm=true`**) |
| `ai_config` | config prefix AI + antrean |
| `ai_inbox` | antrean `/Wa.p` untuk dijawab agent |
| `ai_reply` | jawab antrean + kirim ke chat asal (**needs `confirm=true`**) |
| `ai_clear` | bersihkan antrean (**needs `confirm=true`**) |
| `ping` | pong + jam server + status koneksi |
| `doctor` | diagnostik: creds, store, versi, antrean |
| `help` | panduan pakai + troubleshooting |
| `send_message` | send text (**needs `confirm=true`**) |
| `send_file` | send local file (**needs `confirm=true`**) |
## AI inbox: `/Wa.p` (v0.7)
Nomor full-akses di WA ketik:
```text
/Wa.p tolong rangkum chat ini
```
- Nomor di `WHATSAPP_AI_ALLOW` = full akses: pesan di-react 👀, masuk antrean, dijawab agent (react ✅ habis `ai_reply`)
- Nomor lain = chat biasa: tetap tersimpan, tanpa antre, tanpa auto-balas
- `WHATSAPP_AI_ALLOW` kosong = semua chat boleh (mode lama)
Alur agent per giliran:
1. `ai_inbox` → ambil prompt belum terjawab
2. Jawab dengan pengetahuan + `list_messages`/`search` bila perlu
3. `ai_reply` dengan `confirm=true` → terkirim ke chat asal + `answered` + react ✅
4. Jeda 2 dtk antar kirim (anti-ban)
Config (env):
| Var | Default | Meaning |
|---|---|---|
| `WHATSAPP_AI_ENABLED` | `1` | `0` = matikan antrean |
| `WHATSAPP_AI_PREFIX` | `/Wa.p` | prefix pemicu (case-insensitive) |
| `WHATSAPP_AI_COOLDOWN_S` | `10` | cooldown per pengirim |
| `WHATSAPP_AI_MAXLEN` | `2000` | potong prompt |
| `WHATSAPP_AI_ALLOW` | _(kosong)_ | `62812..,62897..` full akses; kosong = semua boleh |
| `WHATSAPP_AI_REACT_QUEUE` | `👀` | react saat antre; kosong = mati |
| `WHATSAPP_AI_REACT_DONE` | `✅` | react habis jawab; kosong = mati |
Destructive sends require `confirm=true` so agents don't fire accidentally.
## Config (env)
| Var | Default | Meaning |
|---|---|---|
| `WHATSAPP_AUTH_DIR` | `./wa-auth` | Baileys auth + store cache |
| `WHATSAPP_MCP_TRANSPORT` | `stdio` | `stdio` or `http` |
| `WHATSAPP_HTTP_HOST` | `127.0.0.1` | http bind |
| `WHATSAPP_HTTP_PORT` | `8787` | http port |
| `WHATSAPP_HTTP_PATH` | `/mcp` | MCP endpoint |
| `WA_LOG_LEVEL` | `warn` | `debug` for Baileys logs |
## Roadmap
- `download_media` + voice-note transcribe (Whisper-compatible endpoint)
- `sync_contacts` from VCF
- Rate-limit / anti-ban queue
- SQLite store option (currently JSON file)
## Dev
```bash
npm run dev # tsx hot run
npm run build # tsc -> dist/
```
Requires `@whiskeysockets/baileys@^7.0.0-rc.9` or later for QR pairing.
## License
MIT — see `LICENSE`. Contributions welcome (`CONTRIBUTING.md`).
TDQS
Scored across 29 tools
Most tools target distinct resources and actions, but there is clear overlap among connection_status, ping, and doctor, as well as between list_groups and group_list_live. Descriptions help somewhat, but an agent could easily pick the wrong diagnostic or group-list tool.
Names are mostly snake_case, but patterns are mixed: list_chats and list_groups coexist with group_list_live, while bare names like ping, doctor, and help break the verb_noun style. It remains readable, but the naming convention is not consistently applied.
At 29 tools, the surface is above the 25+ threshold and feels heavy for a WhatsApp MCP, especially with several overlapping health-check and group-list utilities. A more focused set could cover the same workflows with fewer near-duplicate tools.
The server covers connection, messaging, groups, newsletters, status, and AI queue workflows, but notable lifecycle operations are missing: no group creation or participant management, no message edit/delete, and no read/seen actions. Agents can work around some gaps, but create/get without update/delete leaves dead ends.