wazap-mcp 0.9.8 → 0.11.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/AGENT.md CHANGED
@@ -6,12 +6,13 @@ wazap keeps stdout for the MCP protocol and writes every human-readable line to
6
6
 
7
7
  1. Run `npx wazap-mcp status --json`. If `linked` is true, skip to step 5.
8
8
  2. Ask the person for their WhatsApp number in international format (e.g. +15550100) and whether the agent may send messages (default: no).
9
- 3. Start the link IN THE BACKGROUND and keep reading its output:
9
+ 3. If you already have the `whatsapp` tools (the Claude Desktop bundle, or any client wazap is connected to), call `link_account` with the number. It returns the code within ~10 s and needs no terminal. Otherwise start the link IN THE BACKGROUND and keep reading its output:
10
10
  `npx wazap-mcp login --phone <number> --no-writes --yes 2>&1` (or `--writes`).
11
11
  Within ~10 s the output contains a line `pairing code: XXXX-XXXX`.
12
- 4. Show the person exactly: "On your phone: WhatsApp → Settings → Linked devices → Link a device → Link with phone number instead → enter XXXX-XXXX". Keep reading the output until `Linked as …` and then `Synced N chats …` appear (up to 3 minutes). If the output says the code expired, run step 3 again.
13
- 5. Register wazap with the client you are running in: `npx wazap-mcp connect <client>` where <client> is claude-code, claude-desktop, cursor, codex, vscode or gemini. Tell the person what the command printed as `Next`.
12
+ 4. Show the person exactly: "On your phone: WhatsApp → Settings → Linked devices → Link a device → Link with phone number instead → enter XXXX-XXXX". After `link_account`, call `get_status` every 10 seconds until it says `connected` (up to 3 minutes); after the command, keep reading the output until `Linked as …` and then `Synced N chats …` appear. If the code expired, run step 3 again.
13
+ 5. If step 1 reported `install.kind: "npx"`, run `npm i -g wazap-mcp` first: Claude Desktop and the background service cannot launch from the npx cache, which npm clears. Register wazap with the client you are running in: `npx wazap-mcp connect <client>` where <client> is claude-code, claude-desktop, cursor, codex, vscode or gemini. Tell the person what the command printed as `Next`. Then, for claude-code, codex, cursor and opencode, run `npx wazap-mcp skills install <client>`, which copies the five workflow skills where that client reads them. The other clients need no such step, because the server hands them the same five workflows as MCP prompts.
14
14
  6. Verify: `npx wazap-mcp status --json` must show `linked: true` and no failing check. If the client needs a restart, say so; otherwise call the `get_status` tool and then `learn`.
15
15
  7. Done when `get_status` returns `connected`. Then offer: "what did I miss on WhatsApp today?"
16
+ 8. Ask whether wazap should keep running after this client closes, and whether cloud agents should reach it. For the first, run `npx wazap-mcp service install`, which writes a launchd agent or a systemd user unit and starts it. For the second, also run `npx wazap-mcp expose`. It opens a tunnel, prints an https URL and a consent password, and restarts the service. Give an agent the URL only. The password is for the person, on their consent page; never paste it into a chat, a config file or a message.
16
17
 
17
18
  Errors: every wazap error prints `✗ message` and `→ fix`; do what the fix says, do not retry blindly. One process owns the session, so while the `login` of step 3 runs, no server and no other wazap command may touch the same data dir; two servers on one data dir refuse to start. Stop the other one first.
package/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
  ```
9
9
 
10
10
  **WhatsApp for your AI agent.** An MCP server that puts your WhatsApp account —
11
- chats, messages, media, contacts, groups — behind 23 tools any MCP client can
11
+ chats, messages, media, contacts, groups — behind 25 tools any MCP client can
12
12
  call. Pairing-code login, no browser, no phone-number reseller, ~20 MB of RAM.
13
13
 
14
14
  Built on [Baileys](https://github.com/WhiskeySockets/Baileys), which speaks the
@@ -23,7 +23,12 @@ npx wazap-mcp setup
23
23
  ```
24
24
 
25
25
  That is the whole install. It links your account, finds the MCP clients
