whazaa 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Matthias Nott
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,204 @@
1
+ # Whazaa
2
+
3
+ WhatsApp MCP server for Claude Code — bidirectional self-chat messaging.
4
+
5
+ You message yourself on WhatsApp, Claude receives it. Claude responds, you see it on WhatsApp. Your phone becomes a parallel terminal.
6
+
7
+ ---
8
+
9
+ ## Features
10
+
11
+ - **Bidirectional messaging** — send from Claude, receive from your phone
12
+ - **Zero configuration** — auto-detects your phone number after first scan
13
+ - **First-run QR pairing** — scan once, connects automatically thereafter
14
+ - **Markdown support** — `**bold**`, `*italic*`, `` `code` `` converted to WhatsApp format
15
+ - **Deduplication** — outgoing messages never echo back as incoming
16
+ - **Exponential backoff** — reconnects automatically (1s to 60s)
17
+ - **MCP-safe** — all output except JSON-RPC goes to stderr
18
+
19
+ ---
20
+
21
+ ## Quick Start
22
+
23
+ ### Option 1: Run directly with npx / bunx
24
+
25
+ No installation required:
26
+
27
+ ```bash
28
+ npx whazaa
29
+ ```
30
+
31
+ or with Bun:
32
+
33
+ ```bash
34
+ bunx whazaa
35
+ ```
36
+
37
+ The first run prints a QR code to your terminal. Scan it with WhatsApp (Settings -> Linked Devices -> Link a Device). Credentials are saved to `~/.whazaa/auth/` and all subsequent runs connect automatically.
38
+
39
+ ### Option 2: Install globally
40
+
41
+ ```bash
42
+ npm install -g whazaa
43
+ whazaa
44
+ ```
45
+
46
+ ### Option 3: Build from source
47
+
48
+ ```bash
49
+ git clone https://github.com/mnott/Whazaa.git
50
+ cd whazaa
51
+ npm install
52
+ npm run build
53
+ node dist/index.js
54
+ ```
55
+
56
+ ---
57
+
58
+ ## Claude Code MCP Configuration
59
+
60
+ Add Whazaa to `~/.claude/.mcp.json` (or your project's `.mcp.json`):
61
+
62
+ ### Using npx (always latest version)
63
+
64
+ ```json
65
+ {
66
+ "mcpServers": {
67
+ "whazaa": {
68
+ "command": "npx",
69
+ "args": ["whazaa"],
70
+ "description": "Whazaa — WhatsApp self-chat MCP server for Claude Code"
71
+ }
72
+ }
73
+ }
74
+ ```
75
+
76
+ ### Using bunx
77
+
78
+ ```json
79
+ {
80
+ "mcpServers": {
81
+ "whazaa": {
82
+ "command": "bunx",
83
+ "args": ["whazaa"],
84
+ "description": "Whazaa — WhatsApp self-chat MCP server for Claude Code"
85
+ }
86
+ }
87
+ }
88
+ ```
89
+
90
+ ### Using a local build
91
+
92
+ ```json
93
+ {
94
+ "mcpServers": {
95
+ "whazaa": {
96
+ "command": "node",
97
+ "args": ["/path/to/whazaa/dist/index.js"],
98
+ "description": "Whazaa — WhatsApp self-chat MCP server for Claude Code"
99
+ }
100
+ }
101
+ }
102
+ ```
103
+
104
+ After updating the MCP config, restart Claude Code. On first run, Whazaa prints a QR code to the Claude Code logs (check Settings -> Developer -> MCP Logs or run it manually from a terminal first to complete pairing).
105
+
106
+ ---
107
+
108
+ ## Available Tools
109
+
110
+ | Tool | Description |
111
+ |------|-------------|
112
+ | `whatsapp_status` | Report connection state and phone number |
113
+ | `whatsapp_send` | Send a message to your own WhatsApp self-chat |
114
+ | `whatsapp_receive` | Drain queued incoming messages from your phone |
115
+ | `whatsapp_login` | Trigger a new QR pairing flow |
116
+
117
+ ---
118
+
119
+ ## How It Works
120
+
121
+ Whazaa uses the [Baileys](https://github.com/WhiskeySockets/Baileys) library to maintain a persistent WebSocket connection to WhatsApp's servers using the same multi-device protocol as WhatsApp Web. It exposes four MCP tools over stdin/stdout and routes all Baileys output to stderr to keep the JSON-RPC stream clean. Incoming messages from your phone are queued in memory and returned when `whatsapp_receive` is called.
122
+
123
+ ---
124
+
125
+ ## Environment Variables
126
+
127
+ | Variable | Default | Description |
128
+ |----------|---------|-------------|
129
+ | `WHAZAA_AUTH_DIR` | `~/.whazaa/auth/` | Directory for WhatsApp session credentials |
130
+
131
+ ### Example: custom auth directory
132
+
133
+ ```json
134
+ {
135
+ "mcpServers": {
136
+ "whazaa": {
137
+ "command": "node",
138
+ "args": ["/path/to/whazaa/dist/index.js"],
139
+ "env": {
140
+ "WHAZAA_AUTH_DIR": "/custom/path/whatsapp-creds"
141
+ }
142
+ }
143
+ }
144
+ }
145
+ ```
146
+
147
+ ---
148
+
149
+ ## First-Time Pairing
150
+
151
+ 1. Run Whazaa from a terminal so you can see the QR code:
152
+ ```bash
153
+ npx whazaa
154
+ ```
155
+
156
+ 2. A QR code prints on stderr. Open WhatsApp on your phone:
157
+ - iOS: Settings -> Linked Devices -> Link a Device
158
+ - Android: Menu (three dots) -> Linked Devices -> Link a Device
159
+
160
+ 3. Scan the QR code. Whazaa logs `Connected. Phone: +XXXXXXXXXXX`.
161
+
162
+ 4. Add the MCP config to Claude Code. Credentials are now saved; subsequent connections are automatic.
163
+
164
+ ---
165
+
166
+ ## Troubleshooting
167
+
168
+ **QR code not appearing**
169
+
170
+ Run Whazaa directly from a terminal (`npx whazaa`) rather than from within Claude Code's MCP runner, which may not show stderr. Once paired, restart Claude Code.
171
+
172
+ **"Logged out (401)" error**
173
+
174
+ Your session was invalidated (e.g. you unlinked the device in WhatsApp). Use the `whatsapp_login` tool or delete `~/.whazaa/auth/` and restart Whazaa to re-pair.
175
+
176
+ **Messages not received**
177
+
178
+ Call `whatsapp_receive` to drain the queue. Only messages sent to your own number (the self-chat / "Saved Messages" chat) are captured.
179
+
180
+ **Connection keeps dropping**
181
+
182
+ Whazaa uses exponential backoff to reconnect automatically. Check your network connection. If the problem persists, use `whatsapp_login` to re-establish the session.
183
+
184
+ **Multiple WhatsApp accounts**
185
+
186
+ Set `WHAZAA_AUTH_DIR` to a different directory for each account and run separate instances.
187
+
188
+ ---
189
+
190
+ ## Security Notes
191
+
192
+ - Session credentials are stored locally in `~/.whazaa/auth/`. Treat them like passwords.
193
+ - Whazaa only reads and sends messages in your self-chat. It does not have access to other conversations.
194
+ - No data is sent to any third-party service. The connection is directly to WhatsApp's servers via Baileys.
195
+
196
+ ---
197
+
198
+ ## License
199
+
200
+ MIT — see [LICENSE](LICENSE)
201
+
202
+ ## Author
203
+
204
+ Matthias Nott — [github.com/mnott](https://github.com/mnott)
package/dist/auth.d.ts ADDED
@@ -0,0 +1,31 @@
1
+ /**
2
+ * auth.ts — Auth directory resolution and QR code display helper
3
+ *
4
+ * Whazaa stores session credentials in ~/.whazaa/auth/ by default.
5
+ * Override with WHAZAA_AUTH_DIR environment variable.
6
+ *
7
+ * QR codes are printed to stderr so they never pollute MCP's JSON-RPC
8
+ * stream on stdout.
9
+ */
10
+ /**
11
+ * Resolve the auth directory, with the following priority:
12
+ * 1. WHAZAA_AUTH_DIR environment variable
13
+ * 2. ~/.whazaa/auth/ (default)
14
+ *
15
+ * Creates the directory if it does not exist.
16
+ */
17
+ export declare function resolveAuthDir(): string;
18
+ /**
19
+ * Return true if an existing auth session appears to be present.
20
+ * Baileys writes creds.json when credentials are saved.
21
+ */
22
+ export declare function hasExistingSession(authDir: string): boolean;
23
+ /**
24
+ * Print a QR code to stderr.
25
+ *
26
+ * Baileys provides the raw QR string in its 'connection.update' event.
27
+ * We render it here so it appears in the user's terminal without
28
+ * contaminating the MCP JSON-RPC stream on stdout.
29
+ */
30
+ export declare function printQR(qrString: string): void;
31
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH;;;;;;GAMG;AACH,wBAAgB,cAAc,IAAI,MAAM,CASvC;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAG3D;AAED;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAY9C"}
package/dist/auth.js ADDED
@@ -0,0 +1,53 @@
1
+ /**
2
+ * auth.ts — Auth directory resolution and QR code display helper
3
+ *
4
+ * Whazaa stores session credentials in ~/.whazaa/auth/ by default.
5
+ * Override with WHAZAA_AUTH_DIR environment variable.
6
+ *
7
+ * QR codes are printed to stderr so they never pollute MCP's JSON-RPC
8
+ * stream on stdout.
9
+ */
10
+ import { existsSync, mkdirSync } from "node:fs";
11
+ import { homedir } from "node:os";
12
+ import { join } from "node:path";
13
+ import qrcode from "qrcode-terminal";
14
+ /**
15
+ * Resolve the auth directory, with the following priority:
16
+ * 1. WHAZAA_AUTH_DIR environment variable
17
+ * 2. ~/.whazaa/auth/ (default)
18
+ *
19
+ * Creates the directory if it does not exist.
20
+ */
21
+ export function resolveAuthDir() {
22
+ const dir = process.env.WHAZAA_AUTH_DIR ?? join(homedir(), ".whazaa", "auth");
23
+ if (!existsSync(dir)) {
24
+ mkdirSync(dir, { recursive: true });
25
+ process.stderr.write(`[whazaa] Created auth directory: ${dir}\n`);
26
+ }
27
+ return dir;
28
+ }
29
+ /**
30
+ * Return true if an existing auth session appears to be present.
31
+ * Baileys writes creds.json when credentials are saved.
32
+ */
33
+ export function hasExistingSession(authDir) {
34
+ const credsPath = join(authDir, "creds.json");
35
+ return existsSync(credsPath);
36
+ }
37
+ /**
38
+ * Print a QR code to stderr.
39
+ *
40
+ * Baileys provides the raw QR string in its 'connection.update' event.
41
+ * We render it here so it appears in the user's terminal without
42
+ * contaminating the MCP JSON-RPC stream on stdout.
43
+ */
44
+ export function printQR(qrString) {
45
+ process.stderr.write("\n[whazaa] Scan the QR code below with WhatsApp:\n");
46
+ process.stderr.write("[whazaa] Open WhatsApp -> Linked Devices -> Link a Device\n\n");
47
+ // qrcode-terminal writes to stdout by default; we capture and re-emit to stderr
48
+ qrcode.generate(qrString, { small: true }, (rendered) => {
49
+ process.stderr.write(rendered + "\n");
50
+ });
51
+ process.stderr.write("[whazaa] Waiting for scan...\n\n");
52
+ }
53
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,MAAM,MAAM,iBAAiB,CAAC;AAErC;;;;;;GAMG;AACH,MAAM,UAAU,cAAc;IAC5B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;IAE9E,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACrB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACpC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,oCAAoC,GAAG,IAAI,CAAC,CAAC;IACpE,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAe;IAChD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IAC9C,OAAO,UAAU,CAAC,SAAS,CAAC,CAAC;AAC/B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,OAAO,CAAC,QAAgB;IACtC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,oDAAoD,CAAC,CAAC;IAC3E,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,+DAA+D,CAChE,CAAC;IAEF,gFAAgF;IAChF,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,QAAgB,EAAE,EAAE;QAC9D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC;AAC3D,CAAC"}
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * index.ts — Whazaa MCP server entry point
4
+ *
5
+ * Exposes four tools over the Model Context Protocol (stdio transport):
6
+ *
7
+ * whatsapp_status — Report connection state and phone number
8
+ * whatsapp_send — Send a message to your own WhatsApp number
9
+ * whatsapp_receive — Drain queued incoming messages from your phone
10
+ * whatsapp_login — Trigger a new QR pairing flow
11
+ *
12
+ * CRITICAL: stdout is the MCP JSON-RPC transport.
13
+ * - NEVER write non-JSON to stdout.
14
+ * - All debug output, QR codes, and logs go to stderr.
15
+ */
16
+ export {};
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;GAaG"}
package/dist/index.js ADDED
@@ -0,0 +1,144 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * index.ts — Whazaa MCP server entry point
4
+ *
5
+ * Exposes four tools over the Model Context Protocol (stdio transport):
6
+ *
7
+ * whatsapp_status — Report connection state and phone number
8
+ * whatsapp_send — Send a message to your own WhatsApp number
9
+ * whatsapp_receive — Drain queued incoming messages from your phone
10
+ * whatsapp_login — Trigger a new QR pairing flow
11
+ *
12
+ * CRITICAL: stdout is the MCP JSON-RPC transport.
13
+ * - NEVER write non-JSON to stdout.
14
+ * - All debug output, QR codes, and logs go to stderr.
15
+ */
16
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
17
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
18
+ import { z } from "zod";
19
+ import { initialize, getStatus, sendMessage, drainMessages, triggerLogin, } from "./whatsapp.js";
20
+ // ---------------------------------------------------------------------------
21
+ // MCP server setup
22
+ // ---------------------------------------------------------------------------
23
+ const server = new McpServer({
24
+ name: "whazaa",
25
+ version: "0.1.0",
26
+ });
27
+ // ---------------------------------------------------------------------------
28
+ // Tool: whatsapp_status
29
+ // ---------------------------------------------------------------------------
30
+ server.tool("whatsapp_status", "Check the Whazaa connection state and the WhatsApp phone number it is logged in as.", {}, async () => {
31
+ const s = getStatus();
32
+ let text;
33
+ if (s.awaitingQR) {
34
+ text =
35
+ "Awaiting QR scan. Check the terminal where Whazaa is running and scan the QR code with WhatsApp.";
36
+ }
37
+ else if (s.connected && s.phoneNumber) {
38
+ text = `Connected. Phone: +${s.phoneNumber}`;
39
+ }
40
+ else {
41
+ text =
42
+ "Disconnected. Whazaa is attempting to reconnect in the background.";
43
+ }
44
+ return { content: [{ type: "text", text }] };
45
+ });
46
+ // ---------------------------------------------------------------------------
47
+ // Tool: whatsapp_send
48
+ // ---------------------------------------------------------------------------
49
+ server.tool("whatsapp_send", [
50
+ "Send a message to yourself via WhatsApp self-chat.",
51
+ "Supports basic Markdown: **bold**, *italic*, `code`.",
52
+ "The message appears in your own WhatsApp chat with yourself.",
53
+ ].join(" "), {
54
+ message: z
55
+ .string()
56
+ .min(1)
57
+ .describe("The message text to send to your WhatsApp self-chat"),
58
+ }, async ({ message }) => {
59
+ try {
60
+ await sendMessage(message);
61
+ const preview = message.length > 80 ? `${message.slice(0, 80)}...` : message;
62
+ return {
63
+ content: [{ type: "text", text: `Sent: ${preview}` }],
64
+ };
65
+ }
66
+ catch (err) {
67
+ const errMsg = err instanceof Error ? err.message : String(err);
68
+ return {
69
+ content: [{ type: "text", text: `Error: ${errMsg}` }],
70
+ isError: true,
71
+ };
72
+ }
73
+ });
74
+ // ---------------------------------------------------------------------------
75
+ // Tool: whatsapp_receive
76
+ // ---------------------------------------------------------------------------
77
+ server.tool("whatsapp_receive", [
78
+ "Return all queued incoming WhatsApp messages received since the last call, then clear the queue.",
79
+ "Messages are from your own WhatsApp number (self-chat) — i.e. messages you type on your phone.",
80
+ "Returns 'No new messages.' if the queue is empty.",
81
+ ].join(" "), {}, async () => {
82
+ const messages = drainMessages();
83
+ if (messages.length === 0) {
84
+ return { content: [{ type: "text", text: "No new messages." }] };
85
+ }
86
+ const formatted = messages
87
+ .map((m) => {
88
+ const ts = new Date(m.timestamp).toISOString();
89
+ return `[${ts}] ${m.body}`;
90
+ })
91
+ .join("\n");
92
+ return { content: [{ type: "text", text: formatted }] };
93
+ });
94
+ // ---------------------------------------------------------------------------
95
+ // Tool: whatsapp_login
96
+ // ---------------------------------------------------------------------------
97
+ server.tool("whatsapp_login", [
98
+ "Trigger a new WhatsApp QR pairing flow.",
99
+ "Use this when the connection is lost and automatic reconnection fails,",
100
+ "or when you need to link a different phone number.",
101
+ "A QR code will be printed to the Whazaa server's stderr — check the terminal where it is running.",
102
+ ].join(" "), {}, async () => {
103
+ try {
104
+ // Non-blocking: triggerLogin initiates the reconnect but QR display
105
+ // happens asynchronously via the Baileys event handler.
106
+ triggerLogin().catch((err) => {
107
+ process.stderr.write(`[whazaa] Login trigger error: ${err}\n`);
108
+ });
109
+ return {
110
+ content: [
111
+ {
112
+ type: "text",
113
+ text: "QR pairing initiated. Check the terminal where Whazaa is running and scan the QR code with WhatsApp (Linked Devices -> Link a Device).",
114
+ },
115
+ ],
116
+ };
117
+ }
118
+ catch (err) {
119
+ const errMsg = err instanceof Error ? err.message : String(err);
120
+ return {
121
+ content: [{ type: "text", text: `Error: ${errMsg}` }],
122
+ isError: true,
123
+ };
124
+ }
125
+ });
126
+ // ---------------------------------------------------------------------------
127
+ // Main
128
+ // ---------------------------------------------------------------------------
129
+ async function main() {
130
+ // Start WhatsApp connection in the background.
131
+ // initialize() resolves once connected OR once a QR code has been emitted,
132
+ // so the MCP server is immediately available for tool calls in both cases.
133
+ initialize().catch((err) => {
134
+ process.stderr.write(`[whazaa] Initialization error: ${err}\n`);
135
+ });
136
+ // Start the MCP server over stdio
137
+ const transport = new StdioServerTransport();
138
+ await server.connect(transport);
139
+ }
140
+ main().catch((err) => {
141
+ process.stderr.write(`[whazaa] Fatal error: ${err}\n`);
142
+ process.exit(1);
143
+ });
144
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * whatsapp.ts — WhatsApp connection manager
3
+ *
4
+ * Manages the Baileys WebSocket connection with:
5
+ * - Automatic self-JID detection (no hardcoded phone number)
6
+ * - QR pairing flow on first run, silent reconnect thereafter
7
+ * - Exponential backoff reconnection (1s -> 60s max)
8
+ * - Deduplication of sent messages to prevent self-echo
9
+ * - Markdown -> WhatsApp format conversion
10
+ * - All Baileys output silenced to avoid MCP stdio pollution
11
+ */
12
+ export interface QueuedMessage {
13
+ body: string;
14
+ timestamp: number;
15
+ }
16
+ export interface WhatsAppStatus {
17
+ connected: boolean;
18
+ /** E.164 phone number without leading +, e.g. "1234567890" */
19
+ phoneNumber: string | null;
20
+ /** Full WhatsApp JID, e.g. "1234567890@s.whatsapp.net" */
21
+ selfJid: string | null;
22
+ /** Linked Identity JID, e.g. "123456789012@lid" — used for self-chat */
23
+ selfLid: string | null;
24
+ /** Whether a QR scan is currently required */
25
+ awaitingQR: boolean;
26
+ }
27
+ /**
28
+ * Initialize the WhatsApp connection.
29
+ * Resolves once the connection is open OR a QR code has been emitted
30
+ * (so the MCP server can start handling tool calls immediately).
31
+ */
32
+ export declare function initialize(): Promise<void>;
33
+ /**
34
+ * Trigger a new QR pairing flow.
35
+ * Closes the current socket (if any) and reconnects with fresh state
36
+ * so Baileys emits a new QR code.
37
+ */
38
+ export declare function triggerLogin(): Promise<void>;
39
+ /**
40
+ * Return the current connection status snapshot.
41
+ */
42
+ export declare function getStatus(): WhatsAppStatus;
43
+ /**
44
+ * Send a message to the authenticated user's own WhatsApp number.
45
+ * Converts Markdown to WhatsApp formatting before sending.
46
+ *
47
+ * @throws If not connected or socket is unavailable.
48
+ */
49
+ export declare function sendMessage(message: string): Promise<void>;
50
+ /**
51
+ * Drain and return all queued incoming messages, then clear the queue.
52
+ */
53
+ export declare function drainMessages(): QueuedMessage[];
54
+ //# sourceMappingURL=whatsapp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whatsapp.d.ts","sourceRoot":"","sources":["../src/whatsapp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAaH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,OAAO,CAAC;IACnB,8DAA8D;IAC9D,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,0DAA0D;IAC1D,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,wEAAwE;IACxE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,8CAA8C;IAC9C,UAAU,EAAE,OAAO,CAAC;CACrB;AAmOD;;;;GAIG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAQhD;AAED;;;;GAIG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CA4BlD;AAED;;GAEG;AACH,wBAAgB,SAAS,IAAI,cAAc,CAE1C;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA6BhE;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,aAAa,EAAE,CAI/C"}
@@ -0,0 +1,300 @@
1
+ /**
2
+ * whatsapp.ts — WhatsApp connection manager
3
+ *
4
+ * Manages the Baileys WebSocket connection with:
5
+ * - Automatic self-JID detection (no hardcoded phone number)
6
+ * - QR pairing flow on first run, silent reconnect thereafter
7
+ * - Exponential backoff reconnection (1s -> 60s max)
8
+ * - Deduplication of sent messages to prevent self-echo
9
+ * - Markdown -> WhatsApp format conversion
10
+ * - All Baileys output silenced to avoid MCP stdio pollution
11
+ */
12
+ import makeWASocket, { DisconnectReason, fetchLatestBaileysVersion, makeCacheableSignalKeyStore, useMultiFileAuthState, } from "@whiskeysockets/baileys";
13
+ import pino from "pino";
14
+ import { resolveAuthDir, printQR } from "./auth.js";
15
+ // --- Module state ------------------------------------------------------------
16
+ /** The active Baileys socket (null when disconnected) */
17
+ let sock = null;
18
+ /** Incoming messages from the phone waiting to be drained */
19
+ const messageQueue = [];
20
+ /** IDs of messages sent by this process — used to suppress self-echo */
21
+ const sentMessageIds = new Set();
22
+ /** Current connection state exposed to MCP tools */
23
+ let status = {
24
+ connected: false,
25
+ phoneNumber: null,
26
+ selfJid: null,
27
+ selfLid: null,
28
+ awaitingQR: false,
29
+ };
30
+ /** Reconnect scheduling */
31
+ let reconnectTimer = null;
32
+ let reconnectAttempts = 0;
33
+ const MAX_RECONNECT_DELAY_MS = 60_000;
34
+ /** Set to true on loggedOut — stops all reconnect attempts */
35
+ let permanentlyLoggedOut = false;
36
+ /** Resolve when the first connection attempt completes (either open or qr shown) */
37
+ let initResolve = null;
38
+ // --- Internal helpers --------------------------------------------------------
39
+ /**
40
+ * Silenced Pino logger — CRITICAL: Baileys must not write to stdout.
41
+ * Stdout is the MCP JSON-RPC transport; any non-JSON output breaks the protocol.
42
+ */
43
+ const logger = pino({ level: "silent" });
44
+ /**
45
+ * Convert common Markdown syntax to WhatsApp formatting codes.
46
+ *
47
+ * **bold** -> *bold* (WhatsApp bold)
48
+ * *italic* -> _italic_ (WhatsApp italic)
49
+ * `code` -> ```code``` (WhatsApp monospace)
50
+ */
51
+ function markdownToWhatsApp(text) {
52
+ return text
53
+ .replace(/\*\*(.+?)\*\*/gs, "*$1*")
54
+ .replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/gs, "_$1_")
55
+ .replace(/`([^`]+)`/g, "```$1```");
56
+ }
57
+ /**
58
+ * Schedule a reconnection attempt with exponential backoff.
59
+ * Does nothing if permanently logged out or a timer is already pending.
60
+ */
61
+ function scheduleReconnect() {
62
+ if (permanentlyLoggedOut)
63
+ return;
64
+ if (reconnectTimer)
65
+ return; // already scheduled
66
+ reconnectAttempts++;
67
+ const delay = Math.min(1_000 * Math.pow(2, reconnectAttempts - 1), MAX_RECONNECT_DELAY_MS);
68
+ process.stderr.write(`[whazaa] Reconnecting in ${delay / 1_000}s (attempt ${reconnectAttempts})...\n`);
69
+ reconnectTimer = setTimeout(() => {
70
+ reconnectTimer = null;
71
+ connect().catch((err) => {
72
+ process.stderr.write(`[whazaa] Reconnect error: ${err}\n`);
73
+ });
74
+ }, delay);
75
+ }
76
+ // --- Core connection ---------------------------------------------------------
77
+ /**
78
+ * Open (or re-open) the Baileys WebSocket connection.
79
+ * On first run with no saved credentials, Baileys emits a QR code which we
80
+ * display on stderr. After the user scans it, credentials are saved and all
81
+ * subsequent runs connect automatically without showing a QR.
82
+ */
83
+ async function connect() {
84
+ const authDir = resolveAuthDir();
85
+ const { state: authState, saveCreds } = await useMultiFileAuthState(authDir);
86
+ const { version } = await fetchLatestBaileysVersion();
87
+ sock = makeWASocket({
88
+ auth: {
89
+ creds: authState.creds,
90
+ keys: makeCacheableSignalKeyStore(authState.keys, logger),
91
+ },
92
+ version,
93
+ // Browser string shown in WhatsApp's linked devices list
94
+ browser: ["Whazaa", "cli", "0.1.0"],
95
+ printQRInTerminal: false, // We handle QR display ourselves on stderr
96
+ syncFullHistory: false,
97
+ markOnlineOnConnect: false,
98
+ logger,
99
+ });
100
+ // Persist credentials whenever they are updated
101
+ sock.ev.on("creds.update", saveCreds);
102
+ // Handle connection lifecycle
103
+ sock.ev.on("connection.update", ({ connection, lastDisconnect, qr }) => {
104
+ // Display QR code when pairing is needed
105
+ if (qr) {
106
+ status.awaitingQR = true;
107
+ printQR(qr);
108
+ // Resolve init promise so MCP server starts up even while awaiting scan
109
+ if (initResolve) {
110
+ initResolve();
111
+ initResolve = null;
112
+ }
113
+ }
114
+ if (connection === "open") {
115
+ status.awaitingQR = false;
116
+ status.connected = true;
117
+ reconnectAttempts = 0;
118
+ // Derive phone number and LID from the authenticated user
119
+ const jid = sock?.user?.id ?? null;
120
+ if (jid) {
121
+ // JID format: "1234567890:12@s.whatsapp.net" or "1234567890@s.whatsapp.net"
122
+ const number = jid.split(":")[0].split("@")[0];
123
+ status.phoneNumber = number;
124
+ status.selfJid = `${number}@s.whatsapp.net`;
125
+ }
126
+ // Capture LID (Linked Identity) — self-chat uses this format
127
+ const lid = sock?.user?.lid;
128
+ if (lid) {
129
+ status.selfLid = lid;
130
+ }
131
+ process.stderr.write(`[whazaa] Connected. Phone: +${status.phoneNumber ?? "unknown"}\n`);
132
+ // Resolve init promise on successful connection
133
+ if (initResolve) {
134
+ initResolve();
135
+ initResolve = null;
136
+ }
137
+ }
138
+ if (connection === "close") {
139
+ status.connected = false;
140
+ const statusCode = lastDisconnect?.error?.output
141
+ ?.statusCode;
142
+ if (statusCode === DisconnectReason.loggedOut) {
143
+ // Auth is invalid (401). Stop reconnecting — user must re-pair.
144
+ permanentlyLoggedOut = true;
145
+ process.stderr.write("[whazaa] Logged out (401). Run whatsapp_login to re-pair.\n");
146
+ if (initResolve) {
147
+ initResolve();
148
+ initResolve = null;
149
+ }
150
+ return;
151
+ }
152
+ process.stderr.write("[whazaa] Connection closed. Will reconnect...\n");
153
+ scheduleReconnect();
154
+ }
155
+ });
156
+ // Handle incoming messages — only self-chat messages are queued
157
+ sock.ev.on("messages.upsert", ({ type, messages }) => {
158
+ // Accept both "notify" (real-time) and "append" (history sync / self-sent)
159
+ // Only skip "set" which is bulk history sync on first connect
160
+ for (const msg of messages) {
161
+ const remoteJid = msg.key?.remoteJid;
162
+ const body = msg.message?.conversation ??
163
+ msg.message?.extendedTextMessage?.text ??
164
+ null;
165
+ // Filter to self-chat only: match selfJid, selfLid, or phone number prefix
166
+ // Strip device suffix (e.g. ":6" or ":12") for comparison
167
+ const stripDevice = (jid) => jid.replace(/:\d+@/, "@");
168
+ const selfNumber = status.phoneNumber;
169
+ const selfLid = status.selfLid ? stripDevice(status.selfLid) : null;
170
+ const remoteJidNorm = remoteJid ? stripDevice(remoteJid) : null;
171
+ const isSelfChat = (status.selfJid && remoteJidNorm === stripDevice(status.selfJid)) ||
172
+ (selfLid && remoteJidNorm === selfLid) ||
173
+ (selfNumber && remoteJid?.startsWith(selfNumber));
174
+ if (!isSelfChat) {
175
+ continue;
176
+ }
177
+ // Deduplicate: skip messages sent by this process
178
+ const msgId = msg.key?.id;
179
+ if (msgId && sentMessageIds.has(msgId)) {
180
+ sentMessageIds.delete(msgId);
181
+ continue;
182
+ }
183
+ if (body) {
184
+ messageQueue.push({
185
+ body,
186
+ timestamp: Number(msg.messageTimestamp) * 1_000,
187
+ });
188
+ }
189
+ }
190
+ });
191
+ }
192
+ // --- Public API --------------------------------------------------------------
193
+ /**
194
+ * Initialize the WhatsApp connection.
195
+ * Resolves once the connection is open OR a QR code has been emitted
196
+ * (so the MCP server can start handling tool calls immediately).
197
+ */
198
+ export async function initialize() {
199
+ await new Promise((resolve) => {
200
+ initResolve = resolve;
201
+ connect().catch((err) => {
202
+ process.stderr.write(`[whazaa] Init error: ${err}\n`);
203
+ resolve(); // Don't block MCP startup on connection failure
204
+ });
205
+ });
206
+ }
207
+ /**
208
+ * Trigger a new QR pairing flow.
209
+ * Closes the current socket (if any) and reconnects with fresh state
210
+ * so Baileys emits a new QR code.
211
+ */
212
+ export async function triggerLogin() {
213
+ permanentlyLoggedOut = false;
214
+ reconnectAttempts = 0;
215
+ if (reconnectTimer) {
216
+ clearTimeout(reconnectTimer);
217
+ reconnectTimer = null;
218
+ }
219
+ if (sock) {
220
+ try {
221
+ sock.end(undefined);
222
+ }
223
+ catch {
224
+ // Ignore errors on close
225
+ }
226
+ sock = null;
227
+ }
228
+ status = {
229
+ connected: false,
230
+ phoneNumber: null,
231
+ selfJid: null,
232
+ selfLid: null,
233
+ awaitingQR: false,
234
+ };
235
+ // Reconnect — Baileys will emit a QR if no creds are present
236
+ await connect();
237
+ }
238
+ /**
239
+ * Return the current connection status snapshot.
240
+ */
241
+ export function getStatus() {
242
+ return { ...status };
243
+ }
244
+ /**
245
+ * Send a message to the authenticated user's own WhatsApp number.
246
+ * Converts Markdown to WhatsApp formatting before sending.
247
+ *
248
+ * @throws If not connected or socket is unavailable.
249
+ */
250
+ export async function sendMessage(message) {
251
+ if (!sock) {
252
+ throw new Error("WhatsApp socket not initialized. Is the connection open?");
253
+ }
254
+ if (!status.connected) {
255
+ throw new Error("WhatsApp is not connected. Check status with whatsapp_status.");
256
+ }
257
+ if (!status.selfJid) {
258
+ throw new Error("Self JID not yet known. Wait for connection to fully open.");
259
+ }
260
+ const text = markdownToWhatsApp(message);
261
+ const result = await sock.sendMessage(status.selfJid, { text });
262
+ // Register the sent message ID for deduplication
263
+ if (result?.key?.id) {
264
+ const id = result.key.id;
265
+ sentMessageIds.add(id);
266
+ // Auto-expire after 30 seconds to prevent unbounded growth
267
+ setTimeout(() => {
268
+ sentMessageIds.delete(id);
269
+ }, 30_000);
270
+ }
271
+ }
272
+ /**
273
+ * Drain and return all queued incoming messages, then clear the queue.
274
+ */
275
+ export function drainMessages() {
276
+ const snapshot = [...messageQueue];
277
+ messageQueue.length = 0;
278
+ return snapshot;
279
+ }
280
+ // --- Graceful shutdown -------------------------------------------------------
281
+ function shutdown(signal) {
282
+ process.stderr.write(`[whazaa] Received ${signal}. Shutting down...\n`);
283
+ if (reconnectTimer) {
284
+ clearTimeout(reconnectTimer);
285
+ reconnectTimer = null;
286
+ }
287
+ if (sock) {
288
+ try {
289
+ sock.end(undefined);
290
+ }
291
+ catch {
292
+ // Ignore
293
+ }
294
+ sock = null;
295
+ }
296
+ process.exit(0);
297
+ }
298
+ process.on("SIGINT", () => shutdown("SIGINT"));
299
+ process.on("SIGTERM", () => shutdown("SIGTERM"));
300
+ //# sourceMappingURL=whatsapp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whatsapp.js","sourceRoot":"","sources":["../src/whatsapp.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "whazaa",
3
+ "version": "0.1.0",
4
+ "description": "WhatsApp MCP server for Claude Code — talk to Claude from your phone via WhatsApp self-chat",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "whazaa": "dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "README.md",
13
+ "LICENSE"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsc",
17
+ "dev": "tsc --watch",
18
+ "start": "node dist/index.js",
19
+ "prepublishOnly": "npm run build"
20
+ },
21
+ "keywords": [
22
+ "mcp",
23
+ "whatsapp",
24
+ "claude",
25
+ "claude-code",
26
+ "mcp-server",
27
+ "baileys",
28
+ "chatbot",
29
+ "ai"
30
+ ],
31
+ "license": "MIT",
32
+ "author": "Matthias Nott",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "https://github.com/mnott/Whazaa"
36
+ },
37
+ "engines": {
38
+ "node": ">=18.0.0"
39
+ },
40
+ "dependencies": {
41
+ "@modelcontextprotocol/sdk": "^1.26.0",
42
+ "@whiskeysockets/baileys": "^7.0.0-rc.9",
43
+ "pino": "^9.0.0",
44
+ "qrcode-terminal": "^0.12.0",
45
+ "zod": "^3.23.0"
46
+ },
47
+ "devDependencies": {
48
+ "@types/node": "^22.0.0",
49
+ "@types/qrcode-terminal": "^0.12.2",
50
+ "typescript": "^5.0.0"
51
+ }
52
+ }