@wakeshift/sdk 0.7.1 → 0.7.3

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/CHANGELOG.md CHANGED
@@ -2,6 +2,19 @@
2
2
 
3
3
  What changed in each release of `@wakeshift/sdk`. 0.4.0 is the first published release: to start with it, read the [README](README.md). Its notes below, and the earlier releases', are for apps that ran the preview builds.
4
4
 
5
+ ## 0.7.3 (2026-11-02)
6
+
7
+ ### Fixed
8
+
9
+ - **An unsubscribe without the session key says so.** When a wrapped tool's `call.unsubscribe` ends nothing because the call didn't pass the conversation's `session_key` (Claude Code's calls name no conversation, so the key is the only way Wakeshift finds it), Wakeshift's block on that call now tells the agent that nothing ended, to call again with the key it was given when it subscribed, and not to subscribe again until it has. `call.unsubscribe` still returns `false`, and the note follows your tool's own text. Before, the agent saw only your text ("This chat wasn't watching…"), subscribed again without the key, and got every message twice. The built-in `unsubscribe_events` tool's reply carries the same note.
10
+
11
+ ## 0.7.2 (2026-11-02)
12
+
13
+ ### Fixed
14
+
15
+ - **`@modelcontextprotocol/server` 2.3.0 or later.** The peer dependency was `^2.0.0`, but on 2.0, 2.1 and 2.2 Claude Code's `wakeshift_wait` never completes: those releases answer `tasks/get` and `tasks/cancel` on protocol 2026-07-28 with "Method not found" themselves, before `attach` sees them ([modelcontextprotocol/typescript-sdk#2598](https://github.com/modelcontextprotocol/typescript-sdk/issues/2598), fixed in 2.3.0 by [#2599](https://github.com/modelcontextprotocol/typescript-sdk/pull/2599)). So conversations told to use the wait tool weren't woken. Everything else (wrapped tools, the built-in tools, MCP Events with `events/poll` and webhooks) works on 2.0 and later. The peer range is now `^2.3.0`: upgrade with `npm install @modelcontextprotocol/server@^2.3.0`. `@modelcontextprotocol/sdk` 1.x is unaffected.
16
+ - **`attach` warns on an older 2.x.** Given a server from `@modelcontextprotocol/server` before 2.3.0, `attach` warns once (through `onWarning`), naming the version to upgrade to.
17
+
5
18
  ## 0.7.1 (2026-11-01)
6
19
 
7
20
  ### Fixed
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Let agents subscribe to things in your app. You define the events your app offers, serve them on your MCP server, and emit them when they happen; Wakeshift wakes every subscribed agent, whether it's Claude Code, Codex, ChatGPT or another. Your events follow MCP Events: clients that speak it subscribe natively, and Wakeshift bridges every other agent. You don't deal with harnesses.
4
4
 
