@wakeshift/sdk 0.5.2 → 0.6.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/CHANGELOG.md +17 -0
- package/README.md +56 -2
- package/dist/discover.d.ts +2 -2
- package/dist/discover.js +67 -46
- package/dist/discover.js.map +1 -1
- package/dist/events.d.ts +13 -9
- package/dist/events.js +80 -84
- package/dist/events.js.map +1 -1
- package/dist/host.d.ts +2 -0
- package/dist/host.js +203 -0
- package/dist/host.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp.d.ts +92 -0
- package/dist/mcp.js +22 -0
- package/dist/mcp.js.map +1 -0
- package/dist/tasks.js +50 -38
- package/dist/tasks.js.map +1 -1
- package/dist/toolcall.d.ts +71 -24
- package/dist/toolcall.js +59 -60
- package/dist/toolcall.js.map +1 -1
- package/dist/wakeshift.d.ts +7 -3
- package/dist/wakeshift.js +12 -11
- package/dist/wakeshift.js.map +1 -1
- package/dist/zod.d.ts +16 -0
- package/dist/zod.js +95 -0
- package/dist/zod.js.map +1 -0
- package/package.json +15 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,23 @@
|
|
|
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.6.0 (2026-10-31)
|
|
6
|
+
|
|
7
|
+
### Breaking
|
|
8
|
+
|
|
9
|
+
- Both MCP SDKs are optional peer dependencies: install the one you use. npm no longer installs `@modelcontextprotocol/sdk` for you, so list it in your app's own dependencies if your code imports it (as the install line has always said).
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **`@modelcontextprotocol/server` 2.x.** `attach` now takes an `McpServer` from the MCP TypeScript SDK 2.x (2.0 or later) as well as from `@modelcontextprotocol/sdk` 1.x, and tells them apart by the server you pass. Everything works the same on both: wrapped tools (Wakeshift's block in text and in `structuredContent`, rollback, `call.subscribe`), the built-in tools, MCP Events (`events/list`, `events/subscribe`, `events/unsubscribe`, `events/poll`), Claude Code's `wakeshift_wait` with `tasks/get` and `tasks/cancel`, and who's calling. 2.x speaks protocol 2026-07-28 itself, so with `createMcpHandler` clients on either revision connect with nothing more to set up. See [Using @modelcontextprotocol/server 2.x](README.md#using-modelcontextprotocolserver-2x).
|
|
14
|
+
- On 2.x, `identify`, `events.native` and a wrapped tool's `call.extra` get 2.x's request context (`ctx`: the token in `ctx.http?.authInfo`), and are typed as it. On 1.x they get `extra`, as before.
|
|
15
|
+
- `attached.inputs` and `attached.output` take a zod object as well as a shape (`attached.inputs(z.object({ table: z.string() }))`), as 2.x's `registerTool` does. Shapes work as before.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- The SDK's published types no longer import either MCP SDK, so they load with only one installed. `attached.events` returns a callback typed from your tool's arguments and your MCP SDK's context; `ToolCallExtra` is now the parts of a request's context Wakeshift reads, whichever SDK serves it (a wrapped tool's `call.extra` is still your MCP SDK's own type). If you passed a `ToolCallExtra` where 1.x's `RequestHandlerExtra` is expected, use `call.extra` instead.
|
|
20
|
+
- A JSON-RPC error from `attach`'s own methods (for example `events/subscribe` for an event your app doesn't offer) carries just its message, without the MCP SDK 1.x's `MCP error <code>: ` prefix in front of it.
|
|
21
|
+
|
|
5
22
|
## 0.5.2 (2026-10-30)
|
|
6
23
|
|
|
7
24
|
### Added
|
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.
|
|
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/sdk` 1.x (1.23 or later: the first that takes zod 4) or `@modelcontextprotocol/server` 2.x ([below](#using-modelcontextprotocolserver-2x)). Its peer dependencies are the one you use and `zod` (3.25 or later, or 4; 4.2 or later with 2.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
|
|
|
@@ -10,6 +10,8 @@ Node 22 or later. The package is ESM-only: load it with `import`, from an ES mod
|
|
|
10
10
|
npm install @wakeshift/sdk @modelcontextprotocol/sdk zod
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
+
On `@modelcontextprotocol/server` 2.x, install that instead of `@modelcontextprotocol/sdk`.
|
|
14
|
+
|
|
13
15
|
Install the package, not a checkout of this repository (a `file:` dependency): a `file:` dependency links the directory along with its `node_modules`, so the SDK can load its own development copy of zod instead of yours, and the MCP SDK then fails with "Mixed Zod versions detected in object shape". To try a change of your own, `npm pack` and install the tarball it writes.
|
|
14
16
|
|
|
15
17
|
## Quickstart: a CI bot
|
|
@@ -153,6 +155,57 @@ server.registerTool(
|
|
|
153
155
|
|
|
154
156
|
A wrapped tool that subscribes to nothing, like `look`, still gets what Wakeshift has for the conversation calling it: occurrences held for an agent Wakeshift can't wake, or what it needs to reconnect. Usually that's nothing.
|
|
155
157
|
|
|
158
|
+
## Using @modelcontextprotocol/server 2.x
|
|
159
|
+
|
|
160
|
+
`attach` takes an `McpServer` from either MCP TypeScript SDK: `@modelcontextprotocol/sdk` 1.x or `@modelcontextprotocol/server` 2.x (2.0 or later). It tells them apart by the server you pass, and everything on this page works the same on both.
|
|
161
|
+
|
|
162
|
+
```sh
|
|
163
|
+
npm install @wakeshift/sdk @modelcontextprotocol/server @modelcontextprotocol/node zod
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
2.x serves HTTP with `createMcpHandler`, which makes a server for each request, so attach in the function that makes it. Define your events once, outside it:
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
import { createServer } from "node:http"
|
|
170
|
+
import { McpServer, createMcpHandler } from "@modelcontextprotocol/server"
|
|
171
|
+
import { toNodeHandler } from "@modelcontextprotocol/node"
|
|
172
|
+
import { z } from "zod"
|
|
173
|
+
import { Wakeshift } from "@wakeshift/sdk"
|
|
174
|
+
|
|
175
|
+
const wake = new Wakeshift({ key: process.env.WAKESHIFT_KEY! })
|
|
176
|
+
|
|
177
|
+
const ciFinished = wake.defineEvent("ci.finished", {
|
|
178
|
+
description: "CI finished on a GitHub repo",
|
|
179
|
+
args: z.object({ owner: z.string(), repo: z.string() }),
|
|
180
|
+
payload: z.object({ branch: z.string(), conclusion: z.string() }),
|
|
181
|
+
text: (run, { owner, repo }) => `CI ${run.conclusion} on ${owner}/${repo} ${run.branch}`,
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
const mcp = createMcpHandler(() => {
|
|
185
|
+
const server = new McpServer({ name: "ci-bot", version: "1.0.0" })
|
|
186
|
+
// identify gets 2.x's request context: your auth middleware's verified token is ctx.http?.authInfo.
|
|
187
|
+
const attached = wake.attach(server, { identify: (ctx) => ({ user: myUser(ctx.http?.authInfo) }) })
|
|
188
|
+
server.registerTool(
|
|
189
|
+
"watch_ci",
|
|
190
|
+
{ description: "Watch CI on a repo", inputSchema: attached.inputs(z.object({ owner: z.string(), repo: z.string() })) },
|
|
191
|
+
attached.events("watch_ci", async ({ owner, repo }, call) => {
|
|
192
|
+
await call.subscribe(ciFinished, { owner, repo }, { reason: `Watching ${owner}/${repo}` })
|
|
193
|
+
return `Watching CI on ${owner}/${repo}.`
|
|
194
|
+
}),
|
|
195
|
+
)
|
|
196
|
+
return server
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
createServer(toNodeHandler(mcp)).listen(3000)
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
What's different on 2.x:
|
|
203
|
+
|
|
204
|
+
- `identify`, `events.native` and a wrapped tool's `call.extra` get 2.x's request context (`ctx`) instead of 1.x's `extra`: the verified token is `ctx.http?.authInfo`, and the HTTP request is `ctx.http?.req`.
|
|
205
|
+
- `attached.inputs` and `attached.output` take a zod object, as 2.x's `registerTool` does: `attached.inputs(z.object({ … }))`. A bare shape works too.
|
|
206
|
+
- Write your schemas, events' included, with zod 4 (4.2 or later), which 2.x requires.
|
|
207
|
+
- 2.x speaks MCP protocol 2026-07-28 itself, and `createMcpHandler` answers older clients too, so clients on either revision connect with nothing more to set up. Wakeshift lists its tools for each request's client, so `tools/list` is cached by that client only, whatever cache hint you set for it.
|
|
208
|
+
|
|
156
209
|
## Reference
|
|
157
210
|
|
|
158
211
|
### `new Wakeshift({ key, core?, fetch?, timeoutMs?, onWarning? })`
|
|
@@ -201,7 +254,8 @@ The guides and the full reference are at [wakeshift.ai/docs](https://wakeshift.a
|
|
|
201
254
|
```sh
|
|
202
255
|
npm ci
|
|
203
256
|
npm run typecheck
|
|
204
|
-
npm test # unit tests (node:test) and the README's examples
|
|
257
|
+
npm test # unit tests (node:test) on @modelcontextprotocol/sdk 1.x, and the README's examples
|
|
258
|
+
npm run test:v2 # the same unit tests on @modelcontextprotocol/server 2.x
|
|
205
259
|
npm run build # dist/
|
|
206
260
|
```
|
|
207
261
|
|
package/dist/discover.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
1
|
+
import { STATELESS_VERSION } from "./host.js";
|
|
2
|
+
export { STATELESS_VERSION };
|
|
3
3
|
/** The MCP tasks extension's capability key. */
|
|
4
4
|
export declare const TASKS_EXTENSION = "io.modelcontextprotocol/tasks";
|
package/dist/discover.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
// Protocol 2026-07-28
|
|
2
|
-
//
|
|
3
|
-
//
|
|
1
|
+
// Protocol 2026-07-28. MCP Events is defined only for 2026-07-28 and later,
|
|
2
|
+
// and some clients speak nothing older (OpenClaw).
|
|
3
|
+
//
|
|
4
|
+
// @modelcontextprotocol/server 2.x speaks it itself: server/discover,
|
|
5
|
+
// resultType, and ttlMs and cacheScope on the lists. attach only varies
|
|
6
|
+
// tools/list per request (below), so it marks that list private.
|
|
7
|
+
//
|
|
8
|
+
// @modelcontextprotocol/sdk 1.x doesn't. With attach, a 1.x server whose
|
|
4
9
|
// transport is stateless (no sessions) also answers those clients:
|
|
5
10
|
//
|
|
6
11
|
// - server/discover, with the server's capabilities (the events keys
|
|
@@ -10,36 +15,37 @@
|
|
|
10
15
|
// - resultType: "complete" on every result of a 2026-07-28 request, as
|
|
11
16
|
// that revision requires (clients on the official 2.x SDKs refuse a
|
|
12
17
|
// result without it), and ttlMs and cacheScope on server/discover and
|
|
13
|
-
// the lists (Claude Code connects the old way without them)
|
|
14
|
-
// - tools/list without subscribe_events for a request that declares the
|
|
15
|
-
// events extension in its own capabilities (2026-07-28 has no
|
|
16
|
-
// initialize, so each request carries them).
|
|
18
|
+
// the lists (Claude Code connects the old way without them).
|
|
17
19
|
//
|
|
18
|
-
// A stateful transport refuses a request without a session before any
|
|
20
|
+
// A stateful 1.x transport refuses a request without a session before any
|
|
19
21
|
// handler runs, so a server with sessions is unchanged: its clients fall
|
|
20
|
-
// back to initialize, as they do today.
|
|
21
|
-
//
|
|
22
|
+
// back to initialize, as they do today.
|
|
23
|
+
//
|
|
24
|
+
// On both, tools/list leaves out subscribe_events for a request that
|
|
25
|
+
// declares the events extension in its own capabilities (2026-07-28 has no
|
|
26
|
+
// initialize, so each request carries them).
|
|
22
27
|
import { z } from "zod";
|
|
23
|
-
import { SUPPORTED_PROTOCOL_VERSIONS } from "@modelcontextprotocol/sdk/types.js";
|
|
24
28
|
import { EXTENSION_KEY, RESULT_TYPE } from "./spec.js";
|
|
25
|
-
|
|
26
|
-
export
|
|
27
|
-
const VERSION_META = "io.modelcontextprotocol/protocolVersion";
|
|
29
|
+
import { STATELESS_VERSION, is2026, v1Req } from "./host.js";
|
|
30
|
+
export { STATELESS_VERSION };
|
|
28
31
|
const CAPABILITIES_META = "io.modelcontextprotocol/clientCapabilities";
|
|
29
32
|
const SERVER_INFO_META = "io.modelcontextprotocol/serverInfo";
|
|
33
|
+
// The MCP SDK 1.x's list of supported versions, which its transport checks
|
|
34
|
+
// the MCP-Protocol-Version header against: the same module the app's own
|
|
35
|
+
// copy of the SDK loaded (loaded only if it's installed).
|
|
36
|
+
const v1Types = await import(
|
|
37
|
+
/* webpackIgnore: true */ String("@modelcontextprotocol/sdk/types.js")).catch(() => undefined);
|
|
30
38
|
// The list methods whose 2026-07-28 results carry ttlMs and cacheScope.
|
|
31
39
|
const LISTS = new Set(["tools/list", "prompts/list", "resources/list", "resources/templates/list"]);
|
|
32
|
-
// is2026 reports whether a request is a 2026-07-28 one: its _meta names the
|
|
33
|
-
// version, or its MCP-Protocol-Version header does.
|
|
34
|
-
function is2026(request, extra) {
|
|
35
|
-
if (request?.params?._meta?.[VERSION_META] === STATELESS_VERSION)
|
|
36
|
-
return true;
|
|
37
|
-
const h = extra?.requestInfo?.headers;
|
|
38
|
-
const v = h?.["mcp-protocol-version"] ?? h?.["MCP-Protocol-Version"];
|
|
39
|
-
return (Array.isArray(v) ? v[0] : v) === STATELESS_VERSION;
|
|
40
|
-
}
|
|
41
40
|
/** The MCP tasks extension's capability key. */
|
|
42
41
|
export const TASKS_EXTENSION = "io.modelcontextprotocol/tasks";
|
|
42
|
+
// reqOf reads meta, and extra's headers (an already-read request's, or
|
|
43
|
+
// 1.x's requestInfo), as one request.
|
|
44
|
+
function reqOf(meta, extra) {
|
|
45
|
+
if (extra && typeof extra.header === "function")
|
|
46
|
+
return { ...extra, meta };
|
|
47
|
+
return v1Req({ ...(extra ?? {}), _meta: meta });
|
|
48
|
+
}
|
|
43
49
|
/**
|
|
44
50
|
* @internal Whether a request (its _meta, as a tool callback's extra has
|
|
45
51
|
* it, and its headers) is protocol 2026-07-28 and declares the tasks
|
|
@@ -47,35 +53,45 @@ export const TASKS_EXTENSION = "io.modelcontextprotocol/tasks";
|
|
|
47
53
|
* (tasks.ts).
|
|
48
54
|
*/
|
|
49
55
|
export function takesTasks(meta, extra) {
|
|
50
|
-
if (!is2026(
|
|
56
|
+
if (!is2026(reqOf(meta, extra)))
|
|
51
57
|
return false;
|
|
52
58
|
const ext = meta?.[CAPABILITIES_META]?.extensions;
|
|
53
59
|
return !!ext && typeof ext === "object" && !Array.isArray(ext) && TASKS_EXTENSION in ext;
|
|
54
60
|
}
|
|
55
|
-
function declaresEvents(
|
|
56
|
-
const ext =
|
|
61
|
+
function declaresEvents(meta) {
|
|
62
|
+
const ext = meta?.[CAPABILITIES_META]?.extensions;
|
|
57
63
|
return !!ext && typeof ext === "object" && EXTENSION_KEY in ext;
|
|
58
64
|
}
|
|
59
65
|
/** @internal Makes server answer 2026-07-28 requests (see the file's comment). */
|
|
60
|
-
export function serveStateless(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
if (!versions.includes(STATELESS_VERSION))
|
|
65
|
-
versions.unshift(STATELESS_VERSION);
|
|
66
|
-
const low = server.server;
|
|
67
|
-
const handlers = low._requestHandlers;
|
|
68
|
-
if (!(handlers instanceof Map))
|
|
69
|
-
return; // a future SDK without it: it speaks 2026-07-28 itself
|
|
66
|
+
export function serveStateless(host, opts = {}) {
|
|
67
|
+
const handlers = host.handlers();
|
|
68
|
+
if (!handlers)
|
|
69
|
+
return; // a future SDK without it: nothing to vary
|
|
70
70
|
const hidden = new Set(opts.bridgedOnly ?? []);
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
const v1 = host.version === 1;
|
|
72
|
+
if (v1) {
|
|
73
|
+
// Mutating the SDK's own list is how 1.x can be taught a version.
|
|
74
|
+
const versions = v1Types?.SUPPORTED_PROTOCOL_VERSIONS;
|
|
75
|
+
if (Array.isArray(versions) && !versions.includes(STATELESS_VERSION))
|
|
76
|
+
versions.unshift(STATELESS_VERSION);
|
|
77
|
+
}
|
|
78
|
+
const wrap = (method, h) => (async (request, raw) => {
|
|
79
|
+
const result = await h(request, raw);
|
|
80
|
+
const req = host.req(raw);
|
|
81
|
+
if (!is2026(req) || !result || typeof result !== "object")
|
|
74
82
|
return result;
|
|
75
|
-
|
|
76
|
-
|
|
83
|
+
let out = result;
|
|
84
|
+
if (method === "tools/list" && hidden.size > 0 && declaresEvents(req.meta) && Array.isArray(out.tools)) {
|
|
85
|
+
out = { ...out, tools: out.tools.filter((t) => !hidden.has(t?.name)) };
|
|
86
|
+
}
|
|
87
|
+
if (!v1) {
|
|
88
|
+
// tools/list differs by what each request declares (this filter,
|
|
89
|
+
// the wait tool), so it's cached by this client only, whatever
|
|
90
|
+
// cache hint the app set; 2.x fills in the rest.
|
|
91
|
+
return method === "tools/list" ? { ...out, cacheScope: "private" } : out;
|
|
77
92
|
}
|
|
78
|
-
|
|
93
|
+
if (out.resultType === undefined)
|
|
94
|
+
out = { ...out, resultType: RESULT_TYPE };
|
|
79
95
|
// A list's result says how long a client may cache it, as 2026-07-28
|
|
80
96
|
// requires (Claude Code falls back to initialize without it): not at
|
|
81
97
|
// all, and for this client only, since tools/list differs by what
|
|
@@ -84,14 +100,19 @@ export function serveStateless(server, opts = {}) {
|
|
|
84
100
|
return { ...out, ttlMs: 0, cacheScope: "private" };
|
|
85
101
|
return out;
|
|
86
102
|
});
|
|
103
|
+
const wraps = (method) => v1 || method === "tools/list";
|
|
87
104
|
for (const [method, h] of handlers)
|
|
88
|
-
|
|
105
|
+
if (wraps(method))
|
|
106
|
+
handlers.set(method, wrap(method, h));
|
|
89
107
|
const set = handlers.set.bind(handlers);
|
|
90
|
-
handlers.set = (method, h) => set(method, wrap(method, h));
|
|
91
|
-
|
|
108
|
+
handlers.set = (method, h) => set(method, wraps(method) ? wrap(method, h) : h);
|
|
109
|
+
if (!v1)
|
|
110
|
+
return;
|
|
111
|
+
const low = host.server.server;
|
|
112
|
+
low.setRequestHandler(z.object({ method: z.literal("server/discover"), params: z.any().optional() }), async () => {
|
|
92
113
|
const out = {
|
|
93
114
|
resultType: RESULT_TYPE,
|
|
94
|
-
supportedVersions: [...
|
|
115
|
+
supportedVersions: [...(v1Types?.SUPPORTED_PROTOCOL_VERSIONS ?? [STATELESS_VERSION])],
|
|
95
116
|
// Cacheable results carry these on 2026-07-28 (Claude Code refuses a
|
|
96
117
|
// server/discover without them, and connects the old way).
|
|
97
118
|
ttlMs: 0,
|
package/dist/discover.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discover.js","sourceRoot":"","sources":["../src/discover.ts"],"names":[],"mappings":"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","sourcesContent":["// Protocol 2026-07-28 for an app on the MCP TypeScript SDK 1.x, which\n// doesn't have it: MCP Events is defined only for 2026-07-28 and later, and\n// some clients speak nothing older (OpenClaw). With attach, a server whose\n// transport is stateless (no sessions) also answers those clients:\n//\n// - server/discover, with the server's capabilities (the events keys\n// included) and the versions it takes;\n// - 2026-07-28 in the SDK's list of supported versions, so the\n// Streamable HTTP transport accepts its MCP-Protocol-Version header;\n// - resultType: \"complete\" on every result of a 2026-07-28 request, as\n// that revision requires (clients on the official 2.x SDKs refuse a\n// result without it), and ttlMs and cacheScope on server/discover and\n// the lists (Claude Code connects the old way without them);\n// - tools/list without subscribe_events for a request that declares the\n// events extension in its own capabilities (2026-07-28 has no\n// initialize, so each request carries them).\n//\n// A stateful transport refuses a request without a session before any\n// handler runs, so a server with sessions is unchanged: its clients fall\n// back to initialize, as they do today. The MCP TypeScript SDK 2.x speaks\n// 2026-07-28 itself.\n\nimport { z } from \"zod\";\nimport { SUPPORTED_PROTOCOL_VERSIONS } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { EXTENSION_KEY, RESULT_TYPE } from \"./spec.js\";\n\n/** The protocol revision that has server/discover and MCP Events. */\nexport const STATELESS_VERSION = \"2026-07-28\";\n\nconst VERSION_META = \"io.modelcontextprotocol/protocolVersion\";\nconst CAPABILITIES_META = \"io.modelcontextprotocol/clientCapabilities\";\nconst SERVER_INFO_META = \"io.modelcontextprotocol/serverInfo\";\n\ntype Handler = (request: any, extra: any) => Promise<any>;\n\n// The list methods whose 2026-07-28 results carry ttlMs and cacheScope.\nconst LISTS = new Set([\"tools/list\", \"prompts/list\", \"resources/list\", \"resources/templates/list\"]);\n\n// is2026 reports whether a request is a 2026-07-28 one: its _meta names the\n// version, or its MCP-Protocol-Version header does.\nfunction is2026(request: any, extra: any): boolean {\n if (request?.params?._meta?.[VERSION_META] === STATELESS_VERSION) return true;\n const h = extra?.requestInfo?.headers;\n const v = h?.[\"mcp-protocol-version\"] ?? h?.[\"MCP-Protocol-Version\"];\n return (Array.isArray(v) ? v[0] : v) === STATELESS_VERSION;\n}\n\n/** The MCP tasks extension's capability key. */\nexport const TASKS_EXTENSION = \"io.modelcontextprotocol/tasks\";\n\n/**\n * @internal Whether a request (its _meta, as a tool callback's extra has\n * it, and its headers) is protocol 2026-07-28 and declares the tasks\n * extension in its own capabilities: a client that takes MCP tasks\n * (tasks.ts).\n */\nexport function takesTasks(meta: Record<string, unknown> | undefined, extra?: any): boolean {\n if (!is2026({ params: { _meta: meta } }, extra)) return false;\n const ext = (meta?.[CAPABILITIES_META] as { extensions?: unknown } | undefined)?.extensions;\n return !!ext && typeof ext === \"object\" && !Array.isArray(ext) && TASKS_EXTENSION in (ext as object);\n}\n\nfunction declaresEvents(request: any): boolean {\n const ext = request?.params?._meta?.[CAPABILITIES_META]?.extensions;\n return !!ext && typeof ext === \"object\" && EXTENSION_KEY in ext;\n}\n\n/** @internal Makes server answer 2026-07-28 requests (see the file's comment). */\nexport function serveStateless(server: McpServer, opts: { bridgedOnly?: readonly string[] } = {}): void {\n // The SDK's own list, which its transport checks the header against.\n // Mutating it is how 1.x can be taught a version; 2.x already has it.\n const versions = SUPPORTED_PROTOCOL_VERSIONS as string[];\n if (!versions.includes(STATELESS_VERSION)) versions.unshift(STATELESS_VERSION);\n\n const low = server.server as any;\n const handlers = low._requestHandlers as Map<string, Handler> | undefined;\n if (!(handlers instanceof Map)) return; // a future SDK without it: it speaks 2026-07-28 itself\n const hidden = new Set(opts.bridgedOnly ?? []);\n const wrap = (method: string, h: Handler): Handler =>\n (async (request: any, extra: any) => {\n const result = await h(request, extra);\n if (!is2026(request, extra) || !result || typeof result !== \"object\") return result;\n if (method === \"tools/list\" && hidden.size > 0 && declaresEvents(request) && Array.isArray(result.tools)) {\n result.tools = result.tools.filter((t: any) => !hidden.has(t?.name));\n }\n const out = result.resultType === undefined ? { ...result, resultType: RESULT_TYPE } : result;\n // A list's result says how long a client may cache it, as 2026-07-28\n // requires (Claude Code falls back to initialize without it): not at\n // all, and for this client only, since tools/list differs by what\n // each request declares.\n if (LISTS.has(method) && out.ttlMs === undefined) return { ...out, ttlMs: 0, cacheScope: \"private\" };\n return out;\n }) as Handler;\n for (const [method, h] of handlers) handlers.set(method, wrap(method, h));\n const set = handlers.set.bind(handlers);\n handlers.set = (method: string, h: Handler) => set(method, wrap(method, h));\n\n server.server.setRequestHandler(z.object({ method: z.literal(\"server/discover\"), params: z.any().optional() }) as any, async () => {\n const out: Record<string, unknown> = {\n resultType: RESULT_TYPE,\n supportedVersions: [...versions],\n // Cacheable results carry these on 2026-07-28 (Claude Code refuses a\n // server/discover without them, and connects the old way).\n ttlMs: 0,\n cacheScope: \"public\",\n capabilities: low.getCapabilities(),\n _meta: { [SERVER_INFO_META]: low._serverInfo },\n };\n if (low._instructions) out.instructions = low._instructions;\n return out as any;\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"discover.js","sourceRoot":"","sources":["../src/discover.ts"],"names":[],"mappings":"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","sourcesContent":["// Protocol 2026-07-28. MCP Events is defined only for 2026-07-28 and later,\n// and some clients speak nothing older (OpenClaw).\n//\n// @modelcontextprotocol/server 2.x speaks it itself: server/discover,\n// resultType, and ttlMs and cacheScope on the lists. attach only varies\n// tools/list per request (below), so it marks that list private.\n//\n// @modelcontextprotocol/sdk 1.x doesn't. With attach, a 1.x server whose\n// transport is stateless (no sessions) also answers those clients:\n//\n// - server/discover, with the server's capabilities (the events keys\n// included) and the versions it takes;\n// - 2026-07-28 in the SDK's list of supported versions, so the\n// Streamable HTTP transport accepts its MCP-Protocol-Version header;\n// - resultType: \"complete\" on every result of a 2026-07-28 request, as\n// that revision requires (clients on the official 2.x SDKs refuse a\n// result without it), and ttlMs and cacheScope on server/discover and\n// the lists (Claude Code connects the old way without them).\n//\n// A stateful 1.x transport refuses a request without a session before any\n// handler runs, so a server with sessions is unchanged: its clients fall\n// back to initialize, as they do today.\n//\n// On both, tools/list leaves out subscribe_events for a request that\n// declares the events extension in its own capabilities (2026-07-28 has no\n// initialize, so each request carries them).\n\nimport { z } from \"zod\";\nimport { EXTENSION_KEY, RESULT_TYPE } from \"./spec.js\";\nimport { STATELESS_VERSION, is2026, v1Req, type Handler, type Host, type Req } from \"./host.js\";\n\nexport { STATELESS_VERSION };\n\nconst CAPABILITIES_META = \"io.modelcontextprotocol/clientCapabilities\";\nconst SERVER_INFO_META = \"io.modelcontextprotocol/serverInfo\";\n\n// The MCP SDK 1.x's list of supported versions, which its transport checks\n// the MCP-Protocol-Version header against: the same module the app's own\n// copy of the SDK loaded (loaded only if it's installed).\nconst v1Types: { SUPPORTED_PROTOCOL_VERSIONS?: string[] } | undefined = await import(\n /* webpackIgnore: true */ String(\"@modelcontextprotocol/sdk/types.js\")\n).catch(() => undefined);\n\n// The list methods whose 2026-07-28 results carry ttlMs and cacheScope.\nconst LISTS = new Set([\"tools/list\", \"prompts/list\", \"resources/list\", \"resources/templates/list\"]);\n\n/** The MCP tasks extension's capability key. */\nexport const TASKS_EXTENSION = \"io.modelcontextprotocol/tasks\";\n\n// reqOf reads meta, and extra's headers (an already-read request's, or\n// 1.x's requestInfo), as one request.\nfunction reqOf(meta: Record<string, unknown> | undefined, extra?: unknown): Req {\n if (extra && typeof (extra as Req).header === \"function\") return { ...(extra as Req), meta };\n return v1Req({ ...((extra as object | undefined) ?? {}), _meta: meta });\n}\n\n/**\n * @internal Whether a request (its _meta, as a tool callback's extra has\n * it, and its headers) is protocol 2026-07-28 and declares the tasks\n * extension in its own capabilities: a client that takes MCP tasks\n * (tasks.ts).\n */\nexport function takesTasks(meta: Record<string, unknown> | undefined, extra?: unknown): boolean {\n if (!is2026(reqOf(meta, extra))) return false;\n const ext = (meta?.[CAPABILITIES_META] as { extensions?: unknown } | undefined)?.extensions;\n return !!ext && typeof ext === \"object\" && !Array.isArray(ext) && TASKS_EXTENSION in (ext as object);\n}\n\nfunction declaresEvents(meta: Record<string, unknown> | undefined): boolean {\n const ext = (meta?.[CAPABILITIES_META] as { extensions?: unknown } | undefined)?.extensions;\n return !!ext && typeof ext === \"object\" && EXTENSION_KEY in ext;\n}\n\n/** @internal Makes server answer 2026-07-28 requests (see the file's comment). */\nexport function serveStateless(host: Host, opts: { bridgedOnly?: readonly string[] } = {}): void {\n const handlers = host.handlers();\n if (!handlers) return; // a future SDK without it: nothing to vary\n const hidden = new Set(opts.bridgedOnly ?? []);\n const v1 = host.version === 1;\n if (v1) {\n // Mutating the SDK's own list is how 1.x can be taught a version.\n const versions = v1Types?.SUPPORTED_PROTOCOL_VERSIONS;\n if (Array.isArray(versions) && !versions.includes(STATELESS_VERSION)) versions.unshift(STATELESS_VERSION);\n }\n const wrap = (method: string, h: Handler): Handler =>\n (async (request: any, raw: any) => {\n const result = await h(request, raw);\n const req = host.req(raw);\n if (!is2026(req) || !result || typeof result !== \"object\") return result;\n let out = result;\n if (method === \"tools/list\" && hidden.size > 0 && declaresEvents(req.meta) && Array.isArray(out.tools)) {\n out = { ...out, tools: out.tools.filter((t: any) => !hidden.has(t?.name)) };\n }\n if (!v1) {\n // tools/list differs by what each request declares (this filter,\n // the wait tool), so it's cached by this client only, whatever\n // cache hint the app set; 2.x fills in the rest.\n return method === \"tools/list\" ? { ...out, cacheScope: \"private\" } : out;\n }\n if (out.resultType === undefined) out = { ...out, resultType: RESULT_TYPE };\n // A list's result says how long a client may cache it, as 2026-07-28\n // requires (Claude Code falls back to initialize without it): not at\n // all, and for this client only, since tools/list differs by what\n // each request declares.\n if (LISTS.has(method) && out.ttlMs === undefined) return { ...out, ttlMs: 0, cacheScope: \"private\" };\n return out;\n }) as Handler;\n const wraps = (method: string) => v1 || method === \"tools/list\";\n for (const [method, h] of handlers) if (wraps(method)) handlers.set(method, wrap(method, h));\n const set = handlers.set.bind(handlers);\n handlers.set = (method: string, h: Handler) => set(method, wraps(method) ? wrap(method, h) : h);\n if (!v1) return;\n\n const low = (host.server as unknown as { server: any }).server;\n low.setRequestHandler(z.object({ method: z.literal(\"server/discover\"), params: z.any().optional() }) as any, async () => {\n const out: Record<string, unknown> = {\n resultType: RESULT_TYPE,\n supportedVersions: [...(v1Types?.SUPPORTED_PROTOCOL_VERSIONS ?? [STATELESS_VERSION])],\n // Cacheable results carry these on 2026-07-28 (Claude Code refuses a\n // server/discover without them, and connects the old way).\n ttlMs: 0,\n cacheScope: \"public\",\n capabilities: low.getCapabilities(),\n _meta: { [SERVER_INFO_META]: low._serverInfo },\n };\n if (low._instructions) out.instructions = low._instructions;\n return out as any;\n });\n}\n"]}
|
package/dist/events.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import { type AnySchema, type SchemaInput, type SchemaOutput, type ZodRawShapeCompat } from "@modelcontextprotocol/sdk/server/zod-compat.js";
|
|
1
|
+
import { type AnySchema, type SchemaInput, type SchemaOutput, type ZodRawShapeCompat } from "./zod.js";
|
|
3
2
|
import { WakeshiftError } from "./errors.js";
|
|
4
3
|
import { type Dialect } from "./spec.js";
|
|
5
|
-
import { type Emitted, type PublishUrl, type Recipient, type
|
|
4
|
+
import { type Emitted, type PublishUrl, type Recipient, type Via, type Wakeshift } from "./wakeshift.js";
|
|
6
5
|
import { type EventsOptions } from "./toolcall.js";
|
|
7
6
|
/** Who is subscribing: what authorize decides on. */
|
|
8
7
|
export interface Subscriber {
|
|
@@ -174,16 +173,21 @@ export interface Identity {
|
|
|
174
173
|
*/
|
|
175
174
|
client?: string;
|
|
176
175
|
}
|
|
177
|
-
|
|
176
|
+
/**
|
|
177
|
+
* attach's options. C is the request context your MCP SDK's handlers get:
|
|
178
|
+
* @modelcontextprotocol/server 2.x's ServerContext (`ctx`), or
|
|
179
|
+
* @modelcontextprotocol/sdk 1.x's RequestHandlerExtra (`extra`).
|
|
180
|
+
*/
|
|
181
|
+
export interface AttachOptions<C = any> {
|
|
178
182
|
/**
|
|
179
183
|
* Who is behind a request. The app passes identify, returning { user }:
|
|
180
184
|
* its own ID for the person, from its own sign-in (and, on a stateless
|
|
181
185
|
* server, the client's name as `client`). Without it, requests have no
|
|
182
|
-
* user, so personal events and list_subscriptions refuse.
|
|
186
|
+
* user, so personal events and list_subscriptions refuse. It gets the
|
|
187
|
+
* request's context as your MCP SDK passes it to handlers: 2.x's ctx
|
|
188
|
+
* (the token in ctx.http?.authInfo), 1.x's extra (extra.authInfo).
|
|
183
189
|
*/
|
|
184
|
-
identify
|
|
185
|
-
authInfo?: AuthInfo;
|
|
186
|
-
}) => Identity | undefined;
|
|
190
|
+
identify?(extra: C): Identity | undefined;
|
|
187
191
|
/**
|
|
188
192
|
* Which of attach's own tools it adds (BUILTIN_TOOLS): subscribe_events,
|
|
189
193
|
* unsubscribe_events and list_subscriptions. Default: all three; `[]`
|
|
@@ -192,7 +196,7 @@ export interface AttachOptions {
|
|
|
192
196
|
*/
|
|
193
197
|
tools?: readonly BuiltinTool[];
|
|
194
198
|
/** The event features' options: events.native overrides native detection for wrapped tools (attached.events). */
|
|
195
|
-
events?: EventsOptions
|
|
199
|
+
events?: EventsOptions<C>;
|
|
196
200
|
}
|
|
197
201
|
/** The tools attach adds, unless AttachOptions.tools names fewer. */
|
|
198
202
|
export declare const BUILTIN_TOOLS: readonly ["subscribe_events", "unsubscribe_events", "list_subscriptions"];
|