@wakeshift/sdk 0.5.0 → 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 +40 -0
- package/README.md +58 -4
- package/dist/discover.d.ts +4 -0
- package/dist/discover.js +128 -0
- package/dist/discover.js.map +1 -0
- package/dist/events.d.ts +14 -9
- package/dist/events.js +131 -88
- 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/spec.d.ts +4 -2
- package/dist/spec.js +4 -2
- package/dist/spec.js.map +1 -1
- package/dist/tasks.d.ts +33 -0
- package/dist/tasks.js +159 -0
- package/dist/tasks.js.map +1 -0
- package/dist/toolcall.d.ts +74 -22
- package/dist/toolcall.js +127 -66
- package/dist/toolcall.js.map +1 -1
- package/dist/wakeshift.d.ts +7 -3
- package/dist/wakeshift.js +29 -18
- 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/dist/host.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host.js","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"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","sourcesContent":["// What attach needs of an MCP server, for each MCP TypeScript SDK it takes:\n// @modelcontextprotocol/sdk 1.x and @modelcontextprotocol/server 2.x. The\n// rest of the SDK (events.ts, toolcall.ts, tasks.ts, discover.ts) is\n// written once against Host, and neither MCP SDK is imported here: hostOf\n// tells them apart by the server object it's given.\n//\n// Where the two differ:\n// - a request's context: 1.x's `extra` (_meta, requestInfo.headers,\n// authInfo, signal), 2.x's `ctx` (mcpReq._meta without the reserved\n// io.modelcontextprotocol/* keys, which it lifts into mcpReq.envelope;\n// http.req's Headers; http.authInfo; mcpReq.signal). req() reads either\n// into one shape, putting the envelope's keys back into _meta, so\n// Wakeshift gets the same call from both (test/mcp-tasks-wire.json);\n// - custom methods (events/*): a zod request schema on 1.x, a method name\n// and a params schema on 2.x;\n// - tasks/get and tasks/cancel: 2.x answers them on protocol 2026-07-28\n// only for a handler registered with a params schema (the tasks\n// extension's methods), so setTaskMethod registers them that way;\n// - protocol 2026-07-28: 1.x doesn't speak it, so discover.ts teaches it;\n// 2.x speaks it itself (server/discover, resultType, ttlMs and\n// cacheScope).\n//\n// Both keep their request handlers in a private Map (_requestHandlers),\n// which tools/list, tools/call, server/discover and tasks/* are wrapped\n// through (neither has public middleware for a method it answers itself),\n// and their tools in _registeredTools, which wrapped tools are checked\n// against. Unit tests pin both against each SDK the CI installs.\n\nimport { z } from \"zod\";\nimport * as z4 from \"zod/v4\";\nimport type { AuthInfo, CallToolResult, McpServerLike } from \"./mcp.js\";\nimport { normalizeObjectSchema, safeParseAsync, type AnySchema, type ZodRawShapeCompat } from \"./zod.js\";\n\n/** @internal A request handler as both SDKs keep them: the request, and the SDK's own context. */\nexport type Handler = (request: any, raw: any) => Promise<any>;\n\n/** @internal One request's context, read the same way from either SDK. */\nexport interface Req {\n /** The request's _meta, with 2.x's lifted envelope keys put back. */\n meta: Record<string, unknown> | undefined;\n /** An HTTP header of the request (\"\" if none, or not over HTTP). */\n header(name: string): string;\n authInfo: AuthInfo | undefined;\n signal: AbortSignal | undefined;\n}\n\n/** @internal A registered tool as the wrapper reads it. */\nexport interface RegisteredToolInternal {\n inputSchema?: unknown;\n outputSchema?: unknown;\n handler?: unknown;\n callback?: unknown;\n}\n\n/** @internal One of attach's own tools' registration. */\nexport interface ToolRegistration {\n description: string;\n /** A zod shape, in the API host.zod gives. */\n inputSchema: ZodRawShapeCompat;\n annotations?: Record<string, unknown>;\n}\n\n/** @internal The zod API attach's own tool schemas are written in. */\nexport type ZodApi = { string(): any; record(k: any, v: any): any; any(): any; enum(values: readonly [string, ...string[]]): any };\n\n/** @internal What attach needs of an MCP server. */\nexport interface Host {\n /** The MCP SDK's major version: 1 (@modelcontextprotocol/sdk) or 2 (@modelcontextprotocol/server). */\n readonly version: 1 | 2;\n readonly server: McpServerLike;\n /** The zod attach's own tools are written with: zod 4 for 2.x, which takes only zod 4. */\n readonly zod: ZodApi;\n /** A request's context, from the SDK's own (extra or ctx), or one already read. */\n req(raw: unknown): Req;\n registerCapabilities(capabilities: Record<string, unknown>): void;\n registerTool(name: string, config: ToolRegistration, cb: (args: Record<string, unknown>, raw: unknown) => Promise<CallToolResult>): { enable(): void; disable(): void };\n /** A JSON-RPC method of Wakeshift's own (events/*): its handler gets the request's params. */\n setMethod(method: string, handler: (params: Record<string, any>, raw: unknown) => Promise<unknown>): void;\n /** Makes the SDK route tasks/get or tasks/cancel on every protocol revision; the caller then sets its handler in handlers(). */\n setTaskMethod(method: string): void;\n /** The SDK's request handlers, or null if this SDK keeps them where Wakeshift can't wrap them. */\n handlers(): Map<string, Handler> | null;\n /** The client's name from initialize (or, on 2.x, the request's envelope). */\n clientName(): string | undefined;\n /** The client's capabilities from initialize (or, on 2.x, the request's envelope). */\n clientCapabilities(): Record<string, unknown> | undefined;\n /** Runs fn after a client's initialized notification, after any earlier hook. */\n onInitialized(fn: () => void): void;\n /** A registered tool (undefined: none by that name; null: the SDK keeps them where Wakeshift can't read them). */\n registeredTool(name: string): RegisteredToolInternal | undefined | null;\n /** Whether a tools/call result passes the tool's output schema, as the SDK checks it after the callback returns. */\n validOutput(outputSchema: unknown, result: CallToolResult | string): Promise<boolean>;\n}\n\nconst VERSION_META = \"io.modelcontextprotocol/protocolVersion\";\n\nfunction lowOf(server: McpServerLike): any {\n return (server as { server?: unknown }).server;\n}\n\n/**\n * @internal The Host for an McpServer from either SDK. 2.x's low-level\n * Server has projectCallToolResult, which 1.x's lacks.\n */\nexport function hostOf(server: unknown): Host {\n const low = (server as { server?: any } | null)?.server;\n if (!low || typeof low.setRequestHandler !== \"function\" || typeof (server as { registerTool?: unknown }).registerTool !== \"function\") {\n throw new Error(\n \"wakeshift: attach takes an McpServer, from @modelcontextprotocol/server 2.x or @modelcontextprotocol/sdk 1.x (@modelcontextprotocol/sdk/server/mcp.js)\",\n );\n }\n return typeof low.projectCallToolResult === \"function\" ? new V2Host(server as McpServerLike) : new V1Host(server as McpServerLike);\n}\n\n// headerOf reads a header from a plain record (1.x's requestInfo.headers).\nfunction headerOf(headers: Record<string, string | string[] | undefined> | undefined, name: string): string {\n if (!headers) return \"\";\n const v = headers[name] ?? headers[name.toLowerCase()];\n return (Array.isArray(v) ? v[0] : v) ?? \"\";\n}\n\n/** @internal A context already read (req's output). */\nfunction isReq(raw: unknown): raw is Req {\n return !!raw && typeof (raw as Req).header === \"function\" && \"meta\" in (raw as object);\n}\n\n/**\n * @internal A request's context read the 1.x way: extra's _meta,\n * requestInfo.headers, authInfo and signal. Also what a plain\n * `{ _meta, requestInfo }` (ToolExtra) reads as.\n */\nexport function v1Req(raw: unknown): Req {\n if (isReq(raw)) return raw;\n const e = (raw ?? {}) as { _meta?: Record<string, unknown>; requestInfo?: { headers?: Record<string, string | string[] | undefined> }; authInfo?: AuthInfo; signal?: AbortSignal };\n return { meta: e._meta, header: (name) => headerOf(e.requestInfo?.headers, name), authInfo: e.authInfo, signal: e.signal };\n}\n\n/** @internal A request's context read the 2.x way (ctx), putting the envelope's keys back into _meta. */\nexport function v2Req(raw: unknown): Req {\n if (isReq(raw)) return raw;\n const c = (raw ?? {}) as {\n mcpReq?: { _meta?: Record<string, unknown>; envelope?: Record<string, unknown>; signal?: AbortSignal };\n http?: { authInfo?: AuthInfo; req?: { headers?: { get(name: string): string | null } } };\n // A 1.x-shaped context (a test's, or one passed through by hand) reads too.\n _meta?: Record<string, unknown>;\n requestInfo?: { headers?: Record<string, string | string[] | undefined> };\n };\n if (!c.mcpReq) return v1Req(raw);\n const own = c.mcpReq._meta;\n const env = c.mcpReq.envelope;\n const meta = env && Object.keys(env).length > 0 ? { ...env, ...own } : own;\n const headers = c.http?.req?.headers;\n return {\n meta,\n header: (name) => (headers && typeof headers.get === \"function\" ? (headers.get(name) ?? \"\") : \"\"),\n authInfo: c.http?.authInfo,\n signal: c.mcpReq.signal,\n };\n}\n\nabstract class BaseHost {\n constructor(readonly server: McpServerLike) {}\n protected get low(): any {\n return lowOf(this.server);\n }\n registerCapabilities(capabilities: Record<string, unknown>): void {\n this.low.registerCapabilities(capabilities);\n }\n handlers(): Map<string, Handler> | null {\n const h = this.low._requestHandlers;\n return h instanceof Map ? (h as Map<string, Handler>) : null;\n }\n clientName(): string | undefined {\n return this.low.getClientVersion?.()?.name || undefined;\n }\n clientCapabilities(): Record<string, unknown> | undefined {\n return this.low.getClientCapabilities?.() as Record<string, unknown> | undefined;\n }\n onInitialized(fn: () => void): void {\n const low = this.low;\n const prev = low.oninitialized as (() => void) | undefined;\n low.oninitialized = () => {\n fn();\n prev?.();\n };\n }\n registeredTool(name: string): RegisteredToolInternal | undefined | null {\n const tools = (this.server as unknown as { _registeredTools?: Record<string, RegisteredToolInternal> })._registeredTools;\n if (!tools || typeof tools !== \"object\") return null;\n return Object.prototype.hasOwnProperty.call(tools, name) ? tools[name] : undefined;\n }\n}\n\nclass V1Host extends BaseHost implements Host {\n readonly version = 1 as const;\n readonly zod: ZodApi = z as unknown as ZodApi;\n req(raw: unknown): Req {\n return v1Req(raw);\n }\n registerTool(name: string, config: ToolRegistration, cb: (args: Record<string, unknown>, raw: unknown) => Promise<CallToolResult>) {\n return (this.server as any).registerTool(name, config, cb);\n }\n setMethod(method: string, handler: (params: Record<string, any>, raw: unknown) => Promise<unknown>): void {\n const schema = z.object({ method: z.literal(method), params: z.any().optional() });\n this.low.setRequestHandler(schema, (request: { params?: Record<string, any> }, extra: unknown) => handler(request.params ?? {}, extra));\n }\n setTaskMethod(_method: string): void {\n // Nothing to register: 1.x routes whatever is in its handler map. (Its\n // setRequestHandler would ask for its own tasks capability, an older\n // revision's, never advertised.)\n }\n async validOutput(outputSchema: unknown, result: CallToolResult | string): Promise<boolean> {\n // McpServer 1.x's validateToolOutput: an object schema, and structured content that parses.\n if (!outputSchema) return true;\n if (typeof result === \"string\" || !result.structuredContent) return false;\n const obj = normalizeObjectSchema(outputSchema);\n if (!obj) return true;\n return (await safeParseAsync(obj as AnySchema, result.structuredContent)).success;\n }\n}\n\nclass V2Host extends BaseHost implements Host {\n readonly version = 2 as const;\n readonly zod: ZodApi = z4 as unknown as ZodApi;\n req(raw: unknown): Req {\n return v2Req(raw);\n }\n registerTool(name: string, config: ToolRegistration, cb: (args: Record<string, unknown>, raw: unknown) => Promise<CallToolResult>) {\n // 2.x takes an object schema (a bare shape is deprecated there).\n return (this.server as any).registerTool(name, { ...config, inputSchema: objectFromV4Shape(config.inputSchema) }, cb);\n }\n setMethod(method: string, handler: (params: Record<string, any>, raw: unknown) => Promise<unknown>): void {\n this.low.setRequestHandler(method, { params: z4.looseObject({}) }, (params: Record<string, any>, ctx: unknown) => handler(params ?? {}, ctx));\n }\n setTaskMethod(method: string): void {\n // Registered with a params schema, so 2.x serves it on protocol\n // 2026-07-28 too, as the tasks extension's method (SEP-2663). The\n // caller replaces the handler that leaves in the map.\n this.low.setRequestHandler(method, { params: z4.looseObject({}) }, async () => {\n throw Object.assign(new Error(\"Method not found\"), { code: -32601 });\n });\n }\n async validOutput(outputSchema: unknown, result: CallToolResult | string): Promise<boolean> {\n // McpServer 2.x's validateToolOutput: structured content (any JSON\n // value) that the output schema (a Standard Schema) accepts.\n if (!outputSchema) return true;\n if (typeof result === \"string\" || result.structuredContent === undefined) return false;\n const std = (outputSchema as { \"~standard\"?: { validate(v: unknown): unknown } })[\"~standard\"];\n if (!std || typeof std.validate !== \"function\") return true;\n const out = (await std.validate(result.structuredContent)) as { issues?: unknown };\n return !out.issues;\n }\n}\n\n// objectFromV4Shape is a zod 4 object of attach's own tool shapes (written\n// with zod/v4: host.zod).\nfunction objectFromV4Shape(shape: ZodRawShapeCompat): unknown {\n const values = Object.values(shape);\n if (values.length === 0) return z4.object({});\n return z4.object(shape as Record<string, z4.ZodType>);\n}\n\n/** The protocol revision that has server/discover, MCP Events and the tasks extension. */\nexport const STATELESS_VERSION = \"2026-07-28\";\n\n/** @internal Whether a request is protocol 2026-07-28: its _meta names it, or its MCP-Protocol-Version header does. */\nexport function is2026(req: Req): boolean {\n if (req.meta?.[VERSION_META] === STATELESS_VERSION) return true;\n return req.header(\"mcp-protocol-version\") === STATELESS_VERSION;\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -3,5 +3,6 @@ export { harnessAgent } from "./harness.js";
|
|
|
3
3
|
export { WakeshiftError, isCode } from "./errors.js";
|
|
4
4
|
export { parseKey, signAssertion, type AppKey } from "./key.js";
|
|
5
5
|
export { WakeEvent, ArgsError, EVENT_TOOL_TEXT, SUBSCRIBE_TOOL_DESCRIPTION, UNSUBSCRIBE_TOOL_DESCRIPTION, LIST_TOOL_DESCRIPTION, BUILTIN_TOOLS, type BuiltinTool, type EventOptions, type EmitOptions, type EventStatus, type EventSubscriptionStatus, MAX_STATUS_SUBSCRIPTIONS, type EventTypeManifest, type AttachOptions, type Identity, type Subscriber, } from "./events.js";
|
|
6
|
-
export { CallEnded, type Attached, type AppArgs, type EventsOptions, type Subscription, type ToolCall, type ToolCallExtra, type ToolSubscribeOptions, type WakeInputs, type WakeKey, type WakeOutputShape, type WakeShape, type WrappedResult, } from "./toolcall.js";
|
|
6
|
+
export { CallEnded, type Attached, type AppArgs, type EventsOptions, type Subscription, type ToolCall, type ToolCallExtra, type ToolSubscribeOptions, type WakeArgs, type WakeInputs, type WakeInputsV3, type WakeInputsV4, type WakeKey, type WakeOutputShape, type WakeOutputV3, type WakeOutputV4, type WakeShape, type WrappedCallback, type WrappedResult, } from "./toolcall.js";
|
|
7
|
+
export type { AuthInfo, CallToolResult, ContentBlock, HostContext, McpServerLike } from "./mcp.js";
|
|
7
8
|
export { EXTENSION_KEY, TEXT_META, REVISION as EVENTS_REVISION } from "./spec.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,YAAY,EACZ,WAAW,EACX,WAAW,EACX,gBAAgB,GAajB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAe,MAAM,UAAU,CAAC;AAChE,OAAO,EACL,SAAS,EACT,SAAS,EACT,eAAe,EACf,0BAA0B,EAC1B,4BAA4B,EAC5B,qBAAqB,EACrB,aAAa,EAMb,wBAAwB,GAKzB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,SAAS,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,YAAY,EACZ,WAAW,EACX,WAAW,EACX,gBAAgB,GAajB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAe,MAAM,UAAU,CAAC;AAChE,OAAO,EACL,SAAS,EACT,SAAS,EACT,eAAe,EACf,0BAA0B,EAC1B,4BAA4B,EAC5B,qBAAqB,EACrB,aAAa,EAMb,wBAAwB,GAKzB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,SAAS,GAmBV,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,QAAQ,IAAI,eAAe,EAAE,MAAM,WAAW,CAAC","sourcesContent":["export {\n Wakeshift,\n DEFAULT_CORE,\n SESSION_ARG,\n HARNESS_ARG,\n CONVERSATION_ARG,\n type WakeshiftOptions,\n type AppInfo,\n type Duration,\n type Recognized,\n type Emitted,\n type Recipient,\n type Via,\n type PublishUrl,\n type ToolExtra,\n type Manifest,\n type AgentScope,\n type ScopeEvent,\n} from \"./wakeshift.js\";\nexport { harnessAgent } from \"./harness.js\";\nexport { WakeshiftError, isCode } from \"./errors.js\";\nexport { parseKey, signAssertion, type AppKey } from \"./key.js\";\nexport {\n WakeEvent,\n ArgsError,\n EVENT_TOOL_TEXT,\n SUBSCRIBE_TOOL_DESCRIPTION,\n UNSUBSCRIBE_TOOL_DESCRIPTION,\n LIST_TOOL_DESCRIPTION,\n BUILTIN_TOOLS,\n type BuiltinTool,\n type EventOptions,\n type EmitOptions,\n type EventStatus,\n type EventSubscriptionStatus,\n MAX_STATUS_SUBSCRIPTIONS,\n type EventTypeManifest,\n type AttachOptions,\n type Identity,\n type Subscriber,\n} from \"./events.js\";\nexport {\n CallEnded,\n type Attached,\n type AppArgs,\n type EventsOptions,\n type Subscription,\n type ToolCall,\n type ToolCallExtra,\n type ToolSubscribeOptions,\n type WakeArgs,\n type WakeInputs,\n type WakeInputsV3,\n type WakeInputsV4,\n type WakeKey,\n type WakeOutputShape,\n type WakeOutputV3,\n type WakeOutputV4,\n type WakeShape,\n type WrappedCallback,\n type WrappedResult,\n} from \"./toolcall.js\";\nexport type { AuthInfo, CallToolResult, ContentBlock, HostContext, McpServerLike } from \"./mcp.js\";\nexport { EXTENSION_KEY, TEXT_META, REVISION as EVENTS_REVISION } from \"./spec.js\";\n"]}
|
package/dist/mcp.d.ts
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/** An MCP content block: text, or anything else the protocol carries. */
|
|
2
|
+
export type ContentBlock = {
|
|
3
|
+
type: "text";
|
|
4
|
+
text: string;
|
|
5
|
+
[k: string]: unknown;
|
|
6
|
+
} | {
|
|
7
|
+
type: "image" | "audio" | "resource_link" | "resource";
|
|
8
|
+
[k: string]: unknown;
|
|
9
|
+
};
|
|
10
|
+
/** A tools/call result, as either MCP SDK types one. */
|
|
11
|
+
export interface CallToolResult {
|
|
12
|
+
content: ContentBlock[];
|
|
13
|
+
/** An object on protocol 2025-11-25; any JSON value on 2026-07-28. */
|
|
14
|
+
structuredContent?: unknown;
|
|
15
|
+
isError?: boolean;
|
|
16
|
+
_meta?: Record<string, unknown>;
|
|
17
|
+
[k: string]: unknown;
|
|
18
|
+
}
|
|
19
|
+
/** A verified access token, as an MCP SDK's auth middleware passes it to handlers. */
|
|
20
|
+
export interface AuthInfo {
|
|
21
|
+
token: string;
|
|
22
|
+
clientId: string;
|
|
23
|
+
scopes: string[];
|
|
24
|
+
expiresAt?: number;
|
|
25
|
+
resource?: URL;
|
|
26
|
+
extra?: Record<string, unknown>;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A JSON-RPC error a handler throws: both MCP SDKs answer with its code,
|
|
30
|
+
* message and data (1.x calls its own McpError, 2.x ProtocolError).
|
|
31
|
+
*/
|
|
32
|
+
export declare class RpcError extends Error {
|
|
33
|
+
readonly code: number;
|
|
34
|
+
readonly data?: unknown;
|
|
35
|
+
constructor(code: number, message: string, data?: unknown);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* An McpServer from either MCP SDK: @modelcontextprotocol/sdk 1.x's
|
|
39
|
+
* (`@modelcontextprotocol/sdk/server/mcp.js`) or
|
|
40
|
+
* @modelcontextprotocol/server 2.x's.
|
|
41
|
+
*/
|
|
42
|
+
export interface McpServerLike {
|
|
43
|
+
readonly server: object;
|
|
44
|
+
registerTool(...args: any[]): unknown;
|
|
45
|
+
}
|
|
46
|
+
type LowOf<S> = S extends {
|
|
47
|
+
server: infer L;
|
|
48
|
+
} ? L : never;
|
|
49
|
+
/**
|
|
50
|
+
* The context a server's request handlers get, read from the server's own
|
|
51
|
+
* type: @modelcontextprotocol/server 2.x's ServerContext (`ctx`), or
|
|
52
|
+
* @modelcontextprotocol/sdk 1.x's RequestHandlerExtra (`extra`).
|
|
53
|
+
*/
|
|
54
|
+
export type HostContext<S> = LowOf<S> extends {
|
|
55
|
+
projectCallToolResult: unknown;
|
|
56
|
+
} ? LowOf<S> extends {
|
|
57
|
+
setRequestHandler(method: string, schemas: any, handler: (params: any, ctx: infer C) => any): void;
|
|
58
|
+
} ? C : ToolCallExtra : S extends {
|
|
59
|
+
registerTool(name: string, config: any, cb: (args: any, extra: infer E) => any): any;
|
|
60
|
+
} ? E : ToolCallExtra;
|
|
61
|
+
/**
|
|
62
|
+
* The parts of a tool call's context Wakeshift reads, whichever MCP SDK
|
|
63
|
+
* serves it: 1.x's RequestHandlerExtra (`_meta`, `authInfo`,
|
|
64
|
+
* `requestInfo`), 2.x's ServerContext (`mcpReq`, `http`). A wrapped tool's
|
|
65
|
+
* `call.extra` is typed as your MCP SDK's own.
|
|
66
|
+
*/
|
|
67
|
+
export interface ToolCallExtra {
|
|
68
|
+
_meta?: Record<string, unknown>;
|
|
69
|
+
authInfo?: AuthInfo;
|
|
70
|
+
requestInfo?: {
|
|
71
|
+
headers?: Record<string, string | string[] | undefined>;
|
|
72
|
+
};
|
|
73
|
+
signal?: AbortSignal;
|
|
74
|
+
sessionId?: string;
|
|
75
|
+
mcpReq?: {
|
|
76
|
+
_meta?: Record<string, unknown>;
|
|
77
|
+
envelope?: Record<string, unknown>;
|
|
78
|
+
signal?: AbortSignal;
|
|
79
|
+
id?: string | number;
|
|
80
|
+
};
|
|
81
|
+
http?: {
|
|
82
|
+
authInfo?: AuthInfo;
|
|
83
|
+
req?: {
|
|
84
|
+
headers: {
|
|
85
|
+
get(name: string): string | null;
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
/** The rest of the SDK's own context (1.x: requestId, sendNotification…; 2.x: mcpReq.send…). */
|
|
90
|
+
[k: string]: any;
|
|
91
|
+
}
|
|
92
|
+
export {};
|
package/dist/mcp.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// The MCP types the SDK's API names, written out here rather than imported,
|
|
2
|
+
// so its published types load with either MCP TypeScript SDK installed and
|
|
3
|
+
// the other missing: @modelcontextprotocol/sdk 1.x or
|
|
4
|
+
// @modelcontextprotocol/server 2.x (host.ts tells them apart at run time).
|
|
5
|
+
// Each is what both SDKs' own types have in common, so a value of either's
|
|
6
|
+
// type fits.
|
|
7
|
+
/**
|
|
8
|
+
* A JSON-RPC error a handler throws: both MCP SDKs answer with its code,
|
|
9
|
+
* message and data (1.x calls its own McpError, 2.x ProtocolError).
|
|
10
|
+
*/
|
|
11
|
+
export class RpcError extends Error {
|
|
12
|
+
code;
|
|
13
|
+
data;
|
|
14
|
+
constructor(code, message, data) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = "RpcError";
|
|
17
|
+
this.code = code;
|
|
18
|
+
if (data !== undefined)
|
|
19
|
+
this.data = data;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=mcp.js.map
|
package/dist/mcp.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,2EAA2E;AAC3E,sDAAsD;AACtD,2EAA2E;AAC3E,2EAA2E;AAC3E,aAAa;AA2Bb;;;GAGG;AACH,MAAM,OAAO,QAAS,SAAQ,KAAK;IACxB,IAAI,CAAS;IACb,IAAI,CAAW;IACxB,YAAY,IAAY,EAAE,OAAe,EAAE,IAAc;QACvD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,IAAI,KAAK,SAAS;YAAE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IAC3C,CAAC;CACF","sourcesContent":["// The MCP types the SDK's API names, written out here rather than imported,\n// so its published types load with either MCP TypeScript SDK installed and\n// the other missing: @modelcontextprotocol/sdk 1.x or\n// @modelcontextprotocol/server 2.x (host.ts tells them apart at run time).\n// Each is what both SDKs' own types have in common, so a value of either's\n// type fits.\n\n/** An MCP content block: text, or anything else the protocol carries. */\nexport type ContentBlock =\n | { type: \"text\"; text: string; [k: string]: unknown }\n | { type: \"image\" | \"audio\" | \"resource_link\" | \"resource\"; [k: string]: unknown };\n\n/** A tools/call result, as either MCP SDK types one. */\nexport interface CallToolResult {\n content: ContentBlock[];\n /** An object on protocol 2025-11-25; any JSON value on 2026-07-28. */\n structuredContent?: unknown;\n isError?: boolean;\n _meta?: Record<string, unknown>;\n [k: string]: unknown;\n}\n\n/** A verified access token, as an MCP SDK's auth middleware passes it to handlers. */\nexport interface AuthInfo {\n token: string;\n clientId: string;\n scopes: string[];\n expiresAt?: number;\n resource?: URL;\n extra?: Record<string, unknown>;\n}\n\n/**\n * A JSON-RPC error a handler throws: both MCP SDKs answer with its code,\n * message and data (1.x calls its own McpError, 2.x ProtocolError).\n */\nexport class RpcError extends Error {\n readonly code: number;\n readonly data?: unknown;\n constructor(code: number, message: string, data?: unknown) {\n super(message);\n this.name = \"RpcError\";\n this.code = code;\n if (data !== undefined) this.data = data;\n }\n}\n\n/**\n * An McpServer from either MCP SDK: @modelcontextprotocol/sdk 1.x's\n * (`@modelcontextprotocol/sdk/server/mcp.js`) or\n * @modelcontextprotocol/server 2.x's.\n */\nexport interface McpServerLike {\n readonly server: object;\n registerTool(...args: any[]): unknown;\n}\n\ntype LowOf<S> = S extends { server: infer L } ? L : never;\n\n/**\n * The context a server's request handlers get, read from the server's own\n * type: @modelcontextprotocol/server 2.x's ServerContext (`ctx`), or\n * @modelcontextprotocol/sdk 1.x's RequestHandlerExtra (`extra`).\n */\nexport type HostContext<S> =\n LowOf<S> extends { projectCallToolResult: unknown }\n ? LowOf<S> extends { setRequestHandler(method: string, schemas: any, handler: (params: any, ctx: infer C) => any): void }\n ? C\n : ToolCallExtra\n : S extends { registerTool(name: string, config: any, cb: (args: any, extra: infer E) => any): any }\n ? E\n : ToolCallExtra;\n\n/**\n * The parts of a tool call's context Wakeshift reads, whichever MCP SDK\n * serves it: 1.x's RequestHandlerExtra (`_meta`, `authInfo`,\n * `requestInfo`), 2.x's ServerContext (`mcpReq`, `http`). A wrapped tool's\n * `call.extra` is typed as your MCP SDK's own.\n */\nexport interface ToolCallExtra {\n _meta?: Record<string, unknown>;\n authInfo?: AuthInfo;\n requestInfo?: { headers?: Record<string, string | string[] | undefined> };\n signal?: AbortSignal;\n sessionId?: string;\n mcpReq?: { _meta?: Record<string, unknown>; envelope?: Record<string, unknown>; signal?: AbortSignal; id?: string | number };\n http?: { authInfo?: AuthInfo; req?: { headers: { get(name: string): string | null } } };\n /** The rest of the SDK's own context (1.x: requestId, sendNotification…; 2.x: mcpReq.send…). */\n [k: string]: any;\n}\n"]}
|
package/dist/spec.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
/** The draft these follow. */
|
|
2
|
-
export declare const REVISION = "SEP-3415 (2026-10-
|
|
1
|
+
/** The draft these follow: SEP-3415 as revised on 2026-10-27. Where clients differ from it, Wakeshift follows the clients (webhook-id equals eventId; Mcp-Name checked only when present). */
|
|
2
|
+
export declare const REVISION = "SEP-3415 (2026-10-27)";
|
|
3
|
+
/** The delivery modes Wakeshift offers for every event type (events/list's delivery): a webhook, or polls. Push (events/stream) isn't offered. */
|
|
4
|
+
export declare const DELIVERY: readonly string[];
|
|
3
5
|
/** Capability keys: the draft's extension, and the top-level key ChatGPT reads. A server advertises both; only the extension is exported. */
|
|
4
6
|
export declare const EXTENSION_KEY = "io.modelcontextprotocol/events";
|
|
5
7
|
export declare const TOP_LEVEL_KEY = "events";
|
package/dist/spec.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
// The SEP-3415 (MCP Events) constants the SDK uses, in one place, matching
|
|
2
2
|
// Wakeshift's own (internal/mcpevents/event/spec.go, which a test checks
|
|
3
3
|
// these against): the draft is still moving.
|
|
4
|
-
/** The draft these follow. */
|
|
5
|
-
export const REVISION = "SEP-3415 (2026-10-
|
|
4
|
+
/** The draft these follow: SEP-3415 as revised on 2026-10-27. Where clients differ from it, Wakeshift follows the clients (webhook-id equals eventId; Mcp-Name checked only when present). */
|
|
5
|
+
export const REVISION = "SEP-3415 (2026-10-27)";
|
|
6
|
+
/** The delivery modes Wakeshift offers for every event type (events/list's delivery): a webhook, or polls. Push (events/stream) isn't offered. */
|
|
7
|
+
export const DELIVERY = ["webhook", "poll"];
|
|
6
8
|
/** Capability keys: the draft's extension, and the top-level key ChatGPT reads. A server advertises both; only the extension is exported. */
|
|
7
9
|
export const EXTENSION_KEY = "io.modelcontextprotocol/events";
|
|
8
10
|
export const TOP_LEVEL_KEY = "events";
|
package/dist/spec.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spec.js","sourceRoot":"","sources":["../src/spec.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,yEAAyE;AACzE,6CAA6C;AAE7C,
|
|
1
|
+
{"version":3,"file":"spec.js","sourceRoot":"","sources":["../src/spec.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,yEAAyE;AACzE,6CAA6C;AAE7C,8LAA8L;AAC9L,MAAM,CAAC,MAAM,QAAQ,GAAG,uBAAuB,CAAC;AAEhD,kJAAkJ;AAClJ,MAAM,CAAC,MAAM,QAAQ,GAAsB,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;AAE/D,6IAA6I;AAC7I,MAAM,CAAC,MAAM,aAAa,GAAG,gCAAgC,CAAC;AAC9D,MAAM,CAAC,MAAM,aAAa,GAAG,QAAQ,CAAC;AAEtC,gCAAgC;AAChC,MAAM,CAAC,MAAM,WAAW,GAAG,UAAU,CAAC;AAEtC,sFAAsF;AACtF,MAAM,CAAC,MAAM,SAAS,GAAG,mBAAmB,CAAC;AAE7C,6FAA6F;AAC7F,MAAM,CAAC,MAAM,WAAW,GAAG,UAAU,CAAC;AAYtC,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,KAAK,CAAC;AACrC,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,KAAK,CAAC;AACtC,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,KAAK,CAAC;AAErC,uEAAuE;AACvE,MAAM,UAAU,QAAQ,CAAC,OAAgB;IACvC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,CAAC,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,WAAW,EAAE,cAAc,EAAE,gBAAgB,EAAE,CAAC,KAAK,EAAE,CAAC;IAC3I,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,CAAC,KAAK,EAAE,iBAAiB,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,CAAC,KAAK,EAAE,gBAAgB,EAAE,CAAC,KAAK,EAAE,CAAC;AAC3H,CAAC;AAED,oGAAoG;AACpG,MAAM,UAAU,SAAS,CAAC,UAAkB,EAAE,SAAiB;IAC7D,OAAO,UAAU,CAAC,WAAW,EAAE,KAAK,YAAY,IAAI,SAAS,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;AAC7H,CAAC;AAED,mIAAmI;AACnI,MAAM,UAAU,WAAW,CAAC,CAAS;IACnC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,CAAC,CAAC;IAC9D,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;QACjE,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;YAAE,OAAO,IAAI,CAAC;QAChH,OAAO,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC","sourcesContent":["// The SEP-3415 (MCP Events) constants the SDK uses, in one place, matching\n// Wakeshift's own (internal/mcpevents/event/spec.go, which a test checks\n// these against): the draft is still moving.\n\n/** The draft these follow: SEP-3415 as revised on 2026-10-27. Where clients differ from it, Wakeshift follows the clients (webhook-id equals eventId; Mcp-Name checked only when present). */\nexport const REVISION = \"SEP-3415 (2026-10-27)\";\n\n/** The delivery modes Wakeshift offers for every event type (events/list's delivery): a webhook, or polls. Push (events/stream) isn't offered. */\nexport const DELIVERY: readonly string[] = [\"webhook\", \"poll\"];\n\n/** Capability keys: the draft's extension, and the top-level key ChatGPT reads. A server advertises both; only the extension is exported. */\nexport const EXTENSION_KEY = \"io.modelcontextprotocol/events\";\nexport const TOP_LEVEL_KEY = \"events\";\n\n/** On every events/* result. */\nexport const RESULT_TYPE = \"complete\";\n\n/** The _meta key of an occurrence's rendered line (Wakeshift adds it on delivery). */\nexport const TEXT_META = \"ai.wakeshift/text\";\n\n/** The Streamable HTTP header events/subscribe and events/unsubscribe carry: params.name. */\nexport const NAME_HEADER = \"mcp-name\";\n\nexport type Dialect = \"draft\" | \"chatgpt\";\n\nexport interface Codes {\n notFound: number;\n forbidden: number;\n resourceExhausted: number;\n unsupported: number;\n callbackEndpoint: number;\n}\n\nexport const INVALID_PARAMS = -32602;\nexport const HEADER_MISMATCH = -32020;\nexport const INTERNAL_ERROR = -32603;\n\n/** A dialect's error codes: the draft's (provisional) or ChatGPT's. */\nexport function codesFor(dialect: Dialect): Codes {\n if (dialect === \"chatgpt\") {\n return { notFound: -32011, forbidden: -32012, resourceExhausted: INVALID_PARAMS, unsupported: INVALID_PARAMS, callbackEndpoint: -32015 };\n }\n return { notFound: -32023, forbidden: -32024, resourceExhausted: -32025, unsupported: -32026, callbackEndpoint: -32027 };\n}\n\n/** A client's dialect, by its clientInfo name or User-Agent: ChatGPT's MCP client is openai-mcp. */\nexport function dialectOf(clientName: string, userAgent: string): Dialect {\n return clientName.toLowerCase() === \"openai-mcp\" || userAgent.toLowerCase().startsWith(\"openai-mcp\") ? \"chatgpt\" : \"draft\";\n}\n\n/** Decodes an Mcp-Name header: plain ASCII, or SEP-2243's base64 sentinel (=?base64?…?=). null: a sentinel that doesn't decode. */\nexport function headerValue(h: string): string | null {\n if (!h.startsWith(\"=?base64?\") || !h.endsWith(\"?=\")) return h;\n try {\n const b = Buffer.from(h.slice(\"=?base64?\".length, -2), \"base64\");\n if (b.toString(\"base64\").replace(/=+$/, \"\") !== h.slice(\"=?base64?\".length, -2).replace(/=+$/, \"\")) return null;\n return b.toString(\"utf8\");\n } catch {\n return null;\n }\n}\n"]}
|
package/dist/tasks.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { TASKS_EXTENSION, takesTasks } from "./discover.js";
|
|
2
|
+
/** The wait tool's name. */
|
|
3
|
+
export declare const WAIT_TOOL = "wakeshift_wait";
|
|
4
|
+
/** The wait tool's description: the core's harnesses.WaitToolDescription. */
|
|
5
|
+
export declare const WAIT_TOOL_DESCRIPTION = "Wait for this conversation's next Wakeshift messages from this app. Returns at once and keeps waiting in the background: when messages arrive, its result reaches you as a task notification. Call it again after each one, with the session_key Wakeshift gave you.";
|
|
6
|
+
/** What every Wakeshift task ID starts with: tasks/get and tasks/cancel for any other ID aren't Wakeshift's. */
|
|
7
|
+
export declare const TASK_ID_PREFIX = "wkt1_";
|
|
8
|
+
/** How long Wakeshift holds a tasks/get for a working task, in seconds. */
|
|
9
|
+
export declare const TASK_HOLD_SECONDS = 20;
|
|
10
|
+
/** The wait tool as tools/list lists it. */
|
|
11
|
+
export declare const WAIT_TOOL_DEFINITION: {
|
|
12
|
+
readonly name: "wakeshift_wait";
|
|
13
|
+
readonly description: "Wait for this conversation's next Wakeshift messages from this app. Returns at once and keeps waiting in the background: when messages arrive, its result reaches you as a task notification. Call it again after each one, with the session_key Wakeshift gave you.";
|
|
14
|
+
readonly inputSchema: {
|
|
15
|
+
readonly type: "object";
|
|
16
|
+
readonly properties: {
|
|
17
|
+
readonly session_key: {
|
|
18
|
+
readonly type: "string";
|
|
19
|
+
readonly description: "This conversation's session_key, from an earlier result (a secret token, or a handle such as claude-code#2). Keep it to this conversation; don't share or log it.";
|
|
20
|
+
};
|
|
21
|
+
readonly harness: {
|
|
22
|
+
readonly type: "string";
|
|
23
|
+
readonly description: "The program you're running in: codex, claude-code, cursor (local CLI or IDE), cursor-cloud (Cursor cloud agent), grok-bot, copilot-cli, opencode, antigravity, openclaw (even when it runs your turns in Codex), hermes, chatgpt, or your program's name if it isn't listed";
|
|
24
|
+
};
|
|
25
|
+
readonly conversation_id: {
|
|
26
|
+
readonly type: "string";
|
|
27
|
+
readonly description: "Your own ID for this conversation, if your program gives you one. Cursor and Grok Bot: the output of `printenv CURSOR_CONVERSATION_ID`. Codex and Antigravity send it automatically; others leave it empty";
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
readonly additionalProperties: false;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
export { TASKS_EXTENSION, takesTasks };
|
package/dist/tasks.js
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
// MCP Tasks as a wake path (docs/harnesses.md, "Claude Code: MCP tasks as a
|
|
2
|
+
// wake path"): for a client that takes MCP tasks, on protocol 2026-07-28
|
|
3
|
+
// (discover.ts), attach serves Wakeshift's wait tool, wakeshift_wait. Its
|
|
4
|
+
// call is answered with a task that completes when the conversation's next
|
|
5
|
+
// Wakeshift messages arrive; the client follows it in the background
|
|
6
|
+
// (tasks/get), and a completed task wakes an idle conversation. Wakeshift
|
|
7
|
+
// decides everything: the SDK passes the tool's call, tasks/get and
|
|
8
|
+
// tasks/cancel to it and answers with the MCP result it returns, so every
|
|
9
|
+
// SDK says the same (test/mcp-tasks-wire.json). A task is only its ID,
|
|
10
|
+
// which any process answers for, so nothing is kept here.
|
|
11
|
+
//
|
|
12
|
+
// Only a request that declares the tasks extension in its own capabilities
|
|
13
|
+
// (2026-07-28 has no initialize: each request carries them) sees the wait
|
|
14
|
+
// tool, and a wrapped tool's call from it tells Wakeshift so (call.tasks),
|
|
15
|
+
// which then gives the wait tool's instructions instead of its harness's
|
|
16
|
+
// zero-install path (Claude Code's Monitor). Everything else is unchanged.
|
|
17
|
+
import { WakeshiftError } from "./errors.js";
|
|
18
|
+
import { TASKS_EXTENSION, takesTasks } from "./discover.js";
|
|
19
|
+
import { RpcError } from "./mcp.js";
|
|
20
|
+
import { WAKE_ARG_DESCRIPTIONS } from "./toolcall.js";
|
|
21
|
+
import { toolCallOf } from "./wakeshift.js";
|
|
22
|
+
/** The wait tool's name. */
|
|
23
|
+
export const WAIT_TOOL = "wakeshift_wait";
|
|
24
|
+
/** The wait tool's description: the core's harnesses.WaitToolDescription. */
|
|
25
|
+
export const WAIT_TOOL_DESCRIPTION = "Wait for this conversation's next Wakeshift messages from this app. Returns at once and keeps waiting in the background: when messages arrive, its result reaches you as a task notification. Call it again after each one, with the session_key Wakeshift gave you.";
|
|
26
|
+
/** What every Wakeshift task ID starts with: tasks/get and tasks/cancel for any other ID aren't Wakeshift's. */
|
|
27
|
+
export const TASK_ID_PREFIX = "wkt1_";
|
|
28
|
+
/** How long Wakeshift holds a tasks/get for a working task, in seconds. */
|
|
29
|
+
export const TASK_HOLD_SECONDS = 20;
|
|
30
|
+
/** The wait tool as tools/list lists it. */
|
|
31
|
+
export const WAIT_TOOL_DEFINITION = {
|
|
32
|
+
name: WAIT_TOOL,
|
|
33
|
+
description: WAIT_TOOL_DESCRIPTION,
|
|
34
|
+
inputSchema: {
|
|
35
|
+
type: "object",
|
|
36
|
+
properties: {
|
|
37
|
+
session_key: { type: "string", description: WAKE_ARG_DESCRIPTIONS.session_key },
|
|
38
|
+
harness: { type: "string", description: WAKE_ARG_DESCRIPTIONS.harness },
|
|
39
|
+
conversation_id: { type: "string", description: WAKE_ARG_DESCRIPTIONS.conversation_id },
|
|
40
|
+
},
|
|
41
|
+
additionalProperties: false,
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
export { TASKS_EXTENSION, takesTasks };
|
|
45
|
+
/**
|
|
46
|
+
* @internal Serves the wait tool, tasks/get and tasks/cancel on server
|
|
47
|
+
* (after serveStateless): the tasks extension in server/discover, the tool
|
|
48
|
+
* in tools/list for a request that takes tasks, and its calls and task
|
|
49
|
+
* requests passed to Wakeshift.
|
|
50
|
+
*/
|
|
51
|
+
export function serveTasks(wake, host, callerOf) {
|
|
52
|
+
const handlers = host.handlers();
|
|
53
|
+
if (!handlers)
|
|
54
|
+
return; // a future SDK: nothing to hook (no wait tool)
|
|
55
|
+
const call = (raw, args) => {
|
|
56
|
+
const { user, client } = callerOf(raw);
|
|
57
|
+
return toolCallOf(host.req(raw), client, user, args, WAIT_TOOL);
|
|
58
|
+
};
|
|
59
|
+
const takes = (raw) => {
|
|
60
|
+
const req = host.req(raw);
|
|
61
|
+
return takesTasks(req.meta, req);
|
|
62
|
+
};
|
|
63
|
+
const waitCall = async (request, raw) => {
|
|
64
|
+
const args = (request?.params?.arguments ?? {});
|
|
65
|
+
try {
|
|
66
|
+
const out = await wake.requestApp("POST", "/calls/task", { call: call(raw, args) });
|
|
67
|
+
if (out.result)
|
|
68
|
+
return out.result;
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
return { isError: true, content: [{ type: "text", text: `Wakeshift couldn't start the wait (${detailOf(err)}). Call ${WAIT_TOOL} again.` }] };
|
|
72
|
+
}
|
|
73
|
+
return { isError: true, content: [{ type: "text", text: `Wakeshift didn't answer the wait. Call ${WAIT_TOOL} again.` }] };
|
|
74
|
+
};
|
|
75
|
+
const taskRequest = (path, hold) => async (request, raw) => {
|
|
76
|
+
const task = request?.params?.taskId;
|
|
77
|
+
const body = { task: typeof task === "string" ? task : "", call: call(raw, {}) };
|
|
78
|
+
if (hold)
|
|
79
|
+
body.hold_seconds = TASK_HOLD_SECONDS;
|
|
80
|
+
const signal = host.req(raw).signal;
|
|
81
|
+
let out;
|
|
82
|
+
try {
|
|
83
|
+
out = await wake.requestApp("POST", path, body, { timeoutMs: (TASK_HOLD_SECONDS + 15) * 1000, signal });
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
if (signal?.aborted)
|
|
87
|
+
throw new RpcError(-32603, "canceled by the client");
|
|
88
|
+
throw new RpcError(-32603, `Wakeshift: ${detailOf(err)}`);
|
|
89
|
+
}
|
|
90
|
+
if (out.rpc_error)
|
|
91
|
+
throw new RpcError(out.rpc_error.code, out.rpc_error.message);
|
|
92
|
+
if (!out.result)
|
|
93
|
+
throw new RpcError(-32603, "Wakeshift didn't answer for this task");
|
|
94
|
+
return out.result;
|
|
95
|
+
};
|
|
96
|
+
// server/discover gets the tasks extension (1.x: discover.ts's handler;
|
|
97
|
+
// 2.x: its own). initialize doesn't: older revisions' clients never see it.
|
|
98
|
+
const wrapDiscover = (h) => async (request, raw) => {
|
|
99
|
+
const out = await h(request, raw);
|
|
100
|
+
if (out && typeof out === "object") {
|
|
101
|
+
const caps = { ...(out.capabilities ?? {}) };
|
|
102
|
+
caps.extensions = { ...(caps.extensions ?? {}), [TASKS_EXTENSION]: {} };
|
|
103
|
+
return { ...out, capabilities: caps };
|
|
104
|
+
}
|
|
105
|
+
return out;
|
|
106
|
+
};
|
|
107
|
+
// tools/list lists the wait tool for a request that takes tasks; tools/call
|
|
108
|
+
// answers it. McpServer sets these when the first tool is registered,
|
|
109
|
+
// perhaps after attach, so a later set is wrapped too.
|
|
110
|
+
const wrapList = (h) => async (request, raw) => {
|
|
111
|
+
const out = await h(request, raw);
|
|
112
|
+
if (takes(raw) && out && Array.isArray(out.tools) && !out.tools.some((t) => t?.name === WAIT_TOOL)) {
|
|
113
|
+
return { ...out, tools: [...out.tools, WAIT_TOOL_DEFINITION] };
|
|
114
|
+
}
|
|
115
|
+
return out;
|
|
116
|
+
};
|
|
117
|
+
const wrapCall = (h) => async (request, raw) => (request?.params?.name === WAIT_TOOL ? waitCall(request, raw) : h(request, raw));
|
|
118
|
+
// tasks/get and tasks/cancel: Wakeshift's own tasks (their IDs start
|
|
119
|
+
// wkt1_) go to Wakeshift; any other goes to the app's own handler, if it
|
|
120
|
+
// has one.
|
|
121
|
+
const wrapTask = (path, hold) => (h) => {
|
|
122
|
+
const ours = taskRequest(path, hold);
|
|
123
|
+
return async (request, raw) => {
|
|
124
|
+
const id = request?.params?.taskId;
|
|
125
|
+
if (typeof id === "string" && id.startsWith(TASK_ID_PREFIX))
|
|
126
|
+
return ours(request, raw);
|
|
127
|
+
if (h)
|
|
128
|
+
return h(request, raw);
|
|
129
|
+
throw new RpcError(-32601, "Method not found");
|
|
130
|
+
};
|
|
131
|
+
};
|
|
132
|
+
const wrappers = {
|
|
133
|
+
"server/discover": (h) => wrapDiscover(h),
|
|
134
|
+
"tools/list": (h) => wrapList(h),
|
|
135
|
+
"tools/call": (h) => wrapCall(h),
|
|
136
|
+
"tasks/get": wrapTask("/calls/task/get", true),
|
|
137
|
+
"tasks/cancel": wrapTask("/calls/task/cancel", false),
|
|
138
|
+
};
|
|
139
|
+
for (const [method, wrap] of Object.entries(wrappers)) {
|
|
140
|
+
const h = handlers.get(method);
|
|
141
|
+
if (method.startsWith("tasks/")) {
|
|
142
|
+
// Routed by the SDK on every protocol revision (host.setTaskMethod),
|
|
143
|
+
// then answered by the wrapper, which hands anything that isn't
|
|
144
|
+
// Wakeshift's to the app's own handler, if it had one.
|
|
145
|
+
host.setTaskMethod(method);
|
|
146
|
+
Map.prototype.set.call(handlers, method, wrap(h));
|
|
147
|
+
}
|
|
148
|
+
else if (h) {
|
|
149
|
+
// Set once (serveStateless wraps what's set through handlers.set).
|
|
150
|
+
Map.prototype.set.call(handlers, method, wrap(h));
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
const set = handlers.set.bind(handlers);
|
|
154
|
+
handlers.set = (method, h) => set(method, wrappers[method] ? wrappers[method](h) : h);
|
|
155
|
+
}
|
|
156
|
+
function detailOf(err) {
|
|
157
|
+
return err instanceof WakeshiftError ? err.detail : String(err?.message ?? err);
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=tasks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tasks.js","sourceRoot":"","sources":["../src/tasks.ts"],"names":[],"mappings":"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","sourcesContent":["// MCP Tasks as a wake path (docs/harnesses.md, \"Claude Code: MCP tasks as a\n// wake path\"): for a client that takes MCP tasks, on protocol 2026-07-28\n// (discover.ts), attach serves Wakeshift's wait tool, wakeshift_wait. Its\n// call is answered with a task that completes when the conversation's next\n// Wakeshift messages arrive; the client follows it in the background\n// (tasks/get), and a completed task wakes an idle conversation. Wakeshift\n// decides everything: the SDK passes the tool's call, tasks/get and\n// tasks/cancel to it and answers with the MCP result it returns, so every\n// SDK says the same (test/mcp-tasks-wire.json). A task is only its ID,\n// which any process answers for, so nothing is kept here.\n//\n// Only a request that declares the tasks extension in its own capabilities\n// (2026-07-28 has no initialize: each request carries them) sees the wait\n// tool, and a wrapped tool's call from it tells Wakeshift so (call.tasks),\n// which then gives the wait tool's instructions instead of its harness's\n// zero-install path (Claude Code's Monitor). Everything else is unchanged.\n\nimport { WakeshiftError } from \"./errors.js\";\nimport { TASKS_EXTENSION, takesTasks } from \"./discover.js\";\nimport type { Handler, Host } from \"./host.js\";\nimport { RpcError } from \"./mcp.js\";\nimport { WAKE_ARG_DESCRIPTIONS } from \"./toolcall.js\";\nimport { toolCallOf, type Wakeshift } from \"./wakeshift.js\";\n\n/** The wait tool's name. */\nexport const WAIT_TOOL = \"wakeshift_wait\";\n\n/** The wait tool's description: the core's harnesses.WaitToolDescription. */\nexport const WAIT_TOOL_DESCRIPTION =\n \"Wait for this conversation's next Wakeshift messages from this app. Returns at once and keeps waiting in the background: when messages arrive, its result reaches you as a task notification. Call it again after each one, with the session_key Wakeshift gave you.\";\n\n/** What every Wakeshift task ID starts with: tasks/get and tasks/cancel for any other ID aren't Wakeshift's. */\nexport const TASK_ID_PREFIX = \"wkt1_\";\n\n/** How long Wakeshift holds a tasks/get for a working task, in seconds. */\nexport const TASK_HOLD_SECONDS = 20;\n\n/** The wait tool as tools/list lists it. */\nexport const WAIT_TOOL_DEFINITION = {\n name: WAIT_TOOL,\n description: WAIT_TOOL_DESCRIPTION,\n inputSchema: {\n type: \"object\",\n properties: {\n session_key: { type: \"string\", description: WAKE_ARG_DESCRIPTIONS.session_key },\n harness: { type: \"string\", description: WAKE_ARG_DESCRIPTIONS.harness },\n conversation_id: { type: \"string\", description: WAKE_ARG_DESCRIPTIONS.conversation_id },\n },\n additionalProperties: false,\n },\n} as const;\n\nexport { TASKS_EXTENSION, takesTasks };\n\n/** What the core answers a task request with. */\ninterface TaskAnswer {\n result?: Record<string, unknown>;\n rpc_error?: { code: number; message: string };\n}\n\n/** @internal Who's calling, for a request (the MCP SDK's own context): the user (identify's) and the client's name. */\nexport type CallerOf = (raw: unknown) => { user: string | undefined; client: string };\n\n/**\n * @internal Serves the wait tool, tasks/get and tasks/cancel on server\n * (after serveStateless): the tasks extension in server/discover, the tool\n * in tools/list for a request that takes tasks, and its calls and task\n * requests passed to Wakeshift.\n */\nexport function serveTasks(wake: Wakeshift, host: Host, callerOf: CallerOf): void {\n const handlers = host.handlers();\n if (!handlers) return; // a future SDK: nothing to hook (no wait tool)\n\n const call = (raw: unknown, args: Record<string, unknown>) => {\n const { user, client } = callerOf(raw);\n return toolCallOf(host.req(raw), client, user, args, WAIT_TOOL);\n };\n const takes = (raw: unknown) => {\n const req = host.req(raw);\n return takesTasks(req.meta, req);\n };\n const waitCall: Handler = async (request, raw) => {\n const args = (request?.params?.arguments ?? {}) as Record<string, unknown>;\n try {\n const out = await wake.requestApp<TaskAnswer>(\"POST\", \"/calls/task\", { call: call(raw, args) });\n if (out.result) return out.result;\n } catch (err) {\n return { isError: true, content: [{ type: \"text\", text: `Wakeshift couldn't start the wait (${detailOf(err)}). Call ${WAIT_TOOL} again.` }] };\n }\n return { isError: true, content: [{ type: \"text\", text: `Wakeshift didn't answer the wait. Call ${WAIT_TOOL} again.` }] };\n };\n const taskRequest = (path: string, hold: boolean): Handler => async (request, raw) => {\n const task = request?.params?.taskId;\n const body: Record<string, unknown> = { task: typeof task === \"string\" ? task : \"\", call: call(raw, {}) };\n if (hold) body.hold_seconds = TASK_HOLD_SECONDS;\n const signal = host.req(raw).signal;\n let out: TaskAnswer;\n try {\n out = await wake.requestApp<TaskAnswer>(\"POST\", path, body, { timeoutMs: (TASK_HOLD_SECONDS + 15) * 1000, signal });\n } catch (err) {\n if (signal?.aborted) throw new RpcError(-32603, \"canceled by the client\");\n throw new RpcError(-32603, `Wakeshift: ${detailOf(err)}`);\n }\n if (out.rpc_error) throw new RpcError(out.rpc_error.code, out.rpc_error.message);\n if (!out.result) throw new RpcError(-32603, \"Wakeshift didn't answer for this task\");\n return out.result;\n };\n\n // server/discover gets the tasks extension (1.x: discover.ts's handler;\n // 2.x: its own). initialize doesn't: older revisions' clients never see it.\n const wrapDiscover = (h: Handler): Handler => async (request, raw) => {\n const out = await h(request, raw);\n if (out && typeof out === \"object\") {\n const caps = { ...(out.capabilities ?? {}) };\n caps.extensions = { ...(caps.extensions ?? {}), [TASKS_EXTENSION]: {} };\n return { ...out, capabilities: caps };\n }\n return out;\n };\n // tools/list lists the wait tool for a request that takes tasks; tools/call\n // answers it. McpServer sets these when the first tool is registered,\n // perhaps after attach, so a later set is wrapped too.\n const wrapList = (h: Handler): Handler => async (request, raw) => {\n const out = await h(request, raw);\n if (takes(raw) && out && Array.isArray(out.tools) && !out.tools.some((t: any) => t?.name === WAIT_TOOL)) {\n return { ...out, tools: [...out.tools, WAIT_TOOL_DEFINITION] };\n }\n return out;\n };\n const wrapCall = (h: Handler): Handler => async (request, raw) => (request?.params?.name === WAIT_TOOL ? waitCall(request, raw) : h(request, raw));\n // tasks/get and tasks/cancel: Wakeshift's own tasks (their IDs start\n // wkt1_) go to Wakeshift; any other goes to the app's own handler, if it\n // has one.\n const wrapTask = (path: string, hold: boolean) => (h: Handler | undefined): Handler => {\n const ours = taskRequest(path, hold);\n return async (request, raw) => {\n const id = request?.params?.taskId;\n if (typeof id === \"string\" && id.startsWith(TASK_ID_PREFIX)) return ours(request, raw);\n if (h) return h(request, raw);\n throw new RpcError(-32601, \"Method not found\");\n };\n };\n const wrappers: Record<string, (h: Handler | undefined) => Handler> = {\n \"server/discover\": (h) => wrapDiscover(h!),\n \"tools/list\": (h) => wrapList(h!),\n \"tools/call\": (h) => wrapCall(h!),\n \"tasks/get\": wrapTask(\"/calls/task/get\", true),\n \"tasks/cancel\": wrapTask(\"/calls/task/cancel\", false),\n };\n for (const [method, wrap] of Object.entries(wrappers)) {\n const h = handlers.get(method);\n if (method.startsWith(\"tasks/\")) {\n // Routed by the SDK on every protocol revision (host.setTaskMethod),\n // then answered by the wrapper, which hands anything that isn't\n // Wakeshift's to the app's own handler, if it had one.\n host.setTaskMethod(method);\n Map.prototype.set.call(handlers, method, wrap(h));\n } else if (h) {\n // Set once (serveStateless wraps what's set through handlers.set).\n Map.prototype.set.call(handlers, method, wrap(h));\n }\n }\n const set = handlers.set.bind(handlers);\n handlers.set = (method: string, h: Handler) => set(method, wrappers[method] ? wrappers[method](h) : h);\n}\n\nfunction detailOf(err: unknown): string {\n return err instanceof WakeshiftError ? err.detail : String((err as Error)?.message ?? err);\n}\n"]}
|