Skip to main content
Glama
prodmeevan

whatsapp-mcp-free

by prodmeevan
README.md
# 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

B3.1/5.0

Scored across 29 tools

Disambiguation3/5

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.

Naming Consistency3/5

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.

Tool Count2/5

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.

Completeness3/5

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.

Maintenance

ActivityMaintained
ResponsivenessNo issues