26
- installed on this machine, writes their config and tells you what to restart.
26
+ installed on this machine, writes their config, copies the five skills where
27
+ that client reads them, and tells you what to restart. When you started through
28
+ `npx`, `setup` offers to install wazap globally so Claude Desktop and the
29
+ background service have a path that does not change. It also offers to
30
+ `brew install` whisper-cpp, ffmpeg or Tailscale when a step needs one and it is
31
+ missing, and to restart Claude Desktop itself once it has connected it.
27
32
 
28
33
  ### Or the path your harness prefers
29
34
 
@@ -82,7 +87,7 @@ it would write.
82
87
  | `gemini` | `~/.gemini/settings.json` |
83
88
  | `windsurf` | `~/.codeium/windsurf/mcp_config.json` |
84
89
  | `opencode` | `mcp.whatsapp` in `~/.config/opencode/opencode.json` |
85
- | anything remote | client's MCP URL field: `https://your-host/mcp` with header `Authorization: Bearer <token>` (see [Self-host](#self-host)) |
90
+ | anything remote | client's MCP URL field: `https://your-host/mcp` with header `Authorization: Bearer <token>`, or just the URL once [OAuth](#hosted-agents-oauth) is on (see [Self-host](#self-host)) |
86
91
 
87
92
  ### Other MCP clients
88
93
 
