zapo ships two optional packages aimed purely at development and testing — neither is meant for production:
- MCP server (
@zapo-js/mcp-server) — expose a liveWaClientto an AI agent (Claude Code, Cursor) so it can connect, pair, send, and inspect state interactively. - Fake server (
@zapo-js/fake-server) — an in-process fake WhatsApp Web server that drives the realWaClientend-to-end, so you can test deterministically without touching WhatsApp’s servers.
MCP server
It exposes a liveWaClient instance and the zapo-js module namespace as MCP tools. An LLM agent can then drive end-to-end WhatsApp flows — connect, pair, send, query groups/newsletters, inspect events, walk SQL state — without you writing throwaway scripts.
Tool surface
Each tool inlines its own schema and examples — the agent reads them at runtime rather than memorizing flags.
Install & register
tsx — no build step, and zapo-js resolves straight from src/:
Pairing gotcha
client.connect() blocks until pairing finishes, so always start it without awaiting, then poll the event buffer:
auth_qr string to the user, wait for auth_paired, then continue.
Key environment variables
One
WaClient per process (multi-session needs multiple servers with distinct MCP_AUTH_PATH + MCP_SESSION_ID); no auto-reconnect (call connect again on connection: close); restart soft does not pick up code changes while process_exit + a supervisor does. Full reference: packages/mcp-server/README.md.
Fake server
@zapo-js/fake-server is an in-process fake WhatsApp Web server that drives the real zapo-js WaClient end-to-end — full Noise XX/IK handshake, QR pairing, Signal Protocol (X3DH + Double Ratchet), group SenderKey, media upload/download over self-signed HTTPS, and app-state sync — all without touching WhatsApp’s servers. It powers the library’s own cross-check test suite and benchmarks, and you can use it to test your integration deterministically.
Quick start
chatSocketUrls (point at the fake WebSocket), testHooks.noiseRootCa (trust the fake server’s certificate without bypassing verification — the full cert-chain check still runs), and proxy.mediaUpload / proxy.mediaDownload (route media to the fake HTTPS server).
What it simulates
FakeWaServer— the WebSocket listener, Noise handshake, an IQ router that answers every IQ the lib emits during normal operation (prekey upload/fetch, usync,media-conn, app-state sync, groups, privacy, profile, blocklist, …), plus state registries for peers and groups.FakePeer— a simulated contact with real Signal crypto:peer.sendConversation(text)/peer.sendGroupConversation(groupJid, text)push messages to the client, andpeer.expectMessage()captures and decrypts what the client sends.- Pairing —
server.runPairing(pipeline, { deviceJid }, materialFn)drives the full QR-pairing handshake; afterward the lib reconnects with the IK handshake (capture it viawaitForNextAuthenticatedPipeline()).
Standalone CLI
Run it as a standalone server for manual experiments:Benchmarking
The package ships a messaging profiler (send/recv × 1:1/group) used to track the library’s performance, plus focused scenario suites for connect lifecycle, history sync, bulk usync, group provisioning, media upload, receipts flood, reconnect/resume, app-state, media-on-the-wire, and the Signal retry round-trip:bench:media:messaging sweeps every media type (image / video / audio / ptt / document / sticker) across 1:1 send, group fan-out (SKDM + SKMSG), and receive + download. It defaults to streaming input (Readable.from(...)) so the lib walks its streaming-upload path; switch to in-memory mode with ZAPO_BENCH_MEDIA_INPUT=buffer to A/B.
bench:retry validates the full retry round-trip against wa-web’s reference parser: incoming retry, recovery, and outbound retry replay after the peer rotates its prekey bundle.
Tune the workload with ZAPO_BENCH_* env vars (ZAPO_BENCH_CONTACTS, ZAPO_BENCH_GROUP_MEMBERS, ZAPO_BENCH_MESSAGES, ZAPO_BENCH_SCENARIOS, …) and add --cpu / --heap / --separate-process for profiles. With --separate-process, the bench drives the fake server in a child process over an RPC bridge and emits a matching server-side CPU profile and heap snapshot alongside the lib-side ones.
Pick a store backend with ZAPO_BENCH_STORE (memory, sqlite, postgres, mysql, redis, or mongo) — the same ZAPO_TEST_* connection env vars as the cross-store test harness apply. To sweep every bench across multiple stores in one shot:
--start-docker to bring up the bundled Postgres/MySQL/Redis/Mongo services on ephemeral ports and tear them down at the end. See packages/fake-server/README.md for the full flag reference.
bench:all-stores only sweeps the eight scenario suites (connect-lifecycle, history-sync, bulk-usync, group-provision, media-upload, receipts-flood, reconnect-resume, appstate) plus messaging. The newer bench:media:messaging and bench:retry aren’t in its --benches= set yet; run them directly when you need them.The fake server is an in-process testing harness, not a runtime you deploy. Pair it with the memory store for fast, isolated tests that reset on every run.
