@zhuxe-js/mcp-server 0.0.0-stage → 1.2.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.
Files changed (2) hide show
  1. package/README.md +164 -2
  2. package/package.json +56 -5
package/README.md CHANGED
@@ -1,3 +1,165 @@
1
- # Temporary Holding Version
1
+ # @zhuxe-js/mcp-server
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Optional package that exposes [`zhuxe-assistance`](https://www.npmjs.com/package/zhuxe-assistance) `WaClient` sessions **and** the `zhuxe-assistance` module namespace as MCP tools, so an LLM agent (Claude Code, Cursor, etc.) can drive end-to-end WhatsApp flows - connect, pair, send, query groups/newsletters, inspect events, walk SQL state - without writing throwaway scripts. Source: [`packages/mcp-server/`](.).
4
+
5
+ > Built for **development and testing**, not as a production protocol server.
6
+
7
+ One process can drive **multiple sessions over a single shared store**: every tool takes an optional `session` id (default `MCP_SESSION_ID`), and any new id lazily spins up an additional `WaClient` on the same backend (the store scopes every row by session id). See [Sessions](#sessions).
8
+
9
+ ## Tool surface
10
+
11
+ Every tool takes an optional **`session`** id (default `MCP_SESSION_ID`); a new id lazily spins up another `WaClient` on the shared store. See [Sessions](#sessions).
12
+
13
+ - **`call`** / **`inspect`** - walk dotted paths against `client` (the selected session's `WaClient`) or `lib` (the `zhuxe-assistance` module namespace, including `proto.*` and helpers like `parsePhoneJid`). `call` invokes functions; `inspect` lists members with origin class.
14
+ - **`events`** / **`events_clear`** - per-session ring buffer of every `WaClientEventMap` event (filter by `types` / `since` / `limit` / `drain`; scoped to `session`).
15
+ - **`logs`** / **`logs_clear`** - `BufferedTeeLogger` mirrors every runtime + lib log line into one queryable buffer (also stderr, and JSONL to `MCP_LOG_FILE` if set). Each session's lines are tagged with `context.session`; `logs` accepts a `session` filter.
16
+ - **`lifecycle`** - `status` / `start` / `destroy` for a session's `WaClient`. `status` also returns a summary of every live session.
17
+ - **`restart`** - `soft` resets one session (drop its client, clear its events + the shared log buffer); `process_exit` disconnects **every** session, destroys the shared store, then exits so a supervisor / reconnect respawns it.
18
+
19
+ The full description, schema, and examples are inlined on each tool - agents should read them at runtime rather than memorize flags.
20
+
21
+ ## Install
22
+
23
+ ```bash
24
+ npm install @zhuxe-js/mcp-server
25
+ ```
26
+
27
+ Peer deps: `zhuxe-assistance`, `@modelcontextprotocol/sdk`. SQLite credential persistence requires `better-sqlite3`.
28
+
29
+ ## Registering with Claude Code
30
+
31
+ Build, then register at user scope so it works from any cwd:
32
+
33
+ ```bash
34
+ npm run build --workspace @zhuxe-js/mcp-server
35
+ claude mcp add zhuxe --scope user -- node <abs-path>/packages/mcp-server/dist/bin.js
36
+ ```
37
+
38
+ For tighter dev iteration, register the source via `tsx` (no build step needed):
39
+
40
+ ```bash
41
+ claude mcp add zhuxe --scope user -- node --import tsx <abs-path>/packages/mcp-server/src/bin.ts
42
+ ```
43
+
44
+ ## Pairing flow gotcha
45
+
46
+ `client.connect()` blocks until pairing finishes. Always invoke it as:
47
+
48
+ ```text
49
+ call({ path: 'connect', noAwait: true })
50
+ ```
51
+
52
+ so the tool returns immediately. Then poll
53
+ `events({ types: ['auth_qr', 'auth_pairing_code', 'auth_paired', 'connection'] })`,
54
+ surface the QR string to the user, wait for `auth_paired`, and continue.
55
+
56
+ ## Sessions
57
+
58
+ The server multiplexes any number of sessions over **one** store (the single
59
+ `MCP_AUTH_PATH` backend, bounded by `MCP_MAX_SESSIONS`). Pass `session` to any
60
+ tool; omitting it targets the default (`MCP_SESSION_ID`). A fresh id is created
61
+ on first use - no extra server process needed.
62
+
63
+ ```text
64
+ # bring up a second account alongside the default, on the same store
65
+ lifecycle({ action: 'start', session: 'business' })
66
+ call({ path: 'connect', session: 'business', noAwait: true })
67
+ events({ session: 'business', types: ['auth_qr', 'auth_paired', 'connection'] })
68
+ # ... scan the QR, wait for auth_paired ...
69
+ call({ path: 'message.send', session: 'business', args: ['<jid>', { conversation: 'hi' }] })
70
+
71
+ # list every live session
72
+ lifecycle({ action: 'status' })
73
+ # -> sessions: [{ sessionId, isDefault, clientCreated, bufferedEvents }, ...]
74
+ ```
75
+
76
+ Each session has its own credentials row, event buffer, and connection
77
+ lifecycle; they share one sqlite connection (writes serialize in-process, no
78
+ cross-process `SQLITE_BUSY`). The in-process read-through cache (`cacheLayer`)
79
+ is safe here because a single process owns each session's rows. Use separate
80
+ processes only when you want isolated stores / auth files.
81
+
82
+ ## Dev loop
83
+
84
+ **Recommended (HTTP + watch runner, zero manual reconnect):**
85
+
86
+ ```bash
87
+ claude mcp add zhuxe --scope user --transport http http://127.0.0.1:3737/mcp
88
+ npm run dev --workspace @zhuxe-js/mcp-server
89
+ ```
90
+
91
+ The `dev` script runs the server under `scripts/dev-watch.cjs`, which spawns
92
+ `node --import tsx src/bin.ts` on HTTP (port 3737) and respawns it when a
93
+ watched source actually changes. `tsx` resolves `zhuxe-assistance` directly from
94
+ `<root>/src/` via `packages/tsconfig.paths.json`, so iterating on the core lib
95
+ needs no rebuild. Edit any `.ts` under `<root>/src`, `<root>/packages` or
96
+ `<root>/spec` → the runner restarts the process and names the file that
97
+ triggered it → the next
98
+ tool call from Claude Code re-establishes the HTTP session automatically. No
99
+ `/mcp` manual reconnect. Generated and non-runtime folders are ignored:
100
+ `node_modules`, `dist`, `target`, `__tests__`, `__test__`, `bench`, `.turbo`
101
+ and `coverage`.
102
+
103
+ The script also sets `MCP_AUTH_PATH=../../.auth/state.sqlite`, so the MCP
104
+ shares the credential store with `test/example.cjs` (no re-pairing).
105
+
106
+ > **Why a custom runner and not `node --watch`:** on Windows libuv subscribes
107
+ > `fs.watch` to `FILE_NOTIFY_CHANGE_LAST_ACCESS`, so merely **reading** a file
108
+ > emits a change event once NTFS flushes a new last-access time (module load,
109
+ > test run, editor indexing, grep). `node --watch` restarts on any event for a
110
+ > file in its module graph without checking whether the file was written at
111
+ > all, which
112
+ > makes the server restart on the first lazy import - `better-sqlite3`, loaded
113
+ > on the first `connect()` - and whenever another tool walks the tree. The
114
+ > runner keeps the same event source and compares mtime + size before
115
+ > restarting. `tsx watch` is not the answer either: it has known issues
116
+ > detecting changes in nested imports on Windows. `tsx` stays as the
117
+ > transpilation loader in every case.
118
+
119
+ **Stdio fallback (manual reconnect):**
120
+
121
+ ```bash
122
+ npm run build --workspace @zhuxe-js/mcp-server
123
+ claude mcp add zhuxe --scope user -- node <abs>/packages/mcp-server/dist/bin.js
124
+ ```
125
+
126
+ After editing source: rebuild → call `restart` with `mode: "process_exit"` → `/mcp` reconnect in Claude Code.
127
+
128
+ ## Environment variables
129
+
130
+ | Var | Default | Purpose |
131
+ | ------------------------------------------------------------------------------ | ----------------------------- | ----------------------------------------------------- |
132
+ | `MCP_AUTH_PATH` | `<cwd>/.auth/state.sqlite` | SQLite credential store path |
133
+ | `MCP_SESSION_ID` | `default_2` | Default session id (tools that omit `session` use it) |
134
+ | `MCP_MAX_SESSIONS` | `16` | Max concurrently-live sessions in the process |
135
+ | `MCP_LOG_LEVEL` | `info` | `trace` / `debug` / `info` / `warn` / `error` |
136
+ | `MCP_LOG_FILE` | unset | Append every log line as JSONL |
137
+ | `MCP_LOG_BUFFER_SIZE` | `500` | In-memory log ring size |
138
+ | `MCP_EVENT_BUFFER_SIZE` | `1000` | In-memory event ring size |
139
+ | `MCP_CAPTURE_TRANSPORT` | `0` | Also buffer noisy `transport_*` events |
140
+ | `MCP_HISTORY_DISABLED` | `0` | Disable history sync on connect |
141
+ | `MCP_GROUP_BUNDLES` | `0` | Download group-history bundles shared by members |
142
+ | `MCP_TRANSPORT` | `stdio` | `stdio` or `http` (StreamableHTTPServerTransport) |
143
+ | `MCP_HTTP_HOST` / `MCP_HTTP_PORT` / `MCP_HTTP_PATH` | `127.0.0.1` / `3737` / `/mcp` | HTTP listener config |
144
+ | `MCP_FAKE_NOISE_PUBKEY_HEX` + `MCP_FAKE_NOISE_SERIAL` + `MCP_CHAT_SOCKET_URLS` | unset | Point at `@zhuxe-js/fake-server` for tests |
145
+
146
+ ## Notes / limits
147
+
148
+ - The cwd of the spawned MCP process determines the default `.auth/`
149
+ location. When Claude Code spawns it, that's wherever Claude Code was
150
+ started.
151
+ - One process runs many sessions over one shared store: pass `session` to any
152
+ tool (default `MCP_SESSION_ID`), bounded by `MCP_MAX_SESSIONS`. All sessions
153
+ share the single `MCP_AUTH_PATH` backend - use separate processes only when
154
+ you want isolated stores / auth files.
155
+ - `WaClient` has no auto-reconnect. On `connection: close`, call `connect`
156
+ again manually (per session).
157
+ - `restart` (`soft`) does **not** pick up code changes; `process_exit` +
158
+ supervisor reconnect does.
159
+ - The watch runner is not a full supervisor: it restarts on file changes
160
+ only, and waits for the next change if the child exits on its own.
161
+ `process_exit` from the `restart` tool kills the child and the runner will
162
+ not respawn it until something changes - under HTTP+watch, just edit a file
163
+ to reload instead.
164
+
165
+ See the main [`zhuxe-assistance`](../../README.md) docs for the `WaClient` API surface.
package/package.json CHANGED
@@ -1,6 +1,57 @@
1
1
  {
2
- "name": "@zhuxe-js/mcp-server",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
2
+ "name": "@zhuxe-js/mcp-server",
3
+ "version": "1.2.0",
4
+ "description": "MCP server exposing zhuxe-assistance WaClient as dynamic tools for end-to-end testing",
5
+ "license": "MIT",
6
+ "author": "vinikjkkj <contact@vinicius.email> (https://github.com/vinikjkkj)",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/abay62096-dotcom/zhuxe.git",
10
+ "directory": "packages/mcp-server"
11
+ },
12
+ "main": "dist/index.js",
13
+ "module": "dist/esm/index.js",
14
+ "types": "dist/index.d.ts",
15
+ "bin": {
16
+ "zhuxe-mcp-server": "./dist/bin.js"
17
+ },
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "require": "./dist/index.js",
22
+ "import": "./dist/esm/index.js",
23
+ "default": "./dist/index.js"
24
+ }
25
+ },
26
+ "files": [
27
+ "dist"
28
+ ],
29
+ "publishConfig": {
30
+ "access": "public"
31
+ },
32
+ "scripts": {
33
+ "build": "tsc -p tsconfig.build.cjs.json && tsc -p tsconfig.build.esm.json && node ../../scripts/finalize-esm-build.cjs",
34
+ "typecheck": "tsc --noEmit",
35
+ "test": "node --import tsx --test \"src/**/__tests__/**/*.test.ts\"",
36
+ "start": "node --import tsx src/bin.ts",
37
+ "dev": "cross-env MCP_TRANSPORT=http MCP_EVAL_ENABLED=1 MCP_LOG_LEVEL=trace MCP_AUTH_PATH=../../.auth/state.sqlite node ../../scripts/dev-watch.cjs --watch ../../src --watch ../../packages --watch ../../spec -- node --import tsx src/bin.ts"
38
+ },
39
+ "dependencies": {
40
+ "@modelcontextprotocol/sdk": "^1.29.0",
41
+ "@zhuxe-js/media-utils": "^1.0.0",
42
+ "@zhuxe-js/store-sqlite": "^1.1.0",
43
+ "@zhuxe-js/wam": "^0.1.0",
44
+ "better-sqlite3": "^12.6.2"
45
+ },
46
+ "peerDependencies": {
47
+ "zhuxe-assistance": "^1.0.0"
48
+ },
49
+ "devDependencies": {
50
+ "@zhuxe-js/fake-server": "file:../fake-server",
51
+ "cross-env": "^7.0.3",
52
+ "zhuxe-assistance": "file:../.."
53
+ },
54
+ "engines": {
55
+ "node": ">=20.9.0"
56
+ }
57
+ }