@@ -159,26 +164,93 @@ Download `wazap-<version>.mcpb` from [Releases](https://github.com/razvangirgiz/
159
164
  and double-click it. Claude Desktop installs the server, its Node dependencies
160
165
  and the icon, and shows two settings: **Read-only**, ticked, and **Data
161
166
  directory**, empty. `wazap connect claude-desktop` does the same job by editing
162
- `claude_desktop_config.json`, and needs `npx` at launch; the bundle does not.
167
+ `claude_desktop_config.json`. Claude Desktop starts its servers without your
168
+ shell PATH, so that entry is the absolute path to `node` when wazap is installed
169
+ globally, and `npx` otherwise; `wazap setup` checks that the entry it wrote is
170
+ one Claude Desktop can actually launch.
163
171
 
164
- Linking the account still needs a terminal once: `npx wazap-mcp login`. The
165
- bundle reads the session that login writes to `~/.wazap`.
172
+ Then ask Claude to link your WhatsApp. It calls `link_account` with your number,
173
+ hands back an 8-character code, and you type that code into **WhatsApp
174
+ Settings → Linked devices → Link a device → Link with phone number instead**.
175
+ No terminal at any point. `npx wazap-mcp login` does the same job from a shell
176
+ when you have one.
166
177
 
167
178
  Untick **Read-only** to let Claude send. It ships ticked because a bundle that
168
179
  can message people from your number before you have said so is the wrong
169
180
  default, and because the setting cannot be left unanswered: the manifest format
170
181
  has no way to omit an argument, so the box you see is the answer the server gets.
182
+ `link_account` is registered either way. Read-only exists to stop Claude
183
+ messaging people from your number, and relinking your own dead session messages
184
+ nobody.
171
185
 
172
186
  Build it yourself with `npm run bundle:mcpb`, which stages `dist/`, the
173
187
  manifest, the icon and a fresh production `node_modules`, then packs them with
174
188
  [`@anthropic-ai/mcpb`](https://github.com/modelcontextprotocol/mcpb).
175
189
 
190
+ ### Keep it running
191
+
192
+ A wazap started by a client lives as long as that client does. Quit Claude Code
193
+ and the session is gone until you open it again. Two commands change that.
194
+ Staying up and being reachable are separate choices.
195
+
196
+ ```bash
197
+ npx wazap-mcp service install
198
+ ```
199
+
200
+ That writes a launchd agent on macOS (`~/Library/LaunchAgents/com.wazap.server.plist`)
201
+ or a systemd user unit on Linux (`~/.config/systemd/user/wazap.service`), starts
202
+ it, and waits for `/healthz` to answer. The unit runs `serve --http` on
203
+ `127.0.0.1:8766` with the absolute path of this Node and this install, so it
204
+ survives a reboot and a logout. Point any client at
205
+ `http://127.0.0.1:8766/mcp`, or keep using the stdio entry. A second wazap on
206
+ the same data directory becomes a bridge onto the session this one holds.
207
+
208
+ `service status` prints the pid, the health check and whether the unit still
209
+ runs the version you have installed. `service logs` tails it. `service restart`
210
+ picks up an upgrade; `service uninstall` removes the unit and leaves your
211
+ session and credentials alone. `wazap login` needs the session to itself, so it
212
+ stops the service, pairs, and starts it again on its own.
213
+
214
+ A sleeping Mac is an offline wazap. System Settings → Lock Screen, or Battery →
215
+ Options, has the switch that keeps it awake on power.
216
+
217
+ ```bash
218
+ npx wazap-mcp expose
219
+ ```
220
+
221
+ That gives the running service a public `https` URL, for agents that are not on
222
+ this machine: a cloud agent, claude.ai, ChatGPT. It uses Tailscale Funnel if
223
+ `tailscale` is installed, Cloudflare Tunnel if `cloudflared` is, opens the
224
+ tunnel, writes `WAZAP_PUBLIC_URL` and a fresh `WAZAP_OAUTH_PASSWORD` into
225
+ `<data-dir>/.env`, restarts the service and checks the URL from here. It then
226
+ prints the MCP URL and the password once.
227
+
228
+ Give an agent the URL only. It signs in on a consent page on your own host with
229
+ that password and picks read or read-and-send there; `wazap status` lists who
230
+ holds a grant. See [Hosted agents (OAuth)](#hosted-agents-oauth) for what that
231
+ page does. `npx wazap-mcp expose off` takes the tunnel down and keeps the
232
+ password, so the next `expose` hands agents the same one.
233
+
234
+ `npx wazap-mcp setup` asks all of this once, as its fourth step.
235
+
236
+ ### Upgrade
237
+
238
+ ```bash
239
+ npx wazap-mcp update
240
+ ```
241
+
242
+ One command for what used to be three. It compares this install against the
243
+ registry, installs the new package when wazap is global, restarts the service so
244
+ it runs the new code, and copies the new skills into every harness that keeps
245
+ them. `--dry-run` prints the plan and touches nothing.
246
+
176
247
  ## Tools
177
248
 
178
249
  | Tool | Kind | What it does |
179
250
  | --- | --- | --- |
180
251
  | `learn` | read | The guide to every tool, id format and error code. Call it first. |
181
252
  | `get_status` | read | Connection status, sync state, linked account, named-contact count, versions, data dir. |
253
+ | `link_account` | read | Pair the account without a terminal: returns the code to type into the phone. Registered in read-only mode too. |
182
254
  | `list_chats` | read | Conversations newest-first; filter `all`/`unread`/`groups`/`individual`/`archived`. |
183
255
  | `read_messages` | read | Messages in a chat; `before` pages further back, pulling older history from the phone; `types` narrows to one or more message types, e.g. `["call"]`. |
184
256
  | `get_recent_messages` | read | Everything from the last N hours, grouped by chat. The catch-up tool. `include_system` adds WhatsApp's own notices, `types` narrows to one or more message types. |
@@ -238,6 +310,10 @@ wazap transcribe download # fetch and verify the model
238
310
  wazap transcribe test recording.ogg # prove it before you trust it
239
311
  ```
240
312
 
313
+ `wazap setup` and `wazap transcribe download` offer that `brew install`
314
+ themselves when either binary is missing, and go straight on to the model in the
315
+ same run. `--no-brew` turns the offer off everywhere.
316
+
241
317
  Models land in `<data-dir>/models/` and are checked against a SHA-256 pinned in
242
318
  the source; an interrupted download resumes where it stopped.
243
319
 
@@ -300,22 +376,25 @@ wazap ships five [Agent Skills](https://agentskills.io) that teach an agent the
300
376
  | `whatsapp-groups` | Catch up on a 300-message group: decisions, dates, what is asked of you. Read-only |
301
377
  | `whatsapp-send` | Draft in the chat's own register, show recipient and text, send only after the user says yes |
302
378
 
303
- Install everything (server and skills) as a Claude Code plugin:
379
+ `wazap setup` copies them into every client it connects, so there is usually
380
+ nothing to run. The command behind it, for a harness `setup` never offered or
381
+ for a checkout you want to install by hand:
304
382
 
305
- ```
306
- /plugin marketplace add razvangirgiz/wazap
307
- /plugin install wazap@wazap
383
+ ```bash
384
+ npx wazap-mcp skills install codex # or claude-code, cursor, opencode, agents
308
385
  ```
309
386
 
310
- Every other harness gets them with one command:
387
+ With no harness named it installs into every client it finds on this machine.
388
+ For Claude Code the other route is the plugin, which carries the server as well:
311
389
 
312
- ```bash
313
- npx wazap-mcp skills install codex # or cursor, opencode, agents
390
+ ```
391
+ /plugin marketplace add razvangirgiz/wazap
392
+ /plugin install wazap@wazap
314
393
  ```
315
394
 
316
395
  | Harness | Where the five directories land |
317
396
  | --- | --- |
318
- | `claude-code` | nowhere — the plugin above already carries them |
397
+ | `claude-code` | `~/.claude/skills/` |
319
398
  | `codex` | `~/.agents/skills/`, the directory Codex documents for user skills. Cursor and OpenCode read it too |
320
399
  | `cursor` | `~/.cursor/skills/` |
321
400
  | `opencode` | `~/.config/opencode/skills/` |
@@ -324,6 +403,13 @@ npx wazap-mcp skills install codex # or cursor, opencode, agents
324
403
  Re-running overwrites, so an upgrade is the same command. `--dry-run` lists
325
404
  what it would copy.
326
405
 
406
+ A client with no skills directory is not left out. The server registers each of
407
+ the five as an MCP prompt of the same name, and sends a short `instructions`
408
+ block that names all five and says when each applies, so an agent that never saw
409
+ the skill files still follows them. That is how Claude Desktop, VS Code and
410
+ Windsurf get the workflows. A bridged session and a self-hosted HTTP server
411
+ carry them the same way.
412
+
327
413
  ## Errors
328
414
 
329
415
  Every failure is a structured `{ error, message, fix }` rather than a stack
@@ -331,7 +417,8 @@ trace, so an agent can decide whether to retry, ask the user, or stop.
331
417
 
332
418
  | Code | Meaning |
333
419
  | --- | --- |
334
- | `NOT_LINKED` | No account linked. Run `npx wazap-mcp login`. |
420
+ | `NOT_LINKED` | No account linked. Call `link_account`, or run `npx wazap-mcp login`. |
421
+ | `ALREADY_LINKED` | `link_account` was called on a session that is already linked. Call `get_status`. |
335
422
  | `SESSION_EXPIRED` | Unlinked from the phone. Run `npx wazap-mcp login`. |
336
423
  | `SESSION_CORRUPT` | Credentials unreadable. Run `npx wazap-mcp logout` then `login`. |
337
424
  | `NOT_CONNECTED` | Still connecting or reconnecting. |
@@ -363,6 +450,7 @@ created `0700` with credentials written `0600`:
363
450
  store.json chat-list snapshot
364
451
  server.lock pid of the running server
365
452
  daemon.json loopback endpoint a second wazap bridges to
453
+ oauth.json registered agents and hashed OAuth grants, when OAuth is on
366
454
  .env optional settings, see .env.example
367
455
  ```
368
456
 
@@ -410,10 +498,14 @@ WAZAP_WRITE_TOKEN=$(openssl rand -hex 32) \
410
498
  npx wazap-mcp serve --http --host 0.0.0.0 --port 8766
411
499
  ```
412
500
 
413
- Streamable HTTP at `/mcp`, with a health check at `/healthz`. Two bearer tokens:
501
+ Streamable HTTP at `/mcp`, with a health check at `/healthz`. That check answers
502
+ `{ ok, status, since }`. It turns 503 once the socket has been anything but
503
+ connected for two minutes, so a tunnel or a monitor sees a real outage rather
504
+ than a reconnect in progress. Two bearer tokens:
414
505
  the read token gets the read tools, the write token also unlocks the write
415
506
  tools, so a leaked read token can never message anyone. wazap refuses to bind a
416
- non-loopback address without a read token.
507
+ non-loopback address without a read token. Agents that cannot carry a header
508
+ sign in with [OAuth](#hosted-agents-oauth) instead.
417
509
 
418
510
  ## Self-host
419
511
 
@@ -448,9 +540,70 @@ curl -s http://127.0.0.1:8766/healthz
448
540
 
449
541
  The container publishes `8766` on loopback only; add the same TLS proxy in front. Upgrading is `git pull && docker compose up -d --build`; the volume keeps the session.
450
542
 
543
+ ### From a machine without a public address
544
+
545
+ A laptop or a box behind NAT can still serve hosted agents through a tunnel, with no port opened and TLS done at the edge. `npx wazap-mcp expose` does the whole thing with Tailscale Funnel or Cloudflare Tunnel, whichever is installed. See [Keep it running](#keep-it-running).
546
+
547
+ wazap keeps binding loopback either way; only the tunnel reaches it.
548
+
549
+ <details>
550
+ <summary>By hand, with Cloudflare Tunnel and a domain on Cloudflare</summary>
551
+
552
+ ```bash
553
+ cloudflared tunnel login
554
+ cloudflared tunnel create wazap
555
+ cloudflared tunnel route dns wazap wazap.example.com
556
+ cloudflared tunnel run --url http://127.0.0.1:8766 wazap
557
+ ```
558
+
559
+ Set `WAZAP_PUBLIC_URL=https://wazap.example.com` for OAuth and keep `cloudflared` running the way you keep wazap running (a systemd unit, a launchd agent). Tailscale Funnel or ngrok work the same way: whatever ends at `https://your-host` with `/mcp` behind it.
560
+
561
+ </details>
562
+
451
563
  ### Which clients can reach it
452
564
 
453
- Claude Code, Claude Desktop, Cursor, Codex, VS Code and any client with an "MCP URL + header" field connect with the bearer token. claude.ai Connectors require OAuth rather than a static token, so they cannot use a self-hosted wazap yet. Keep the read token in clients that only need to read; hand out the write token deliberately.
565
+ Claude Code, Claude Desktop, Cursor, Codex, VS Code, Poke and any client with an "MCP URL + header" field connect with the bearer token. Keep the read token in clients that only need to read; hand out the write token deliberately.
566
+
567
+ claude.ai Connectors, ChatGPT and some hosted agents will not take a static header. They want OAuth, which is the next section.
568
+
569
+ ### Hosted agents (OAuth)
570
+
571
+ Two more lines in the same `.env` turn wazap into its own OAuth 2.1 server:
572
+
573
+ ```bash
574
+ WAZAP_PUBLIC_URL=https://wazap.example.com
575
+ WAZAP_OAUTH_PASSWORD=$(openssl rand -base64 18)
576
+ ```
577
+
578
+ Then give an agent nothing but `https://wazap.example.com/mcp`. It finds the
579
+ authorization server at `/.well-known/oauth-protected-resource/mcp`, registers
580
+ itself (RFC 7591, so there is no client id to paste anywhere), and sends you to
581
+ a page on your own host that asks two things: the password above, and whether
582
+ this agent may only read or also send. A refresh token keeps the agent signed
583
+ in until you revoke it; access tokens rotate every 24 hours on their own.
584
+
585
+ Tested against the flow claude.ai, ChatGPT and Poke use: S256 PKCE, public
586
+ clients, `/token` with refresh, `/revoke`. The bearer tokens keep working next
587
+ to it, so a laptop client on a header and a hosted agent on OAuth share one
588
+ server.
589
+
590
+ What to know before exposing it:
591
+
592
+ - `WAZAP_PUBLIC_URL` must be `https` and a bare origin, no path: the
593
+ endpoints live at its root. The password travels to it.
594
+ - The password is the whole identity layer. Use a long one. A consent page
595
+ takes three wrong guesses and is gone; five from one address lock that
596
+ address out for fifteen minutes; twenty from anywhere close the page for
597
+ everyone for fifteen minutes.
598
+ - With OAuth on, `/mcp` never answers an unauthenticated request, whether or
599
+ not a read token is set.
600
+ - Grants live in `<data-dir>/oauth.json` as hashes. Delete the file to sign
601
+ every agent out at once, running server included; `wazap status` lists who
602
+ holds one. Disconnecting an agent on its side revokes its refresh token and
603
+ every access token it minted. A refresh token unused for ninety days is
604
+ dropped.
605
+ - A read grant never sees a write tool, whatever scope the agent requested.
606
+ The radio button on the consent page is the only thing that decides.
454
607
 
455
608
  ## Settings
456
609
 
@@ -464,6 +617,8 @@ Claude Code, Claude Desktop, Cursor, Codex, VS Code and any client with an "MCP
464
617
  | `WAZAP_TRANSPORT` | `stdio` | `stdio` or `http`. |
465
618
  | `WAZAP_HOST` / `WAZAP_PORT` | `127.0.0.1` / `8766` | HTTP bind address. |
466
619
  | `WAZAP_READ_TOKEN` / `WAZAP_WRITE_TOKEN` | unset | HTTP bearer tokens. |
620
+ | `WAZAP_PUBLIC_URL` | unset | The `https` address agents reach the server at. With the password, turns OAuth on. |
621
+ | `WAZAP_OAUTH_PASSWORD` | unset | What the consent page asks for. At least 8 characters. |
467
622
  | `WAZAP_NO_UPDATE_CHECK` | `0` | `1` stops `status` asking npm for a newer version. |
468
623
  | `WAZAP_TRANSCRIBE` | `off` | `local`, `openai` or `off`. |
469
624
  | `WAZAP_TRANSCRIBE_AUTO` | `1` | Transcribe incoming voice notes in the background. |
@@ -117,6 +117,11 @@ export function readLinkedAccount(dir) {
117
117
  export function clearAuth(dir) {
118
118
  rmSync(dir, { recursive: true, force: true });
119
119
  }
120
+ /** Everything a logout deletes: the credentials, and the store they decrypt. */
121
+ export function clearSession(p) {
122
+ clearAuth(p.authDir);
123
+ rmSync(p.storeFile, { force: true });
124
+ }
120
125
  const APP_STATE_SYNC_VERSION = "app-state-sync-version";
121
126
  /**
122
127
  * The same auth state with the app state sync journal held at zero: reads of it
package/dist/bridge.js CHANGED
@@ -2,7 +2,7 @@ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
2
2
  import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
3
3
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
4
4
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
- import { CallToolRequestSchema, CallToolResultSchema, ListToolsRequestSchema, ListToolsResultSchema, } from "@modelcontextprotocol/sdk/types.js";
5
+ import { CallToolRequestSchema, CallToolResultSchema, GetPromptRequestSchema, GetPromptResultSchema, ListPromptsRequestSchema, ListPromptsResultSchema, ListToolsRequestSchema, ListToolsResultSchema, } from "@modelcontextprotocol/sdk/types.js";
6
6
  import { WAZAP_VERSION } from "./config.js";
7
7
  import { readDaemon } from "./daemon.js";
8
8
  import { log } from "./logger.js";
@@ -31,13 +31,18 @@ export async function runBridge(daemon, daemonFile) {
31
31
  }));
32
32
  const caps = client.getServerCapabilities() ?? {};
33
33
  const server = new Server(client.getServerVersion() ?? { name: "wazap", version: daemon.version }, {
34
- // Only what we forward: the daemon has no resources or prompts, and we have
35
- // no handler for them.
36
- capabilities: { tools: caps.tools ?? {} },
34
+ // Only what we forward: the daemon has no resources, and we have no handler
35
+ // for them. The SDK refuses a handler for a capability we did not declare,
36
+ // so the prompts pair is registered under the same condition.
37
+ capabilities: { tools: caps.tools ?? {}, ...(caps.prompts ? { prompts: caps.prompts } : {}) },
37
38
  instructions: client.getInstructions(),
38
39
  });
39
40
  server.setRequestHandler(ListToolsRequestSchema, (req) => client.request({ method: "tools/list", params: req.params }, ListToolsResultSchema));
40
41
  server.setRequestHandler(CallToolRequestSchema, (req) => client.request({ method: "tools/call", params: req.params }, CallToolResultSchema));
42
+ if (caps.prompts) {
43
+ server.setRequestHandler(ListPromptsRequestSchema, (req) => client.request({ method: "prompts/list", params: req.params }, ListPromptsResultSchema));
44
+ server.setRequestHandler(GetPromptRequestSchema, (req) => client.request({ method: "prompts/get", params: req.params }, GetPromptResultSchema));
45
+ }
41
46
  client.onclose = () => leave(`the session holder (pid ${daemon.pid}) closed the connection`);
42
47
  client.onerror = () => leave(`lost the connection to the session holder (pid ${daemon.pid})`);
43
48
  // A dead daemon does not close the client: the transport retries its stream and