5
- Node 22 or later. The package is ESM-only: load it with `import`, from an ES module (`"type": "module"`, or a `.mjs` or `.mts` file). It has no CommonJS build, so `require("@wakeshift/sdk")` works only where Node can require ES modules. It works with either MCP TypeScript SDK: `@modelcontextprotocol/server` 2.x (2.0 or later), which this page uses, or `@modelcontextprotocol/sdk` 1.x (1.23 or later: the first that takes zod 4; [below](#using-modelcontextprotocolsdk-1x)). Its peer dependencies are the one you use and `zod`: 4.2 or later with 2.x, 3.25 or later with 1.x. Import `z` from `"zod"`, not `"zod/v4"`: the SDK's schemas are built from `"zod"`, and the MCP SDK refuses a schema that mixes the two.
5
+ Node 22 or later. The package is ESM-only: load it with `import`, from an ES module (`"type": "module"`, or a `.mjs` or `.mts` file). It has no CommonJS build, so `require("@wakeshift/sdk")` works only where Node can require ES modules. It works with either MCP TypeScript SDK: `@modelcontextprotocol/server` 2.x (2.3 or later), which this page uses, or `@modelcontextprotocol/sdk` 1.x (1.23 or later: the first that takes zod 4; [below](#using-modelcontextprotocolsdk-1x)). Its peer dependencies are the one you use and `zod`: 4.2 or later with 2.x, 3.25 or later with 1.x. Import `z` from `"zod"`, not `"zod/v4"`: the SDK's schemas are built from `"zod"`, and the MCP SDK refuses a schema that mixes the two.
6
6
 
7
7
  ## Install
8
8
 
@@ -348,6 +348,8 @@ npm run test:v2 # the same unit tests on @modelcontextprotocol/server 2.x
348
348
  npm run build # dist/
349
349
  ```
350
350
 
351
+ `sh scripts/mcp-floor.sh` installs the oldest `@modelcontextprotocol/server` the peer range allows (unsaved), for running `npm run test:v2` on it; `npm ci` puts the locked versions back.
352
+
351
353
  The end-to-end tests (`test/e2e*.test.ts`) run against a Wakeshift server, so they run in Wakeshift's own repository and skip here.
352
354
 
353
355
  ## Contributing and security
package/dist/host.js CHANGED
@@ -15,7 +15,10 @@
15
15
  // and a params schema on 2.x;
16
16
  // - tasks/get and tasks/cancel: 2.x answers them on protocol 2026-07-28
17
17
  // only for a handler registered with a params schema (the tasks
18
- // extension's methods), so setTaskMethod registers them that way;
18
+ // extension's methods), so setTaskMethod registers them that way.
19
+ // Before 2.3.0 it refused them there whatever was registered
20
+ // (modelcontextprotocol/typescript-sdk#2598, fixed by #2599), so the
21
+ // peer range starts at 2.3.0 and routesTasks tells attach to warn;
19
22
  // - protocol 2026-07-28: 1.x doesn't speak it, so discover.ts teaches it;
20
23
  // 2.x speaks it itself (server/discover, resultType, ttlMs and
21
24
  // cacheScope).
@@ -29,6 +32,12 @@ import { z } from "zod";
29
32
  import * as z4 from "zod/v4";
30
33
  import { normalizeObjectSchema, safeParseAsync } from "./zod.js";
31
34
  const VERSION_META = "io.modelcontextprotocol/protocolVersion";
35
+ /**
36
+ * @internal The oldest @modelcontextprotocol/server that serves tasks/get
37
+ * and tasks/cancel on protocol 2026-07-28 (modelcontextprotocol/typescript-sdk#2599):
38
+ * the floor of the SDK's peer range for it.
39
+ */
40
+ export const TASKS_MIN_SERVER = "2.3.0";
32
41
  function lowOf(server) {
33
42
  return server.server;
34
43
  }
@@ -210,6 +219,9 @@ class V1Host extends BaseHost {
210
219
  // setRequestHandler would ask for its own tasks capability, an older
211
220
  // revision's, never advertised.)
212
221
  }
222
+ routesTasks() {
223
+ return true;
224
+ }
213
225
  async validOutput(outputSchema, result) {
214
226
  // McpServer 1.x's validateToolOutput: an object schema, and structured content that parses.
215
227
  if (!outputSchema)
@@ -243,6 +255,15 @@ class V2Host extends BaseHost {
243
255
  throw Object.assign(new Error("Method not found"), { code: -32601 });
244
256
  });
245
257
  }
258
+ routesTasks() {
259
+ // 2.3.0's fix keeps the methods registered with a schema in this set,
260
+ // and lets them past the era gate; 2.0 to 2.2 have no such set. 2.x
261
+ // doesn't expose its version (nor its package.json), so the fix is
262
+ // what's checked, private like _requestHandlers. A release that renames
263
+ // it would only warn wrongly, and fails v2.test.ts's check that the
264
+ // installed 2.x doesn't warn, on the Dependabot bump that brings it.
265
+ return this.low._customSchemaRequestMethods instanceof Set;
266
+ }
246
267
  async validOutput(outputSchema, result) {
247
268
  // McpServer 2.x's validateToolOutput: structured content (any JSON
248
269
  // value) that the output schema (a Standard Schema) accepts.
@@ -362,6 +383,7 @@ export function toolsOnlyHost(opts) {
362
383
  },
363
384
  setMethod: noop,
364
385
  setTaskMethod: noop,
386
+ routesTasks: () => true,
365
387
  handlers: () => null,
366
388
  clientName: () => undefined,
367
389
  clientCapabilities: () => undefined,
package/dist/tasks.js CHANGED
@@ -16,6 +16,7 @@
16
16
  // zero-install path (Claude Code's Monitor). Everything else is unchanged.
17
17
  import { WakeshiftError } from "./errors.js";
18
18
  import { TASKS_EXTENSION, takesTasks } from "./discover.js";
19
+ import { TASKS_MIN_SERVER } from "./host.js";
19
20
  import { RpcError } from "./mcp.js";
20
21
  import { WAKE_ARG_DESCRIPTIONS } from "./toolcall.js";
21
22
  import { toolCallOf } from "./wakeshift.js";
@@ -52,6 +53,9 @@ export function serveTasks(wake, host, callerOf) {
52
53
  const handlers = host.handlers();
53
54
  if (!handlers)
54
55
  return; // a future SDK: nothing to hook (no wait tool)
56
+ if (!host.routesTasks()) {
57
+ wake.warnOnce("tasks-routing", `wakeshift: this server's @modelcontextprotocol/server is older than ${TASKS_MIN_SERVER} (2.0 to 2.2 answer tasks/get with "Method not found" on protocol 2026-07-28 themselves), so Claude Code's ${WAIT_TOOL} never completes and conversations that use it aren't woken. Upgrade @modelcontextprotocol/server to ${TASKS_MIN_SERVER} or later.`);
58
+ }
55
59
  const call = (raw, args) => {
56
60
  const { user, client } = callerOf(raw);
57
61
  return toolCallOf(host.req(raw), client, user, args, WAIT_TOOL);
package/dist/toolcall.js CHANGED
@@ -240,6 +240,9 @@ export class CallScope {
240
240
  armed = false;
241
241
  created = [];
242
242
  nativeLines = [];
243
+ // Wakeshift's notes from the call's unsubscribes (one that ended nothing
244
+ // because the call passed no session key), for the block.
245
+ notes = [];
243
246
  inflight = new Set();
244
247
  queue = Promise.resolve();
245
248
  // The client's name identify gave, for a request that names none.
@@ -330,7 +333,16 @@ export class CallScope {
330
333
  const known = event.parseArgs(args);
331
334
  if (this.native)
332
335
  return this.endNative(event.name, known);
333
- const out = await this.at.wake.requestApp("POST", "/event-subscriptions/unsubscribe", { call: this.wire(), name: event.name, arguments: known });
336
+ const out = await this.at.wake.requestApp("POST", "/event-subscriptions/unsubscribe", {
337
+ call: this.wire(),
338
+ name: event.name,
339
+ arguments: known,
340
+ });
341
+ // addition: the call passed no session key, so it ended nothing; the
342
+ // block says to call again with it.
343
+ const note = out.addition?.text?.trim();
344
+ if (note && !this.notes.includes(note))
345
+ this.notes.push(note);
334
346
  return !!out.ended;
335
347
  });
336
348
  }
@@ -402,7 +414,16 @@ export class CallScope {
402
414
  // should subscribe to. A call that names no conversation, and subscribed
403
415
  // nothing, gets nothing (null). Only a failure for a call that subscribed
404
416
  // is thrown: without a subscription, the block is a courtesy.
417
+ //
418
+ // Notes from the call's unsubscribes come first, whatever else it gets.
405
419
  async addition() {
420
+ const add = await this.fetchAddition();
421
+ if (this.notes.length === 0)
422
+ return add;
423
+ const text = [this.notes.join(" "), add?.text?.trim() ?? ""].filter(Boolean).join("\n\n");
424
+ return { ...(add ?? {}), text };
425
+ }
426
+ async fetchAddition() {
406
427
  const wire = this.wire();
407
428
  if (!this.pending && this.nativeLines.length === 0 && !wire.session && !wire.conversation && !namesConversation(wire.meta))
408
429
  return null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wakeshift/sdk",
3
- "version": "0.7.1",
3
+ "version": "0.7.3",
4
4
  "description": "Let agents subscribe to things in your app: Wakeshift wakes them when you emit an event.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Clawvisor Inc. <support@wakeshift.ai>",
@@ -62,7 +62,7 @@
62
62
  },
63
63
  "peerDependencies": {
64
64
  "@modelcontextprotocol/sdk": "^1.23.0",
65
- "@modelcontextprotocol/server": "^2.0.0",
65
+ "@modelcontextprotocol/server": "^2.3.0",
66
66
  "zod": "^3.25.0 || ^4.0.0",
67
67
  "@mastra/mcp": "^2.7.0",
68
68
  "xmcp": "^1.9.0"