@mcp-b/webmcp-ts-sdk 2.0.0 → 2.0.2
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/README.md +5 -5
- package/dist/index.d.ts +163 -25
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4692 -47
- package/dist/index.js.map +1 -1
- package/package.json +17 -3
package/dist/index.js
CHANGED
|
@@ -1,88 +1,4733 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
1
|
+
import * as z3rt from "zod/v3";
|
|
2
|
+
import * as z4mini from "zod/v4-mini";
|
|
3
|
+
import * as z from "zod/v4";
|
|
4
|
+
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
5
|
+
import { ZodOptional } from "zod";
|
|
6
|
+
import { isPlainObject, validateArgsWithSchema } from "@mcp-b/webmcp-polyfill";
|
|
7
7
|
|
|
8
|
-
//#region
|
|
8
|
+
//#region ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.26.0_@cfworker+json-schema@4.1.1_zod@4.3.5/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-compat.js
|
|
9
|
+
function isZ4Schema(s) {
|
|
10
|
+
return !!s._zod;
|
|
11
|
+
}
|
|
12
|
+
function objectFromShape(shape) {
|
|
13
|
+
const values = Object.values(shape);
|
|
14
|
+
if (values.length === 0) return z4mini.object({});
|
|
15
|
+
const allV4 = values.every(isZ4Schema);
|
|
16
|
+
const allV3 = values.every((s) => !isZ4Schema(s));
|
|
17
|
+
if (allV4) return z4mini.object(shape);
|
|
18
|
+
if (allV3) return z3rt.object(shape);
|
|
19
|
+
throw new Error("Mixed Zod versions detected in object shape.");
|
|
20
|
+
}
|
|
21
|
+
function safeParse(schema, data) {
|
|
22
|
+
if (isZ4Schema(schema)) return z4mini.safeParse(schema, data);
|
|
23
|
+
return schema.safeParse(data);
|
|
24
|
+
}
|
|
25
|
+
async function safeParseAsync(schema, data) {
|
|
26
|
+
if (isZ4Schema(schema)) return await z4mini.safeParseAsync(schema, data);
|
|
27
|
+
return await schema.safeParseAsync(data);
|
|
28
|
+
}
|
|
29
|
+
function getObjectShape(schema) {
|
|
30
|
+
if (!schema) return void 0;
|
|
31
|
+
let rawShape;
|
|
32
|
+
if (isZ4Schema(schema)) rawShape = schema._zod?.def?.shape;
|
|
33
|
+
else rawShape = schema.shape;
|
|
34
|
+
if (!rawShape) return void 0;
|
|
35
|
+
if (typeof rawShape === "function") try {
|
|
36
|
+
return rawShape();
|
|
37
|
+
} catch {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
return rawShape;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Normalizes a schema to an object schema. Handles both:
|
|
44
|
+
* - Already-constructed object schemas (v3 or v4)
|
|
45
|
+
* - Raw shapes that need to be wrapped into object schemas
|
|
46
|
+
*/
|
|
47
|
+
function normalizeObjectSchema(schema) {
|
|
48
|
+
if (!schema) return void 0;
|
|
49
|
+
if (typeof schema === "object") {
|
|
50
|
+
const asV3 = schema;
|
|
51
|
+
const asV4 = schema;
|
|
52
|
+
if (!asV3._def && !asV4._zod) {
|
|
53
|
+
const values = Object.values(schema);
|
|
54
|
+
if (values.length > 0 && values.every((v) => typeof v === "object" && v !== null && (v._def !== void 0 || v._zod !== void 0 || typeof v.parse === "function"))) return objectFromShape(schema);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (isZ4Schema(schema)) {
|
|
58
|
+
const def = schema._zod?.def;
|
|
59
|
+
if (def && (def.type === "object" || def.shape !== void 0)) return schema;
|
|
60
|
+
} else if (schema.shape !== void 0) return schema;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Safely extracts an error message from a parse result error.
|
|
64
|
+
* Zod errors can have different structures, so we handle various cases.
|
|
65
|
+
*/
|
|
66
|
+
function getParseErrorMessage(error) {
|
|
67
|
+
if (error && typeof error === "object") {
|
|
68
|
+
if ("message" in error && typeof error.message === "string") return error.message;
|
|
69
|
+
if ("issues" in error && Array.isArray(error.issues) && error.issues.length > 0) {
|
|
70
|
+
const firstIssue = error.issues[0];
|
|
71
|
+
if (firstIssue && typeof firstIssue === "object" && "message" in firstIssue) return String(firstIssue.message);
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
return JSON.stringify(error);
|
|
75
|
+
} catch {
|
|
76
|
+
return String(error);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return String(error);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Gets the description from a schema, if available.
|
|
83
|
+
* Works with both Zod v3 and v4.
|
|
84
|
+
*
|
|
85
|
+
* Both versions expose a `.description` getter that returns the description
|
|
86
|
+
* from their respective internal storage (v3: _def, v4: globalRegistry).
|
|
87
|
+
*/
|
|
88
|
+
function getSchemaDescription(schema) {
|
|
89
|
+
return schema.description;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Checks if a schema is optional.
|
|
93
|
+
* Works with both Zod v3 and v4.
|
|
94
|
+
*/
|
|
95
|
+
function isSchemaOptional(schema) {
|
|
96
|
+
if (isZ4Schema(schema)) return schema._zod?.def?.type === "optional";
|
|
97
|
+
const v3Schema = schema;
|
|
98
|
+
if (typeof schema.isOptional === "function") return schema.isOptional();
|
|
99
|
+
return v3Schema._def?.typeName === "ZodOptional";
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Gets the literal value from a schema, if it's a literal schema.
|
|
103
|
+
* Works with both Zod v3 and v4.
|
|
104
|
+
* Returns undefined if the schema is not a literal or the value cannot be determined.
|
|
105
|
+
*/
|
|
106
|
+
function getLiteralValue(schema) {
|
|
107
|
+
if (isZ4Schema(schema)) {
|
|
108
|
+
const def$1 = schema._zod?.def;
|
|
109
|
+
if (def$1) {
|
|
110
|
+
if (def$1.value !== void 0) return def$1.value;
|
|
111
|
+
if (Array.isArray(def$1.values) && def$1.values.length > 0) return def$1.values[0];
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const def = schema._def;
|
|
115
|
+
if (def) {
|
|
116
|
+
if (def.value !== void 0) return def.value;
|
|
117
|
+
if (Array.isArray(def.values) && def.values.length > 0) return def.values[0];
|
|
118
|
+
}
|
|
119
|
+
const directValue = schema.value;
|
|
120
|
+
if (directValue !== void 0) return directValue;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
//#endregion
|
|
124
|
+
//#region ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.26.0_@cfworker+json-schema@4.1.1_zod@4.3.5/node_modules/@modelcontextprotocol/sdk/dist/esm/types.js
|
|
125
|
+
const LATEST_PROTOCOL_VERSION = "2025-11-25";
|
|
126
|
+
const SUPPORTED_PROTOCOL_VERSIONS = [
|
|
127
|
+
LATEST_PROTOCOL_VERSION,
|
|
128
|
+
"2025-06-18",
|
|
129
|
+
"2025-03-26",
|
|
130
|
+
"2024-11-05",
|
|
131
|
+
"2024-10-07"
|
|
132
|
+
];
|
|
133
|
+
const RELATED_TASK_META_KEY = "io.modelcontextprotocol/related-task";
|
|
134
|
+
const JSONRPC_VERSION = "2.0";
|
|
135
|
+
/**
|
|
136
|
+
* Assert 'object' type schema.
|
|
137
|
+
*
|
|
138
|
+
* @internal
|
|
139
|
+
*/
|
|
140
|
+
const AssertObjectSchema = z.custom((v) => v !== null && (typeof v === "object" || typeof v === "function"));
|
|
141
|
+
/**
|
|
142
|
+
* A progress token, used to associate progress notifications with the original request.
|
|
143
|
+
*/
|
|
144
|
+
const ProgressTokenSchema = z.union([z.string(), z.number().int()]);
|
|
145
|
+
/**
|
|
146
|
+
* An opaque token used to represent a cursor for pagination.
|
|
147
|
+
*/
|
|
148
|
+
const CursorSchema = z.string();
|
|
149
|
+
/**
|
|
150
|
+
* Task creation parameters, used to ask that the server create a task to represent a request.
|
|
151
|
+
*/
|
|
152
|
+
const TaskCreationParamsSchema = z.looseObject({
|
|
153
|
+
ttl: z.union([z.number(), z.null()]).optional(),
|
|
154
|
+
pollInterval: z.number().optional()
|
|
155
|
+
});
|
|
156
|
+
const TaskMetadataSchema = z.object({ ttl: z.number().optional() });
|
|
157
|
+
/**
|
|
158
|
+
* Metadata for associating messages with a task.
|
|
159
|
+
* Include this in the `_meta` field under the key `io.modelcontextprotocol/related-task`.
|
|
160
|
+
*/
|
|
161
|
+
const RelatedTaskMetadataSchema = z.object({ taskId: z.string() });
|
|
162
|
+
const RequestMetaSchema = z.looseObject({
|
|
163
|
+
progressToken: ProgressTokenSchema.optional(),
|
|
164
|
+
[RELATED_TASK_META_KEY]: RelatedTaskMetadataSchema.optional()
|
|
165
|
+
});
|
|
166
|
+
/**
|
|
167
|
+
* Common params for any request.
|
|
168
|
+
*/
|
|
169
|
+
const BaseRequestParamsSchema = z.object({ _meta: RequestMetaSchema.optional() });
|
|
170
|
+
/**
|
|
171
|
+
* Common params for any task-augmented request.
|
|
172
|
+
*/
|
|
173
|
+
const TaskAugmentedRequestParamsSchema = BaseRequestParamsSchema.extend({ task: TaskMetadataSchema.optional() });
|
|
174
|
+
/**
|
|
175
|
+
* Checks if a value is a valid TaskAugmentedRequestParams.
|
|
176
|
+
* @param value - The value to check.
|
|
177
|
+
*
|
|
178
|
+
* @returns True if the value is a valid TaskAugmentedRequestParams, false otherwise.
|
|
179
|
+
*/
|
|
180
|
+
const isTaskAugmentedRequestParams = (value) => TaskAugmentedRequestParamsSchema.safeParse(value).success;
|
|
181
|
+
const RequestSchema = z.object({
|
|
182
|
+
method: z.string(),
|
|
183
|
+
params: BaseRequestParamsSchema.loose().optional()
|
|
184
|
+
});
|
|
185
|
+
const NotificationsParamsSchema = z.object({ _meta: RequestMetaSchema.optional() });
|
|
186
|
+
const NotificationSchema = z.object({
|
|
187
|
+
method: z.string(),
|
|
188
|
+
params: NotificationsParamsSchema.loose().optional()
|
|
189
|
+
});
|
|
190
|
+
const ResultSchema = z.looseObject({ _meta: RequestMetaSchema.optional() });
|
|
191
|
+
/**
|
|
192
|
+
* A uniquely identifying ID for a request in JSON-RPC.
|
|
193
|
+
*/
|
|
194
|
+
const RequestIdSchema = z.union([z.string(), z.number().int()]);
|
|
195
|
+
/**
|
|
196
|
+
* A request that expects a response.
|
|
197
|
+
*/
|
|
198
|
+
const JSONRPCRequestSchema = z.object({
|
|
199
|
+
jsonrpc: z.literal(JSONRPC_VERSION),
|
|
200
|
+
id: RequestIdSchema,
|
|
201
|
+
...RequestSchema.shape
|
|
202
|
+
}).strict();
|
|
203
|
+
const isJSONRPCRequest = (value) => JSONRPCRequestSchema.safeParse(value).success;
|
|
204
|
+
/**
|
|
205
|
+
* A notification which does not expect a response.
|
|
206
|
+
*/
|
|
207
|
+
const JSONRPCNotificationSchema = z.object({
|
|
208
|
+
jsonrpc: z.literal(JSONRPC_VERSION),
|
|
209
|
+
...NotificationSchema.shape
|
|
210
|
+
}).strict();
|
|
211
|
+
const isJSONRPCNotification = (value) => JSONRPCNotificationSchema.safeParse(value).success;
|
|
212
|
+
/**
|
|
213
|
+
* A successful (non-error) response to a request.
|
|
214
|
+
*/
|
|
215
|
+
const JSONRPCResultResponseSchema = z.object({
|
|
216
|
+
jsonrpc: z.literal(JSONRPC_VERSION),
|
|
217
|
+
id: RequestIdSchema,
|
|
218
|
+
result: ResultSchema
|
|
219
|
+
}).strict();
|
|
220
|
+
/**
|
|
221
|
+
* Checks if a value is a valid JSONRPCResultResponse.
|
|
222
|
+
* @param value - The value to check.
|
|
223
|
+
*
|
|
224
|
+
* @returns True if the value is a valid JSONRPCResultResponse, false otherwise.
|
|
225
|
+
*/
|
|
226
|
+
const isJSONRPCResultResponse = (value) => JSONRPCResultResponseSchema.safeParse(value).success;
|
|
227
|
+
/**
|
|
228
|
+
* Error codes defined by the JSON-RPC specification.
|
|
229
|
+
*/
|
|
230
|
+
var ErrorCode;
|
|
231
|
+
(function(ErrorCode$1) {
|
|
232
|
+
ErrorCode$1[ErrorCode$1["ConnectionClosed"] = -32e3] = "ConnectionClosed";
|
|
233
|
+
ErrorCode$1[ErrorCode$1["RequestTimeout"] = -32001] = "RequestTimeout";
|
|
234
|
+
ErrorCode$1[ErrorCode$1["ParseError"] = -32700] = "ParseError";
|
|
235
|
+
ErrorCode$1[ErrorCode$1["InvalidRequest"] = -32600] = "InvalidRequest";
|
|
236
|
+
ErrorCode$1[ErrorCode$1["MethodNotFound"] = -32601] = "MethodNotFound";
|
|
237
|
+
ErrorCode$1[ErrorCode$1["InvalidParams"] = -32602] = "InvalidParams";
|
|
238
|
+
ErrorCode$1[ErrorCode$1["InternalError"] = -32603] = "InternalError";
|
|
239
|
+
ErrorCode$1[ErrorCode$1["UrlElicitationRequired"] = -32042] = "UrlElicitationRequired";
|
|
240
|
+
})(ErrorCode || (ErrorCode = {}));
|
|
241
|
+
/**
|
|
242
|
+
* A response to a request that indicates an error occurred.
|
|
243
|
+
*/
|
|
244
|
+
const JSONRPCErrorResponseSchema = z.object({
|
|
245
|
+
jsonrpc: z.literal(JSONRPC_VERSION),
|
|
246
|
+
id: RequestIdSchema.optional(),
|
|
247
|
+
error: z.object({
|
|
248
|
+
code: z.number().int(),
|
|
249
|
+
message: z.string(),
|
|
250
|
+
data: z.unknown().optional()
|
|
251
|
+
})
|
|
252
|
+
}).strict();
|
|
253
|
+
/**
|
|
254
|
+
* Checks if a value is a valid JSONRPCErrorResponse.
|
|
255
|
+
* @param value - The value to check.
|
|
256
|
+
*
|
|
257
|
+
* @returns True if the value is a valid JSONRPCErrorResponse, false otherwise.
|
|
258
|
+
*/
|
|
259
|
+
const isJSONRPCErrorResponse = (value) => JSONRPCErrorResponseSchema.safeParse(value).success;
|
|
260
|
+
const JSONRPCMessageSchema = z.union([
|
|
261
|
+
JSONRPCRequestSchema,
|
|
262
|
+
JSONRPCNotificationSchema,
|
|
263
|
+
JSONRPCResultResponseSchema,
|
|
264
|
+
JSONRPCErrorResponseSchema
|
|
265
|
+
]);
|
|
266
|
+
const JSONRPCResponseSchema = z.union([JSONRPCResultResponseSchema, JSONRPCErrorResponseSchema]);
|
|
267
|
+
/**
|
|
268
|
+
* A response that indicates success but carries no data.
|
|
269
|
+
*/
|
|
270
|
+
const EmptyResultSchema = ResultSchema.strict();
|
|
271
|
+
const CancelledNotificationParamsSchema = NotificationsParamsSchema.extend({
|
|
272
|
+
requestId: RequestIdSchema.optional(),
|
|
273
|
+
reason: z.string().optional()
|
|
274
|
+
});
|
|
275
|
+
/**
|
|
276
|
+
* This notification can be sent by either side to indicate that it is cancelling a previously-issued request.
|
|
277
|
+
*
|
|
278
|
+
* The request SHOULD still be in-flight, but due to communication latency, it is always possible that this notification MAY arrive after the request has already finished.
|
|
279
|
+
*
|
|
280
|
+
* This notification indicates that the result will be unused, so any associated processing SHOULD cease.
|
|
281
|
+
*
|
|
282
|
+
* A client MUST NOT attempt to cancel its `initialize` request.
|
|
283
|
+
*/
|
|
284
|
+
const CancelledNotificationSchema = NotificationSchema.extend({
|
|
285
|
+
method: z.literal("notifications/cancelled"),
|
|
286
|
+
params: CancelledNotificationParamsSchema
|
|
287
|
+
});
|
|
288
|
+
/**
|
|
289
|
+
* Icon schema for use in tools, prompts, resources, and implementations.
|
|
290
|
+
*/
|
|
291
|
+
const IconSchema = z.object({
|
|
292
|
+
src: z.string(),
|
|
293
|
+
mimeType: z.string().optional(),
|
|
294
|
+
sizes: z.array(z.string()).optional(),
|
|
295
|
+
theme: z.enum(["light", "dark"]).optional()
|
|
296
|
+
});
|
|
297
|
+
/**
|
|
298
|
+
* Base schema to add `icons` property.
|
|
299
|
+
*
|
|
300
|
+
*/
|
|
301
|
+
const IconsSchema = z.object({ icons: z.array(IconSchema).optional() });
|
|
302
|
+
/**
|
|
303
|
+
* Base metadata interface for common properties across resources, tools, prompts, and implementations.
|
|
304
|
+
*/
|
|
305
|
+
const BaseMetadataSchema = z.object({
|
|
306
|
+
name: z.string(),
|
|
307
|
+
title: z.string().optional()
|
|
308
|
+
});
|
|
309
|
+
/**
|
|
310
|
+
* Describes the name and version of an MCP implementation.
|
|
311
|
+
*/
|
|
312
|
+
const ImplementationSchema = BaseMetadataSchema.extend({
|
|
313
|
+
...BaseMetadataSchema.shape,
|
|
314
|
+
...IconsSchema.shape,
|
|
315
|
+
version: z.string(),
|
|
316
|
+
websiteUrl: z.string().optional(),
|
|
317
|
+
description: z.string().optional()
|
|
318
|
+
});
|
|
319
|
+
const FormElicitationCapabilitySchema = z.intersection(z.object({ applyDefaults: z.boolean().optional() }), z.record(z.string(), z.unknown()));
|
|
320
|
+
const ElicitationCapabilitySchema = z.preprocess((value) => {
|
|
321
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
322
|
+
if (Object.keys(value).length === 0) return { form: {} };
|
|
323
|
+
}
|
|
324
|
+
return value;
|
|
325
|
+
}, z.intersection(z.object({
|
|
326
|
+
form: FormElicitationCapabilitySchema.optional(),
|
|
327
|
+
url: AssertObjectSchema.optional()
|
|
328
|
+
}), z.record(z.string(), z.unknown()).optional()));
|
|
329
|
+
/**
|
|
330
|
+
* Task capabilities for clients, indicating which request types support task creation.
|
|
331
|
+
*/
|
|
332
|
+
const ClientTasksCapabilitySchema = z.looseObject({
|
|
333
|
+
list: AssertObjectSchema.optional(),
|
|
334
|
+
cancel: AssertObjectSchema.optional(),
|
|
335
|
+
requests: z.looseObject({
|
|
336
|
+
sampling: z.looseObject({ createMessage: AssertObjectSchema.optional() }).optional(),
|
|
337
|
+
elicitation: z.looseObject({ create: AssertObjectSchema.optional() }).optional()
|
|
338
|
+
}).optional()
|
|
339
|
+
});
|
|
340
|
+
/**
|
|
341
|
+
* Task capabilities for servers, indicating which request types support task creation.
|
|
342
|
+
*/
|
|
343
|
+
const ServerTasksCapabilitySchema = z.looseObject({
|
|
344
|
+
list: AssertObjectSchema.optional(),
|
|
345
|
+
cancel: AssertObjectSchema.optional(),
|
|
346
|
+
requests: z.looseObject({ tools: z.looseObject({ call: AssertObjectSchema.optional() }).optional() }).optional()
|
|
347
|
+
});
|
|
348
|
+
/**
|
|
349
|
+
* Capabilities a client may support. Known capabilities are defined here, in this schema, but this is not a closed set: any client can define its own, additional capabilities.
|
|
350
|
+
*/
|
|
351
|
+
const ClientCapabilitiesSchema = z.object({
|
|
352
|
+
experimental: z.record(z.string(), AssertObjectSchema).optional(),
|
|
353
|
+
sampling: z.object({
|
|
354
|
+
context: AssertObjectSchema.optional(),
|
|
355
|
+
tools: AssertObjectSchema.optional()
|
|
356
|
+
}).optional(),
|
|
357
|
+
elicitation: ElicitationCapabilitySchema.optional(),
|
|
358
|
+
roots: z.object({ listChanged: z.boolean().optional() }).optional(),
|
|
359
|
+
tasks: ClientTasksCapabilitySchema.optional()
|
|
360
|
+
});
|
|
361
|
+
const InitializeRequestParamsSchema = BaseRequestParamsSchema.extend({
|
|
362
|
+
protocolVersion: z.string(),
|
|
363
|
+
capabilities: ClientCapabilitiesSchema,
|
|
364
|
+
clientInfo: ImplementationSchema
|
|
365
|
+
});
|
|
366
|
+
/**
|
|
367
|
+
* This request is sent from the client to the server when it first connects, asking it to begin initialization.
|
|
368
|
+
*/
|
|
369
|
+
const InitializeRequestSchema = RequestSchema.extend({
|
|
370
|
+
method: z.literal("initialize"),
|
|
371
|
+
params: InitializeRequestParamsSchema
|
|
372
|
+
});
|
|
373
|
+
/**
|
|
374
|
+
* Capabilities that a server may support. Known capabilities are defined here, in this schema, but this is not a closed set: any server can define its own, additional capabilities.
|
|
375
|
+
*/
|
|
376
|
+
const ServerCapabilitiesSchema = z.object({
|
|
377
|
+
experimental: z.record(z.string(), AssertObjectSchema).optional(),
|
|
378
|
+
logging: AssertObjectSchema.optional(),
|
|
379
|
+
completions: AssertObjectSchema.optional(),
|
|
380
|
+
prompts: z.object({ listChanged: z.boolean().optional() }).optional(),
|
|
381
|
+
resources: z.object({
|
|
382
|
+
subscribe: z.boolean().optional(),
|
|
383
|
+
listChanged: z.boolean().optional()
|
|
384
|
+
}).optional(),
|
|
385
|
+
tools: z.object({ listChanged: z.boolean().optional() }).optional(),
|
|
386
|
+
tasks: ServerTasksCapabilitySchema.optional()
|
|
387
|
+
});
|
|
388
|
+
/**
|
|
389
|
+
* After receiving an initialize request from the client, the server sends this response.
|
|
390
|
+
*/
|
|
391
|
+
const InitializeResultSchema = ResultSchema.extend({
|
|
392
|
+
protocolVersion: z.string(),
|
|
393
|
+
capabilities: ServerCapabilitiesSchema,
|
|
394
|
+
serverInfo: ImplementationSchema,
|
|
395
|
+
instructions: z.string().optional()
|
|
396
|
+
});
|
|
397
|
+
/**
|
|
398
|
+
* This notification is sent from the client to the server after initialization has finished.
|
|
399
|
+
*/
|
|
400
|
+
const InitializedNotificationSchema = NotificationSchema.extend({
|
|
401
|
+
method: z.literal("notifications/initialized"),
|
|
402
|
+
params: NotificationsParamsSchema.optional()
|
|
403
|
+
});
|
|
404
|
+
/**
|
|
405
|
+
* A ping, issued by either the server or the client, to check that the other party is still alive. The receiver must promptly respond, or else may be disconnected.
|
|
406
|
+
*/
|
|
407
|
+
const PingRequestSchema = RequestSchema.extend({
|
|
408
|
+
method: z.literal("ping"),
|
|
409
|
+
params: BaseRequestParamsSchema.optional()
|
|
410
|
+
});
|
|
411
|
+
const ProgressSchema = z.object({
|
|
412
|
+
progress: z.number(),
|
|
413
|
+
total: z.optional(z.number()),
|
|
414
|
+
message: z.optional(z.string())
|
|
415
|
+
});
|
|
416
|
+
const ProgressNotificationParamsSchema = z.object({
|
|
417
|
+
...NotificationsParamsSchema.shape,
|
|
418
|
+
...ProgressSchema.shape,
|
|
419
|
+
progressToken: ProgressTokenSchema
|
|
420
|
+
});
|
|
421
|
+
/**
|
|
422
|
+
* An out-of-band notification used to inform the receiver of a progress update for a long-running request.
|
|
423
|
+
*
|
|
424
|
+
* @category notifications/progress
|
|
425
|
+
*/
|
|
426
|
+
const ProgressNotificationSchema = NotificationSchema.extend({
|
|
427
|
+
method: z.literal("notifications/progress"),
|
|
428
|
+
params: ProgressNotificationParamsSchema
|
|
429
|
+
});
|
|
430
|
+
const PaginatedRequestParamsSchema = BaseRequestParamsSchema.extend({ cursor: CursorSchema.optional() });
|
|
431
|
+
const PaginatedRequestSchema = RequestSchema.extend({ params: PaginatedRequestParamsSchema.optional() });
|
|
432
|
+
const PaginatedResultSchema = ResultSchema.extend({ nextCursor: CursorSchema.optional() });
|
|
433
|
+
/**
|
|
434
|
+
* The status of a task.
|
|
435
|
+
* */
|
|
436
|
+
const TaskStatusSchema = z.enum([
|
|
437
|
+
"working",
|
|
438
|
+
"input_required",
|
|
439
|
+
"completed",
|
|
440
|
+
"failed",
|
|
441
|
+
"cancelled"
|
|
442
|
+
]);
|
|
443
|
+
/**
|
|
444
|
+
* A pollable state object associated with a request.
|
|
445
|
+
*/
|
|
446
|
+
const TaskSchema = z.object({
|
|
447
|
+
taskId: z.string(),
|
|
448
|
+
status: TaskStatusSchema,
|
|
449
|
+
ttl: z.union([z.number(), z.null()]),
|
|
450
|
+
createdAt: z.string(),
|
|
451
|
+
lastUpdatedAt: z.string(),
|
|
452
|
+
pollInterval: z.optional(z.number()),
|
|
453
|
+
statusMessage: z.optional(z.string())
|
|
454
|
+
});
|
|
455
|
+
/**
|
|
456
|
+
* Result returned when a task is created, containing the task data wrapped in a task field.
|
|
457
|
+
*/
|
|
458
|
+
const CreateTaskResultSchema = ResultSchema.extend({ task: TaskSchema });
|
|
459
|
+
/**
|
|
460
|
+
* Parameters for task status notification.
|
|
461
|
+
*/
|
|
462
|
+
const TaskStatusNotificationParamsSchema = NotificationsParamsSchema.merge(TaskSchema);
|
|
463
|
+
/**
|
|
464
|
+
* A notification sent when a task's status changes.
|
|
465
|
+
*/
|
|
466
|
+
const TaskStatusNotificationSchema = NotificationSchema.extend({
|
|
467
|
+
method: z.literal("notifications/tasks/status"),
|
|
468
|
+
params: TaskStatusNotificationParamsSchema
|
|
469
|
+
});
|
|
470
|
+
/**
|
|
471
|
+
* A request to get the state of a specific task.
|
|
472
|
+
*/
|
|
473
|
+
const GetTaskRequestSchema = RequestSchema.extend({
|
|
474
|
+
method: z.literal("tasks/get"),
|
|
475
|
+
params: BaseRequestParamsSchema.extend({ taskId: z.string() })
|
|
476
|
+
});
|
|
477
|
+
/**
|
|
478
|
+
* The response to a tasks/get request.
|
|
479
|
+
*/
|
|
480
|
+
const GetTaskResultSchema = ResultSchema.merge(TaskSchema);
|
|
481
|
+
/**
|
|
482
|
+
* A request to get the result of a specific task.
|
|
483
|
+
*/
|
|
484
|
+
const GetTaskPayloadRequestSchema = RequestSchema.extend({
|
|
485
|
+
method: z.literal("tasks/result"),
|
|
486
|
+
params: BaseRequestParamsSchema.extend({ taskId: z.string() })
|
|
487
|
+
});
|
|
488
|
+
/**
|
|
489
|
+
* The response to a tasks/result request.
|
|
490
|
+
* The structure matches the result type of the original request.
|
|
491
|
+
* For example, a tools/call task would return the CallToolResult structure.
|
|
492
|
+
*
|
|
493
|
+
*/
|
|
494
|
+
const GetTaskPayloadResultSchema = ResultSchema.loose();
|
|
495
|
+
/**
|
|
496
|
+
* A request to list tasks.
|
|
497
|
+
*/
|
|
498
|
+
const ListTasksRequestSchema = PaginatedRequestSchema.extend({ method: z.literal("tasks/list") });
|
|
499
|
+
/**
|
|
500
|
+
* The response to a tasks/list request.
|
|
501
|
+
*/
|
|
502
|
+
const ListTasksResultSchema = PaginatedResultSchema.extend({ tasks: z.array(TaskSchema) });
|
|
503
|
+
/**
|
|
504
|
+
* A request to cancel a specific task.
|
|
505
|
+
*/
|
|
506
|
+
const CancelTaskRequestSchema = RequestSchema.extend({
|
|
507
|
+
method: z.literal("tasks/cancel"),
|
|
508
|
+
params: BaseRequestParamsSchema.extend({ taskId: z.string() })
|
|
509
|
+
});
|
|
510
|
+
/**
|
|
511
|
+
* The response to a tasks/cancel request.
|
|
512
|
+
*/
|
|
513
|
+
const CancelTaskResultSchema = ResultSchema.merge(TaskSchema);
|
|
514
|
+
/**
|
|
515
|
+
* The contents of a specific resource or sub-resource.
|
|
516
|
+
*/
|
|
517
|
+
const ResourceContentsSchema = z.object({
|
|
518
|
+
uri: z.string(),
|
|
519
|
+
mimeType: z.optional(z.string()),
|
|
520
|
+
_meta: z.record(z.string(), z.unknown()).optional()
|
|
521
|
+
});
|
|
522
|
+
const TextResourceContentsSchema = ResourceContentsSchema.extend({ text: z.string() });
|
|
523
|
+
/**
|
|
524
|
+
* A Zod schema for validating Base64 strings that is more performant and
|
|
525
|
+
* robust for very large inputs than the default regex-based check. It avoids
|
|
526
|
+
* stack overflows by using the native `atob` function for validation.
|
|
527
|
+
*/
|
|
528
|
+
const Base64Schema = z.string().refine((val) => {
|
|
529
|
+
try {
|
|
530
|
+
atob(val);
|
|
531
|
+
return true;
|
|
532
|
+
} catch {
|
|
533
|
+
return false;
|
|
534
|
+
}
|
|
535
|
+
}, { message: "Invalid Base64 string" });
|
|
536
|
+
const BlobResourceContentsSchema = ResourceContentsSchema.extend({ blob: Base64Schema });
|
|
537
|
+
/**
|
|
538
|
+
* The sender or recipient of messages and data in a conversation.
|
|
539
|
+
*/
|
|
540
|
+
const RoleSchema = z.enum(["user", "assistant"]);
|
|
541
|
+
/**
|
|
542
|
+
* Optional annotations providing clients additional context about a resource.
|
|
543
|
+
*/
|
|
544
|
+
const AnnotationsSchema = z.object({
|
|
545
|
+
audience: z.array(RoleSchema).optional(),
|
|
546
|
+
priority: z.number().min(0).max(1).optional(),
|
|
547
|
+
lastModified: z.iso.datetime({ offset: true }).optional()
|
|
548
|
+
});
|
|
549
|
+
/**
|
|
550
|
+
* A known resource that the server is capable of reading.
|
|
551
|
+
*/
|
|
552
|
+
const ResourceSchema = z.object({
|
|
553
|
+
...BaseMetadataSchema.shape,
|
|
554
|
+
...IconsSchema.shape,
|
|
555
|
+
uri: z.string(),
|
|
556
|
+
description: z.optional(z.string()),
|
|
557
|
+
mimeType: z.optional(z.string()),
|
|
558
|
+
annotations: AnnotationsSchema.optional(),
|
|
559
|
+
_meta: z.optional(z.looseObject({}))
|
|
560
|
+
});
|
|
561
|
+
/**
|
|
562
|
+
* A template description for resources available on the server.
|
|
563
|
+
*/
|
|
564
|
+
const ResourceTemplateSchema = z.object({
|
|
565
|
+
...BaseMetadataSchema.shape,
|
|
566
|
+
...IconsSchema.shape,
|
|
567
|
+
uriTemplate: z.string(),
|
|
568
|
+
description: z.optional(z.string()),
|
|
569
|
+
mimeType: z.optional(z.string()),
|
|
570
|
+
annotations: AnnotationsSchema.optional(),
|
|
571
|
+
_meta: z.optional(z.looseObject({}))
|
|
572
|
+
});
|
|
573
|
+
/**
|
|
574
|
+
* Sent from the client to request a list of resources the server has.
|
|
575
|
+
*/
|
|
576
|
+
const ListResourcesRequestSchema = PaginatedRequestSchema.extend({ method: z.literal("resources/list") });
|
|
577
|
+
/**
|
|
578
|
+
* The server's response to a resources/list request from the client.
|
|
579
|
+
*/
|
|
580
|
+
const ListResourcesResultSchema = PaginatedResultSchema.extend({ resources: z.array(ResourceSchema) });
|
|
581
|
+
/**
|
|
582
|
+
* Sent from the client to request a list of resource templates the server has.
|
|
583
|
+
*/
|
|
584
|
+
const ListResourceTemplatesRequestSchema = PaginatedRequestSchema.extend({ method: z.literal("resources/templates/list") });
|
|
585
|
+
/**
|
|
586
|
+
* The server's response to a resources/templates/list request from the client.
|
|
587
|
+
*/
|
|
588
|
+
const ListResourceTemplatesResultSchema = PaginatedResultSchema.extend({ resourceTemplates: z.array(ResourceTemplateSchema) });
|
|
589
|
+
const ResourceRequestParamsSchema = BaseRequestParamsSchema.extend({ uri: z.string() });
|
|
590
|
+
/**
|
|
591
|
+
* Parameters for a `resources/read` request.
|
|
592
|
+
*/
|
|
593
|
+
const ReadResourceRequestParamsSchema = ResourceRequestParamsSchema;
|
|
594
|
+
/**
|
|
595
|
+
* Sent from the client to the server, to read a specific resource URI.
|
|
596
|
+
*/
|
|
597
|
+
const ReadResourceRequestSchema = RequestSchema.extend({
|
|
598
|
+
method: z.literal("resources/read"),
|
|
599
|
+
params: ReadResourceRequestParamsSchema
|
|
600
|
+
});
|
|
601
|
+
/**
|
|
602
|
+
* The server's response to a resources/read request from the client.
|
|
603
|
+
*/
|
|
604
|
+
const ReadResourceResultSchema = ResultSchema.extend({ contents: z.array(z.union([TextResourceContentsSchema, BlobResourceContentsSchema])) });
|
|
605
|
+
/**
|
|
606
|
+
* An optional notification from the server to the client, informing it that the list of resources it can read from has changed. This may be issued by servers without any previous subscription from the client.
|
|
607
|
+
*/
|
|
608
|
+
const ResourceListChangedNotificationSchema = NotificationSchema.extend({
|
|
609
|
+
method: z.literal("notifications/resources/list_changed"),
|
|
610
|
+
params: NotificationsParamsSchema.optional()
|
|
611
|
+
});
|
|
612
|
+
const SubscribeRequestParamsSchema = ResourceRequestParamsSchema;
|
|
613
|
+
/**
|
|
614
|
+
* Sent from the client to request resources/updated notifications from the server whenever a particular resource changes.
|
|
615
|
+
*/
|
|
616
|
+
const SubscribeRequestSchema = RequestSchema.extend({
|
|
617
|
+
method: z.literal("resources/subscribe"),
|
|
618
|
+
params: SubscribeRequestParamsSchema
|
|
619
|
+
});
|
|
620
|
+
const UnsubscribeRequestParamsSchema = ResourceRequestParamsSchema;
|
|
621
|
+
/**
|
|
622
|
+
* Sent from the client to request cancellation of resources/updated notifications from the server. This should follow a previous resources/subscribe request.
|
|
623
|
+
*/
|
|
624
|
+
const UnsubscribeRequestSchema = RequestSchema.extend({
|
|
625
|
+
method: z.literal("resources/unsubscribe"),
|
|
626
|
+
params: UnsubscribeRequestParamsSchema
|
|
627
|
+
});
|
|
628
|
+
/**
|
|
629
|
+
* Parameters for a `notifications/resources/updated` notification.
|
|
630
|
+
*/
|
|
631
|
+
const ResourceUpdatedNotificationParamsSchema = NotificationsParamsSchema.extend({ uri: z.string() });
|
|
632
|
+
/**
|
|
633
|
+
* A notification from the server to the client, informing it that a resource has changed and may need to be read again. This should only be sent if the client previously sent a resources/subscribe request.
|
|
634
|
+
*/
|
|
635
|
+
const ResourceUpdatedNotificationSchema = NotificationSchema.extend({
|
|
636
|
+
method: z.literal("notifications/resources/updated"),
|
|
637
|
+
params: ResourceUpdatedNotificationParamsSchema
|
|
638
|
+
});
|
|
639
|
+
/**
|
|
640
|
+
* Describes an argument that a prompt can accept.
|
|
641
|
+
*/
|
|
642
|
+
const PromptArgumentSchema = z.object({
|
|
643
|
+
name: z.string(),
|
|
644
|
+
description: z.optional(z.string()),
|
|
645
|
+
required: z.optional(z.boolean())
|
|
646
|
+
});
|
|
647
|
+
/**
|
|
648
|
+
* A prompt or prompt template that the server offers.
|
|
649
|
+
*/
|
|
650
|
+
const PromptSchema = z.object({
|
|
651
|
+
...BaseMetadataSchema.shape,
|
|
652
|
+
...IconsSchema.shape,
|
|
653
|
+
description: z.optional(z.string()),
|
|
654
|
+
arguments: z.optional(z.array(PromptArgumentSchema)),
|
|
655
|
+
_meta: z.optional(z.looseObject({}))
|
|
656
|
+
});
|
|
657
|
+
/**
|
|
658
|
+
* Sent from the client to request a list of prompts and prompt templates the server has.
|
|
659
|
+
*/
|
|
660
|
+
const ListPromptsRequestSchema = PaginatedRequestSchema.extend({ method: z.literal("prompts/list") });
|
|
661
|
+
/**
|
|
662
|
+
* The server's response to a prompts/list request from the client.
|
|
663
|
+
*/
|
|
664
|
+
const ListPromptsResultSchema = PaginatedResultSchema.extend({ prompts: z.array(PromptSchema) });
|
|
665
|
+
/**
|
|
666
|
+
* Parameters for a `prompts/get` request.
|
|
667
|
+
*/
|
|
668
|
+
const GetPromptRequestParamsSchema = BaseRequestParamsSchema.extend({
|
|
669
|
+
name: z.string(),
|
|
670
|
+
arguments: z.record(z.string(), z.string()).optional()
|
|
671
|
+
});
|
|
672
|
+
/**
|
|
673
|
+
* Used by the client to get a prompt provided by the server.
|
|
674
|
+
*/
|
|
675
|
+
const GetPromptRequestSchema = RequestSchema.extend({
|
|
676
|
+
method: z.literal("prompts/get"),
|
|
677
|
+
params: GetPromptRequestParamsSchema
|
|
678
|
+
});
|
|
679
|
+
/**
|
|
680
|
+
* Text provided to or from an LLM.
|
|
681
|
+
*/
|
|
682
|
+
const TextContentSchema = z.object({
|
|
683
|
+
type: z.literal("text"),
|
|
684
|
+
text: z.string(),
|
|
685
|
+
annotations: AnnotationsSchema.optional(),
|
|
686
|
+
_meta: z.record(z.string(), z.unknown()).optional()
|
|
687
|
+
});
|
|
688
|
+
/**
|
|
689
|
+
* An image provided to or from an LLM.
|
|
690
|
+
*/
|
|
691
|
+
const ImageContentSchema = z.object({
|
|
692
|
+
type: z.literal("image"),
|
|
693
|
+
data: Base64Schema,
|
|
694
|
+
mimeType: z.string(),
|
|
695
|
+
annotations: AnnotationsSchema.optional(),
|
|
696
|
+
_meta: z.record(z.string(), z.unknown()).optional()
|
|
697
|
+
});
|
|
698
|
+
/**
|
|
699
|
+
* An Audio provided to or from an LLM.
|
|
700
|
+
*/
|
|
701
|
+
const AudioContentSchema = z.object({
|
|
702
|
+
type: z.literal("audio"),
|
|
703
|
+
data: Base64Schema,
|
|
704
|
+
mimeType: z.string(),
|
|
705
|
+
annotations: AnnotationsSchema.optional(),
|
|
706
|
+
_meta: z.record(z.string(), z.unknown()).optional()
|
|
707
|
+
});
|
|
708
|
+
/**
|
|
709
|
+
* A tool call request from an assistant (LLM).
|
|
710
|
+
* Represents the assistant's request to use a tool.
|
|
711
|
+
*/
|
|
712
|
+
const ToolUseContentSchema = z.object({
|
|
713
|
+
type: z.literal("tool_use"),
|
|
714
|
+
name: z.string(),
|
|
715
|
+
id: z.string(),
|
|
716
|
+
input: z.record(z.string(), z.unknown()),
|
|
717
|
+
_meta: z.record(z.string(), z.unknown()).optional()
|
|
718
|
+
});
|
|
719
|
+
/**
|
|
720
|
+
* The contents of a resource, embedded into a prompt or tool call result.
|
|
721
|
+
*/
|
|
722
|
+
const EmbeddedResourceSchema = z.object({
|
|
723
|
+
type: z.literal("resource"),
|
|
724
|
+
resource: z.union([TextResourceContentsSchema, BlobResourceContentsSchema]),
|
|
725
|
+
annotations: AnnotationsSchema.optional(),
|
|
726
|
+
_meta: z.record(z.string(), z.unknown()).optional()
|
|
727
|
+
});
|
|
728
|
+
/**
|
|
729
|
+
* A resource that the server is capable of reading, included in a prompt or tool call result.
|
|
730
|
+
*
|
|
731
|
+
* Note: resource links returned by tools are not guaranteed to appear in the results of `resources/list` requests.
|
|
732
|
+
*/
|
|
733
|
+
const ResourceLinkSchema = ResourceSchema.extend({ type: z.literal("resource_link") });
|
|
734
|
+
/**
|
|
735
|
+
* A content block that can be used in prompts and tool results.
|
|
736
|
+
*/
|
|
737
|
+
const ContentBlockSchema = z.union([
|
|
738
|
+
TextContentSchema,
|
|
739
|
+
ImageContentSchema,
|
|
740
|
+
AudioContentSchema,
|
|
741
|
+
ResourceLinkSchema,
|
|
742
|
+
EmbeddedResourceSchema
|
|
743
|
+
]);
|
|
744
|
+
/**
|
|
745
|
+
* Describes a message returned as part of a prompt.
|
|
746
|
+
*/
|
|
747
|
+
const PromptMessageSchema = z.object({
|
|
748
|
+
role: RoleSchema,
|
|
749
|
+
content: ContentBlockSchema
|
|
750
|
+
});
|
|
751
|
+
/**
|
|
752
|
+
* The server's response to a prompts/get request from the client.
|
|
753
|
+
*/
|
|
754
|
+
const GetPromptResultSchema = ResultSchema.extend({
|
|
755
|
+
description: z.string().optional(),
|
|
756
|
+
messages: z.array(PromptMessageSchema)
|
|
757
|
+
});
|
|
758
|
+
/**
|
|
759
|
+
* An optional notification from the server to the client, informing it that the list of prompts it offers has changed. This may be issued by servers without any previous subscription from the client.
|
|
760
|
+
*/
|
|
761
|
+
const PromptListChangedNotificationSchema = NotificationSchema.extend({
|
|
762
|
+
method: z.literal("notifications/prompts/list_changed"),
|
|
763
|
+
params: NotificationsParamsSchema.optional()
|
|
764
|
+
});
|
|
765
|
+
/**
|
|
766
|
+
* Additional properties describing a Tool to clients.
|
|
767
|
+
*
|
|
768
|
+
* NOTE: all properties in ToolAnnotations are **hints**.
|
|
769
|
+
* They are not guaranteed to provide a faithful description of
|
|
770
|
+
* tool behavior (including descriptive properties like `title`).
|
|
771
|
+
*
|
|
772
|
+
* Clients should never make tool use decisions based on ToolAnnotations
|
|
773
|
+
* received from untrusted servers.
|
|
774
|
+
*/
|
|
775
|
+
const ToolAnnotationsSchema = z.object({
|
|
776
|
+
title: z.string().optional(),
|
|
777
|
+
readOnlyHint: z.boolean().optional(),
|
|
778
|
+
destructiveHint: z.boolean().optional(),
|
|
779
|
+
idempotentHint: z.boolean().optional(),
|
|
780
|
+
openWorldHint: z.boolean().optional()
|
|
781
|
+
});
|
|
782
|
+
/**
|
|
783
|
+
* Execution-related properties for a tool.
|
|
784
|
+
*/
|
|
785
|
+
const ToolExecutionSchema = z.object({ taskSupport: z.enum([
|
|
786
|
+
"required",
|
|
787
|
+
"optional",
|
|
788
|
+
"forbidden"
|
|
789
|
+
]).optional() });
|
|
790
|
+
/**
|
|
791
|
+
* Definition for a tool the client can call.
|
|
792
|
+
*/
|
|
793
|
+
const ToolSchema = z.object({
|
|
794
|
+
...BaseMetadataSchema.shape,
|
|
795
|
+
...IconsSchema.shape,
|
|
796
|
+
description: z.string().optional(),
|
|
797
|
+
inputSchema: z.object({
|
|
798
|
+
type: z.literal("object"),
|
|
799
|
+
properties: z.record(z.string(), AssertObjectSchema).optional(),
|
|
800
|
+
required: z.array(z.string()).optional()
|
|
801
|
+
}).catchall(z.unknown()),
|
|
802
|
+
outputSchema: z.object({
|
|
803
|
+
type: z.literal("object"),
|
|
804
|
+
properties: z.record(z.string(), AssertObjectSchema).optional(),
|
|
805
|
+
required: z.array(z.string()).optional()
|
|
806
|
+
}).catchall(z.unknown()).optional(),
|
|
807
|
+
annotations: ToolAnnotationsSchema.optional(),
|
|
808
|
+
execution: ToolExecutionSchema.optional(),
|
|
809
|
+
_meta: z.record(z.string(), z.unknown()).optional()
|
|
810
|
+
});
|
|
811
|
+
/**
|
|
812
|
+
* Sent from the client to request a list of tools the server has.
|
|
813
|
+
*/
|
|
814
|
+
const ListToolsRequestSchema = PaginatedRequestSchema.extend({ method: z.literal("tools/list") });
|
|
815
|
+
/**
|
|
816
|
+
* The server's response to a tools/list request from the client.
|
|
817
|
+
*/
|
|
818
|
+
const ListToolsResultSchema = PaginatedResultSchema.extend({ tools: z.array(ToolSchema) });
|
|
819
|
+
/**
|
|
820
|
+
* The server's response to a tool call.
|
|
821
|
+
*/
|
|
822
|
+
const CallToolResultSchema = ResultSchema.extend({
|
|
823
|
+
content: z.array(ContentBlockSchema).default([]),
|
|
824
|
+
structuredContent: z.record(z.string(), z.unknown()).optional(),
|
|
825
|
+
isError: z.boolean().optional()
|
|
826
|
+
});
|
|
827
|
+
/**
|
|
828
|
+
* CallToolResultSchema extended with backwards compatibility to protocol version 2024-10-07.
|
|
829
|
+
*/
|
|
830
|
+
const CompatibilityCallToolResultSchema = CallToolResultSchema.or(ResultSchema.extend({ toolResult: z.unknown() }));
|
|
831
|
+
/**
|
|
832
|
+
* Parameters for a `tools/call` request.
|
|
833
|
+
*/
|
|
834
|
+
const CallToolRequestParamsSchema = TaskAugmentedRequestParamsSchema.extend({
|
|
835
|
+
name: z.string(),
|
|
836
|
+
arguments: z.record(z.string(), z.unknown()).optional()
|
|
837
|
+
});
|
|
838
|
+
/**
|
|
839
|
+
* Used by the client to invoke a tool provided by the server.
|
|
840
|
+
*/
|
|
841
|
+
const CallToolRequestSchema = RequestSchema.extend({
|
|
842
|
+
method: z.literal("tools/call"),
|
|
843
|
+
params: CallToolRequestParamsSchema
|
|
844
|
+
});
|
|
845
|
+
/**
|
|
846
|
+
* An optional notification from the server to the client, informing it that the list of tools it offers has changed. This may be issued by servers without any previous subscription from the client.
|
|
847
|
+
*/
|
|
848
|
+
const ToolListChangedNotificationSchema = NotificationSchema.extend({
|
|
849
|
+
method: z.literal("notifications/tools/list_changed"),
|
|
850
|
+
params: NotificationsParamsSchema.optional()
|
|
851
|
+
});
|
|
852
|
+
/**
|
|
853
|
+
* Base schema for list changed subscription options (without callback).
|
|
854
|
+
* Used internally for Zod validation of autoRefresh and debounceMs.
|
|
855
|
+
*/
|
|
856
|
+
const ListChangedOptionsBaseSchema = z.object({
|
|
857
|
+
autoRefresh: z.boolean().default(true),
|
|
858
|
+
debounceMs: z.number().int().nonnegative().default(300)
|
|
859
|
+
});
|
|
860
|
+
/**
|
|
861
|
+
* The severity of a log message.
|
|
862
|
+
*/
|
|
863
|
+
const LoggingLevelSchema = z.enum([
|
|
864
|
+
"debug",
|
|
865
|
+
"info",
|
|
866
|
+
"notice",
|
|
867
|
+
"warning",
|
|
868
|
+
"error",
|
|
869
|
+
"critical",
|
|
870
|
+
"alert",
|
|
871
|
+
"emergency"
|
|
872
|
+
]);
|
|
873
|
+
/**
|
|
874
|
+
* Parameters for a `logging/setLevel` request.
|
|
875
|
+
*/
|
|
876
|
+
const SetLevelRequestParamsSchema = BaseRequestParamsSchema.extend({ level: LoggingLevelSchema });
|
|
877
|
+
/**
|
|
878
|
+
* A request from the client to the server, to enable or adjust logging.
|
|
879
|
+
*/
|
|
880
|
+
const SetLevelRequestSchema = RequestSchema.extend({
|
|
881
|
+
method: z.literal("logging/setLevel"),
|
|
882
|
+
params: SetLevelRequestParamsSchema
|
|
883
|
+
});
|
|
884
|
+
/**
|
|
885
|
+
* Parameters for a `notifications/message` notification.
|
|
886
|
+
*/
|
|
887
|
+
const LoggingMessageNotificationParamsSchema = NotificationsParamsSchema.extend({
|
|
888
|
+
level: LoggingLevelSchema,
|
|
889
|
+
logger: z.string().optional(),
|
|
890
|
+
data: z.unknown()
|
|
891
|
+
});
|
|
892
|
+
/**
|
|
893
|
+
* Notification of a log message passed from server to client. If no logging/setLevel request has been sent from the client, the server MAY decide which messages to send automatically.
|
|
894
|
+
*/
|
|
895
|
+
const LoggingMessageNotificationSchema = NotificationSchema.extend({
|
|
896
|
+
method: z.literal("notifications/message"),
|
|
897
|
+
params: LoggingMessageNotificationParamsSchema
|
|
898
|
+
});
|
|
899
|
+
/**
|
|
900
|
+
* Hints to use for model selection.
|
|
901
|
+
*/
|
|
902
|
+
const ModelHintSchema = z.object({ name: z.string().optional() });
|
|
903
|
+
/**
|
|
904
|
+
* The server's preferences for model selection, requested of the client during sampling.
|
|
905
|
+
*/
|
|
906
|
+
const ModelPreferencesSchema = z.object({
|
|
907
|
+
hints: z.array(ModelHintSchema).optional(),
|
|
908
|
+
costPriority: z.number().min(0).max(1).optional(),
|
|
909
|
+
speedPriority: z.number().min(0).max(1).optional(),
|
|
910
|
+
intelligencePriority: z.number().min(0).max(1).optional()
|
|
911
|
+
});
|
|
912
|
+
/**
|
|
913
|
+
* Controls tool usage behavior in sampling requests.
|
|
914
|
+
*/
|
|
915
|
+
const ToolChoiceSchema = z.object({ mode: z.enum([
|
|
916
|
+
"auto",
|
|
917
|
+
"required",
|
|
918
|
+
"none"
|
|
919
|
+
]).optional() });
|
|
920
|
+
/**
|
|
921
|
+
* The result of a tool execution, provided by the user (server).
|
|
922
|
+
* Represents the outcome of invoking a tool requested via ToolUseContent.
|
|
923
|
+
*/
|
|
924
|
+
const ToolResultContentSchema = z.object({
|
|
925
|
+
type: z.literal("tool_result"),
|
|
926
|
+
toolUseId: z.string().describe("The unique identifier for the corresponding tool call."),
|
|
927
|
+
content: z.array(ContentBlockSchema).default([]),
|
|
928
|
+
structuredContent: z.object({}).loose().optional(),
|
|
929
|
+
isError: z.boolean().optional(),
|
|
930
|
+
_meta: z.record(z.string(), z.unknown()).optional()
|
|
931
|
+
});
|
|
932
|
+
/**
|
|
933
|
+
* Basic content types for sampling responses (without tool use).
|
|
934
|
+
* Used for backwards-compatible CreateMessageResult when tools are not used.
|
|
935
|
+
*/
|
|
936
|
+
const SamplingContentSchema = z.discriminatedUnion("type", [
|
|
937
|
+
TextContentSchema,
|
|
938
|
+
ImageContentSchema,
|
|
939
|
+
AudioContentSchema
|
|
940
|
+
]);
|
|
941
|
+
/**
|
|
942
|
+
* Content block types allowed in sampling messages.
|
|
943
|
+
* This includes text, image, audio, tool use requests, and tool results.
|
|
944
|
+
*/
|
|
945
|
+
const SamplingMessageContentBlockSchema = z.discriminatedUnion("type", [
|
|
946
|
+
TextContentSchema,
|
|
947
|
+
ImageContentSchema,
|
|
948
|
+
AudioContentSchema,
|
|
949
|
+
ToolUseContentSchema,
|
|
950
|
+
ToolResultContentSchema
|
|
951
|
+
]);
|
|
952
|
+
/**
|
|
953
|
+
* Describes a message issued to or received from an LLM API.
|
|
954
|
+
*/
|
|
955
|
+
const SamplingMessageSchema = z.object({
|
|
956
|
+
role: RoleSchema,
|
|
957
|
+
content: z.union([SamplingMessageContentBlockSchema, z.array(SamplingMessageContentBlockSchema)]),
|
|
958
|
+
_meta: z.record(z.string(), z.unknown()).optional()
|
|
959
|
+
});
|
|
960
|
+
/**
|
|
961
|
+
* Parameters for a `sampling/createMessage` request.
|
|
962
|
+
*/
|
|
963
|
+
const CreateMessageRequestParamsSchema = TaskAugmentedRequestParamsSchema.extend({
|
|
964
|
+
messages: z.array(SamplingMessageSchema),
|
|
965
|
+
modelPreferences: ModelPreferencesSchema.optional(),
|
|
966
|
+
systemPrompt: z.string().optional(),
|
|
967
|
+
includeContext: z.enum([
|
|
968
|
+
"none",
|
|
969
|
+
"thisServer",
|
|
970
|
+
"allServers"
|
|
971
|
+
]).optional(),
|
|
972
|
+
temperature: z.number().optional(),
|
|
973
|
+
maxTokens: z.number().int(),
|
|
974
|
+
stopSequences: z.array(z.string()).optional(),
|
|
975
|
+
metadata: AssertObjectSchema.optional(),
|
|
976
|
+
tools: z.array(ToolSchema).optional(),
|
|
977
|
+
toolChoice: ToolChoiceSchema.optional()
|
|
978
|
+
});
|
|
979
|
+
/**
|
|
980
|
+
* A request from the server to sample an LLM via the client. The client has full discretion over which model to select. The client should also inform the user before beginning sampling, to allow them to inspect the request (human in the loop) and decide whether to approve it.
|
|
981
|
+
*/
|
|
982
|
+
const CreateMessageRequestSchema = RequestSchema.extend({
|
|
983
|
+
method: z.literal("sampling/createMessage"),
|
|
984
|
+
params: CreateMessageRequestParamsSchema
|
|
985
|
+
});
|
|
986
|
+
/**
|
|
987
|
+
* The client's response to a sampling/create_message request from the server.
|
|
988
|
+
* This is the backwards-compatible version that returns single content (no arrays).
|
|
989
|
+
* Used when the request does not include tools.
|
|
990
|
+
*/
|
|
991
|
+
const CreateMessageResultSchema = ResultSchema.extend({
|
|
992
|
+
model: z.string(),
|
|
993
|
+
stopReason: z.optional(z.enum([
|
|
994
|
+
"endTurn",
|
|
995
|
+
"stopSequence",
|
|
996
|
+
"maxTokens"
|
|
997
|
+
]).or(z.string())),
|
|
998
|
+
role: RoleSchema,
|
|
999
|
+
content: SamplingContentSchema
|
|
1000
|
+
});
|
|
1001
|
+
/**
|
|
1002
|
+
* The client's response to a sampling/create_message request when tools were provided.
|
|
1003
|
+
* This version supports array content for tool use flows.
|
|
1004
|
+
*/
|
|
1005
|
+
const CreateMessageResultWithToolsSchema = ResultSchema.extend({
|
|
1006
|
+
model: z.string(),
|
|
1007
|
+
stopReason: z.optional(z.enum([
|
|
1008
|
+
"endTurn",
|
|
1009
|
+
"stopSequence",
|
|
1010
|
+
"maxTokens",
|
|
1011
|
+
"toolUse"
|
|
1012
|
+
]).or(z.string())),
|
|
1013
|
+
role: RoleSchema,
|
|
1014
|
+
content: z.union([SamplingMessageContentBlockSchema, z.array(SamplingMessageContentBlockSchema)])
|
|
1015
|
+
});
|
|
1016
|
+
/**
|
|
1017
|
+
* Primitive schema definition for boolean fields.
|
|
1018
|
+
*/
|
|
1019
|
+
const BooleanSchemaSchema = z.object({
|
|
1020
|
+
type: z.literal("boolean"),
|
|
1021
|
+
title: z.string().optional(),
|
|
1022
|
+
description: z.string().optional(),
|
|
1023
|
+
default: z.boolean().optional()
|
|
1024
|
+
});
|
|
1025
|
+
/**
|
|
1026
|
+
* Primitive schema definition for string fields.
|
|
1027
|
+
*/
|
|
1028
|
+
const StringSchemaSchema = z.object({
|
|
1029
|
+
type: z.literal("string"),
|
|
1030
|
+
title: z.string().optional(),
|
|
1031
|
+
description: z.string().optional(),
|
|
1032
|
+
minLength: z.number().optional(),
|
|
1033
|
+
maxLength: z.number().optional(),
|
|
1034
|
+
format: z.enum([
|
|
1035
|
+
"email",
|
|
1036
|
+
"uri",
|
|
1037
|
+
"date",
|
|
1038
|
+
"date-time"
|
|
1039
|
+
]).optional(),
|
|
1040
|
+
default: z.string().optional()
|
|
1041
|
+
});
|
|
1042
|
+
/**
|
|
1043
|
+
* Primitive schema definition for number fields.
|
|
1044
|
+
*/
|
|
1045
|
+
const NumberSchemaSchema = z.object({
|
|
1046
|
+
type: z.enum(["number", "integer"]),
|
|
1047
|
+
title: z.string().optional(),
|
|
1048
|
+
description: z.string().optional(),
|
|
1049
|
+
minimum: z.number().optional(),
|
|
1050
|
+
maximum: z.number().optional(),
|
|
1051
|
+
default: z.number().optional()
|
|
1052
|
+
});
|
|
1053
|
+
/**
|
|
1054
|
+
* Schema for single-selection enumeration without display titles for options.
|
|
1055
|
+
*/
|
|
1056
|
+
const UntitledSingleSelectEnumSchemaSchema = z.object({
|
|
1057
|
+
type: z.literal("string"),
|
|
1058
|
+
title: z.string().optional(),
|
|
1059
|
+
description: z.string().optional(),
|
|
1060
|
+
enum: z.array(z.string()),
|
|
1061
|
+
default: z.string().optional()
|
|
1062
|
+
});
|
|
1063
|
+
/**
|
|
1064
|
+
* Schema for single-selection enumeration with display titles for each option.
|
|
1065
|
+
*/
|
|
1066
|
+
const TitledSingleSelectEnumSchemaSchema = z.object({
|
|
1067
|
+
type: z.literal("string"),
|
|
1068
|
+
title: z.string().optional(),
|
|
1069
|
+
description: z.string().optional(),
|
|
1070
|
+
oneOf: z.array(z.object({
|
|
1071
|
+
const: z.string(),
|
|
1072
|
+
title: z.string()
|
|
1073
|
+
})),
|
|
1074
|
+
default: z.string().optional()
|
|
1075
|
+
});
|
|
1076
|
+
/**
|
|
1077
|
+
* Use TitledSingleSelectEnumSchema instead.
|
|
1078
|
+
* This interface will be removed in a future version.
|
|
1079
|
+
*/
|
|
1080
|
+
const LegacyTitledEnumSchemaSchema = z.object({
|
|
1081
|
+
type: z.literal("string"),
|
|
1082
|
+
title: z.string().optional(),
|
|
1083
|
+
description: z.string().optional(),
|
|
1084
|
+
enum: z.array(z.string()),
|
|
1085
|
+
enumNames: z.array(z.string()).optional(),
|
|
1086
|
+
default: z.string().optional()
|
|
1087
|
+
});
|
|
1088
|
+
const SingleSelectEnumSchemaSchema = z.union([UntitledSingleSelectEnumSchemaSchema, TitledSingleSelectEnumSchemaSchema]);
|
|
1089
|
+
/**
|
|
1090
|
+
* Schema for multiple-selection enumeration without display titles for options.
|
|
1091
|
+
*/
|
|
1092
|
+
const UntitledMultiSelectEnumSchemaSchema = z.object({
|
|
1093
|
+
type: z.literal("array"),
|
|
1094
|
+
title: z.string().optional(),
|
|
1095
|
+
description: z.string().optional(),
|
|
1096
|
+
minItems: z.number().optional(),
|
|
1097
|
+
maxItems: z.number().optional(),
|
|
1098
|
+
items: z.object({
|
|
1099
|
+
type: z.literal("string"),
|
|
1100
|
+
enum: z.array(z.string())
|
|
1101
|
+
}),
|
|
1102
|
+
default: z.array(z.string()).optional()
|
|
1103
|
+
});
|
|
1104
|
+
/**
|
|
1105
|
+
* Schema for multiple-selection enumeration with display titles for each option.
|
|
1106
|
+
*/
|
|
1107
|
+
const TitledMultiSelectEnumSchemaSchema = z.object({
|
|
1108
|
+
type: z.literal("array"),
|
|
1109
|
+
title: z.string().optional(),
|
|
1110
|
+
description: z.string().optional(),
|
|
1111
|
+
minItems: z.number().optional(),
|
|
1112
|
+
maxItems: z.number().optional(),
|
|
1113
|
+
items: z.object({ anyOf: z.array(z.object({
|
|
1114
|
+
const: z.string(),
|
|
1115
|
+
title: z.string()
|
|
1116
|
+
})) }),
|
|
1117
|
+
default: z.array(z.string()).optional()
|
|
1118
|
+
});
|
|
1119
|
+
/**
|
|
1120
|
+
* Combined schema for multiple-selection enumeration
|
|
1121
|
+
*/
|
|
1122
|
+
const MultiSelectEnumSchemaSchema = z.union([UntitledMultiSelectEnumSchemaSchema, TitledMultiSelectEnumSchemaSchema]);
|
|
1123
|
+
/**
|
|
1124
|
+
* Primitive schema definition for enum fields.
|
|
1125
|
+
*/
|
|
1126
|
+
const EnumSchemaSchema = z.union([
|
|
1127
|
+
LegacyTitledEnumSchemaSchema,
|
|
1128
|
+
SingleSelectEnumSchemaSchema,
|
|
1129
|
+
MultiSelectEnumSchemaSchema
|
|
1130
|
+
]);
|
|
1131
|
+
/**
|
|
1132
|
+
* Union of all primitive schema definitions.
|
|
1133
|
+
*/
|
|
1134
|
+
const PrimitiveSchemaDefinitionSchema = z.union([
|
|
1135
|
+
EnumSchemaSchema,
|
|
1136
|
+
BooleanSchemaSchema,
|
|
1137
|
+
StringSchemaSchema,
|
|
1138
|
+
NumberSchemaSchema
|
|
1139
|
+
]);
|
|
1140
|
+
/**
|
|
1141
|
+
* Parameters for an `elicitation/create` request for form-based elicitation.
|
|
1142
|
+
*/
|
|
1143
|
+
const ElicitRequestFormParamsSchema = TaskAugmentedRequestParamsSchema.extend({
|
|
1144
|
+
mode: z.literal("form").optional(),
|
|
1145
|
+
message: z.string(),
|
|
1146
|
+
requestedSchema: z.object({
|
|
1147
|
+
type: z.literal("object"),
|
|
1148
|
+
properties: z.record(z.string(), PrimitiveSchemaDefinitionSchema),
|
|
1149
|
+
required: z.array(z.string()).optional()
|
|
1150
|
+
})
|
|
1151
|
+
});
|
|
1152
|
+
/**
|
|
1153
|
+
* Parameters for an `elicitation/create` request for URL-based elicitation.
|
|
1154
|
+
*/
|
|
1155
|
+
const ElicitRequestURLParamsSchema = TaskAugmentedRequestParamsSchema.extend({
|
|
1156
|
+
mode: z.literal("url"),
|
|
1157
|
+
message: z.string(),
|
|
1158
|
+
elicitationId: z.string(),
|
|
1159
|
+
url: z.string().url()
|
|
1160
|
+
});
|
|
1161
|
+
/**
|
|
1162
|
+
* The parameters for a request to elicit additional information from the user via the client.
|
|
1163
|
+
*/
|
|
1164
|
+
const ElicitRequestParamsSchema = z.union([ElicitRequestFormParamsSchema, ElicitRequestURLParamsSchema]);
|
|
1165
|
+
/**
|
|
1166
|
+
* A request from the server to elicit user input via the client.
|
|
1167
|
+
* The client should present the message and form fields to the user (form mode)
|
|
1168
|
+
* or navigate to a URL (URL mode).
|
|
1169
|
+
*/
|
|
1170
|
+
const ElicitRequestSchema = RequestSchema.extend({
|
|
1171
|
+
method: z.literal("elicitation/create"),
|
|
1172
|
+
params: ElicitRequestParamsSchema
|
|
1173
|
+
});
|
|
1174
|
+
/**
|
|
1175
|
+
* Parameters for a `notifications/elicitation/complete` notification.
|
|
1176
|
+
*
|
|
1177
|
+
* @category notifications/elicitation/complete
|
|
1178
|
+
*/
|
|
1179
|
+
const ElicitationCompleteNotificationParamsSchema = NotificationsParamsSchema.extend({ elicitationId: z.string() });
|
|
1180
|
+
/**
|
|
1181
|
+
* A notification from the server to the client, informing it of a completion of an out-of-band elicitation request.
|
|
1182
|
+
*
|
|
1183
|
+
* @category notifications/elicitation/complete
|
|
1184
|
+
*/
|
|
1185
|
+
const ElicitationCompleteNotificationSchema = NotificationSchema.extend({
|
|
1186
|
+
method: z.literal("notifications/elicitation/complete"),
|
|
1187
|
+
params: ElicitationCompleteNotificationParamsSchema
|
|
1188
|
+
});
|
|
1189
|
+
/**
|
|
1190
|
+
* The client's response to an elicitation/create request from the server.
|
|
1191
|
+
*/
|
|
1192
|
+
const ElicitResultSchema = ResultSchema.extend({
|
|
1193
|
+
action: z.enum([
|
|
1194
|
+
"accept",
|
|
1195
|
+
"decline",
|
|
1196
|
+
"cancel"
|
|
1197
|
+
]),
|
|
1198
|
+
content: z.preprocess((val) => val === null ? void 0 : val, z.record(z.string(), z.union([
|
|
1199
|
+
z.string(),
|
|
1200
|
+
z.number(),
|
|
1201
|
+
z.boolean(),
|
|
1202
|
+
z.array(z.string())
|
|
1203
|
+
])).optional())
|
|
1204
|
+
});
|
|
1205
|
+
/**
|
|
1206
|
+
* A reference to a resource or resource template definition.
|
|
1207
|
+
*/
|
|
1208
|
+
const ResourceTemplateReferenceSchema = z.object({
|
|
1209
|
+
type: z.literal("ref/resource"),
|
|
1210
|
+
uri: z.string()
|
|
1211
|
+
});
|
|
1212
|
+
/**
|
|
1213
|
+
* Identifies a prompt.
|
|
1214
|
+
*/
|
|
1215
|
+
const PromptReferenceSchema = z.object({
|
|
1216
|
+
type: z.literal("ref/prompt"),
|
|
1217
|
+
name: z.string()
|
|
1218
|
+
});
|
|
1219
|
+
/**
|
|
1220
|
+
* Parameters for a `completion/complete` request.
|
|
1221
|
+
*/
|
|
1222
|
+
const CompleteRequestParamsSchema = BaseRequestParamsSchema.extend({
|
|
1223
|
+
ref: z.union([PromptReferenceSchema, ResourceTemplateReferenceSchema]),
|
|
1224
|
+
argument: z.object({
|
|
1225
|
+
name: z.string(),
|
|
1226
|
+
value: z.string()
|
|
1227
|
+
}),
|
|
1228
|
+
context: z.object({ arguments: z.record(z.string(), z.string()).optional() }).optional()
|
|
1229
|
+
});
|
|
1230
|
+
/**
|
|
1231
|
+
* A request from the client to the server, to ask for completion options.
|
|
1232
|
+
*/
|
|
1233
|
+
const CompleteRequestSchema = RequestSchema.extend({
|
|
1234
|
+
method: z.literal("completion/complete"),
|
|
1235
|
+
params: CompleteRequestParamsSchema
|
|
1236
|
+
});
|
|
1237
|
+
function assertCompleteRequestPrompt(request) {
|
|
1238
|
+
if (request.params.ref.type !== "ref/prompt") throw new TypeError(`Expected CompleteRequestPrompt, but got ${request.params.ref.type}`);
|
|
1239
|
+
}
|
|
1240
|
+
function assertCompleteRequestResourceTemplate(request) {
|
|
1241
|
+
if (request.params.ref.type !== "ref/resource") throw new TypeError(`Expected CompleteRequestResourceTemplate, but got ${request.params.ref.type}`);
|
|
1242
|
+
}
|
|
1243
|
+
/**
|
|
1244
|
+
* The server's response to a completion/complete request
|
|
1245
|
+
*/
|
|
1246
|
+
const CompleteResultSchema = ResultSchema.extend({ completion: z.looseObject({
|
|
1247
|
+
values: z.array(z.string()).max(100),
|
|
1248
|
+
total: z.optional(z.number().int()),
|
|
1249
|
+
hasMore: z.optional(z.boolean())
|
|
1250
|
+
}) });
|
|
1251
|
+
/**
|
|
1252
|
+
* Represents a root directory or file that the server can operate on.
|
|
1253
|
+
*/
|
|
1254
|
+
const RootSchema = z.object({
|
|
1255
|
+
uri: z.string().startsWith("file://"),
|
|
1256
|
+
name: z.string().optional(),
|
|
1257
|
+
_meta: z.record(z.string(), z.unknown()).optional()
|
|
1258
|
+
});
|
|
1259
|
+
/**
|
|
1260
|
+
* Sent from the server to request a list of root URIs from the client.
|
|
1261
|
+
*/
|
|
1262
|
+
const ListRootsRequestSchema = RequestSchema.extend({
|
|
1263
|
+
method: z.literal("roots/list"),
|
|
1264
|
+
params: BaseRequestParamsSchema.optional()
|
|
1265
|
+
});
|
|
1266
|
+
/**
|
|
1267
|
+
* The client's response to a roots/list request from the server.
|
|
1268
|
+
*/
|
|
1269
|
+
const ListRootsResultSchema = ResultSchema.extend({ roots: z.array(RootSchema) });
|
|
1270
|
+
/**
|
|
1271
|
+
* A notification from the client to the server, informing it that the list of roots has changed.
|
|
1272
|
+
*/
|
|
1273
|
+
const RootsListChangedNotificationSchema = NotificationSchema.extend({
|
|
1274
|
+
method: z.literal("notifications/roots/list_changed"),
|
|
1275
|
+
params: NotificationsParamsSchema.optional()
|
|
1276
|
+
});
|
|
1277
|
+
const ClientRequestSchema = z.union([
|
|
1278
|
+
PingRequestSchema,
|
|
1279
|
+
InitializeRequestSchema,
|
|
1280
|
+
CompleteRequestSchema,
|
|
1281
|
+
SetLevelRequestSchema,
|
|
1282
|
+
GetPromptRequestSchema,
|
|
1283
|
+
ListPromptsRequestSchema,
|
|
1284
|
+
ListResourcesRequestSchema,
|
|
1285
|
+
ListResourceTemplatesRequestSchema,
|
|
1286
|
+
ReadResourceRequestSchema,
|
|
1287
|
+
SubscribeRequestSchema,
|
|
1288
|
+
UnsubscribeRequestSchema,
|
|
1289
|
+
CallToolRequestSchema,
|
|
1290
|
+
ListToolsRequestSchema,
|
|
1291
|
+
GetTaskRequestSchema,
|
|
1292
|
+
GetTaskPayloadRequestSchema,
|
|
1293
|
+
ListTasksRequestSchema,
|
|
1294
|
+
CancelTaskRequestSchema
|
|
1295
|
+
]);
|
|
1296
|
+
const ClientNotificationSchema = z.union([
|
|
1297
|
+
CancelledNotificationSchema,
|
|
1298
|
+
ProgressNotificationSchema,
|
|
1299
|
+
InitializedNotificationSchema,
|
|
1300
|
+
RootsListChangedNotificationSchema,
|
|
1301
|
+
TaskStatusNotificationSchema
|
|
1302
|
+
]);
|
|
1303
|
+
const ClientResultSchema = z.union([
|
|
1304
|
+
EmptyResultSchema,
|
|
1305
|
+
CreateMessageResultSchema,
|
|
1306
|
+
CreateMessageResultWithToolsSchema,
|
|
1307
|
+
ElicitResultSchema,
|
|
1308
|
+
ListRootsResultSchema,
|
|
1309
|
+
GetTaskResultSchema,
|
|
1310
|
+
ListTasksResultSchema,
|
|
1311
|
+
CreateTaskResultSchema
|
|
1312
|
+
]);
|
|
1313
|
+
const ServerRequestSchema = z.union([
|
|
1314
|
+
PingRequestSchema,
|
|
1315
|
+
CreateMessageRequestSchema,
|
|
1316
|
+
ElicitRequestSchema,
|
|
1317
|
+
ListRootsRequestSchema,
|
|
1318
|
+
GetTaskRequestSchema,
|
|
1319
|
+
GetTaskPayloadRequestSchema,
|
|
1320
|
+
ListTasksRequestSchema,
|
|
1321
|
+
CancelTaskRequestSchema
|
|
1322
|
+
]);
|
|
1323
|
+
const ServerNotificationSchema = z.union([
|
|
1324
|
+
CancelledNotificationSchema,
|
|
1325
|
+
ProgressNotificationSchema,
|
|
1326
|
+
LoggingMessageNotificationSchema,
|
|
1327
|
+
ResourceUpdatedNotificationSchema,
|
|
1328
|
+
ResourceListChangedNotificationSchema,
|
|
1329
|
+
ToolListChangedNotificationSchema,
|
|
1330
|
+
PromptListChangedNotificationSchema,
|
|
1331
|
+
TaskStatusNotificationSchema,
|
|
1332
|
+
ElicitationCompleteNotificationSchema
|
|
1333
|
+
]);
|
|
1334
|
+
const ServerResultSchema = z.union([
|
|
1335
|
+
EmptyResultSchema,
|
|
1336
|
+
InitializeResultSchema,
|
|
1337
|
+
CompleteResultSchema,
|
|
1338
|
+
GetPromptResultSchema,
|
|
1339
|
+
ListPromptsResultSchema,
|
|
1340
|
+
ListResourcesResultSchema,
|
|
1341
|
+
ListResourceTemplatesResultSchema,
|
|
1342
|
+
ReadResourceResultSchema,
|
|
1343
|
+
CallToolResultSchema,
|
|
1344
|
+
ListToolsResultSchema,
|
|
1345
|
+
GetTaskResultSchema,
|
|
1346
|
+
ListTasksResultSchema,
|
|
1347
|
+
CreateTaskResultSchema
|
|
1348
|
+
]);
|
|
1349
|
+
var McpError = class McpError extends Error {
|
|
1350
|
+
constructor(code, message, data) {
|
|
1351
|
+
super(`MCP error ${code}: ${message}`);
|
|
1352
|
+
this.code = code;
|
|
1353
|
+
this.data = data;
|
|
1354
|
+
this.name = "McpError";
|
|
1355
|
+
}
|
|
1356
|
+
/**
|
|
1357
|
+
* Factory method to create the appropriate error type based on the error code and data
|
|
1358
|
+
*/
|
|
1359
|
+
static fromError(code, message, data) {
|
|
1360
|
+
if (code === ErrorCode.UrlElicitationRequired && data) {
|
|
1361
|
+
const errorData = data;
|
|
1362
|
+
if (errorData.elicitations) return new UrlElicitationRequiredError(errorData.elicitations, message);
|
|
1363
|
+
}
|
|
1364
|
+
return new McpError(code, message, data);
|
|
1365
|
+
}
|
|
1366
|
+
};
|
|
1367
|
+
/**
|
|
1368
|
+
* Specialized error type when a tool requires a URL mode elicitation.
|
|
1369
|
+
* This makes it nicer for the client to handle since there is specific data to work with instead of just a code to check against.
|
|
1370
|
+
*/
|
|
1371
|
+
var UrlElicitationRequiredError = class extends McpError {
|
|
1372
|
+
constructor(elicitations, message = `URL elicitation${elicitations.length > 1 ? "s" : ""} required`) {
|
|
1373
|
+
super(ErrorCode.UrlElicitationRequired, message, { elicitations });
|
|
1374
|
+
}
|
|
1375
|
+
get elicitations() {
|
|
1376
|
+
return this.data?.elicitations ?? [];
|
|
1377
|
+
}
|
|
1378
|
+
};
|
|
1379
|
+
|
|
1380
|
+
//#endregion
|
|
1381
|
+
//#region ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.26.0_@cfworker+json-schema@4.1.1_zod@4.3.5/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/interfaces.js
|
|
1382
|
+
/**
|
|
1383
|
+
* Experimental task interfaces for MCP SDK.
|
|
1384
|
+
* WARNING: These APIs are experimental and may change without notice.
|
|
1385
|
+
*/
|
|
1386
|
+
/**
|
|
1387
|
+
* Checks if a task status represents a terminal state.
|
|
1388
|
+
* Terminal states are those where the task has finished and will not change.
|
|
1389
|
+
*
|
|
1390
|
+
* @param status - The task status to check
|
|
1391
|
+
* @returns True if the status is terminal (completed, failed, or cancelled)
|
|
1392
|
+
* @experimental
|
|
1393
|
+
*/
|
|
1394
|
+
function isTerminal(status) {
|
|
1395
|
+
return status === "completed" || status === "failed" || status === "cancelled";
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
//#endregion
|
|
1399
|
+
//#region ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.26.0_@cfworker+json-schema@4.1.1_zod@4.3.5/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-json-schema-compat.js
|
|
1400
|
+
function mapMiniTarget(t) {
|
|
1401
|
+
if (!t) return "draft-7";
|
|
1402
|
+
if (t === "jsonSchema7" || t === "draft-7") return "draft-7";
|
|
1403
|
+
if (t === "jsonSchema2019-09" || t === "draft-2020-12") return "draft-2020-12";
|
|
1404
|
+
return "draft-7";
|
|
1405
|
+
}
|
|
1406
|
+
function toJsonSchemaCompat(schema, opts) {
|
|
1407
|
+
if (isZ4Schema(schema)) return z4mini.toJSONSchema(schema, {
|
|
1408
|
+
target: mapMiniTarget(opts?.target),
|
|
1409
|
+
io: opts?.pipeStrategy ?? "input"
|
|
1410
|
+
});
|
|
1411
|
+
return zodToJsonSchema(schema, {
|
|
1412
|
+
strictUnions: opts?.strictUnions ?? true,
|
|
1413
|
+
pipeStrategy: opts?.pipeStrategy ?? "input"
|
|
1414
|
+
});
|
|
1415
|
+
}
|
|
1416
|
+
function getMethodLiteral(schema) {
|
|
1417
|
+
const methodSchema = getObjectShape(schema)?.method;
|
|
1418
|
+
if (!methodSchema) throw new Error("Schema is missing a method literal");
|
|
1419
|
+
const value = getLiteralValue(methodSchema);
|
|
1420
|
+
if (typeof value !== "string") throw new Error("Schema method literal must be a string");
|
|
1421
|
+
return value;
|
|
1422
|
+
}
|
|
1423
|
+
function parseWithCompat(schema, data) {
|
|
1424
|
+
const result = safeParse(schema, data);
|
|
1425
|
+
if (!result.success) throw result.error;
|
|
1426
|
+
return result.data;
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
//#endregion
|
|
1430
|
+
//#region ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.26.0_@cfworker+json-schema@4.1.1_zod@4.3.5/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/protocol.js
|
|
1431
|
+
/**
|
|
1432
|
+
* The default request timeout, in miliseconds.
|
|
1433
|
+
*/
|
|
1434
|
+
const DEFAULT_REQUEST_TIMEOUT_MSEC = 6e4;
|
|
1435
|
+
/**
|
|
1436
|
+
* Implements MCP protocol framing on top of a pluggable transport, including
|
|
1437
|
+
* features like request/response linking, notifications, and progress.
|
|
1438
|
+
*/
|
|
1439
|
+
var Protocol = class {
|
|
1440
|
+
constructor(_options) {
|
|
1441
|
+
this._options = _options;
|
|
1442
|
+
this._requestMessageId = 0;
|
|
1443
|
+
this._requestHandlers = /* @__PURE__ */ new Map();
|
|
1444
|
+
this._requestHandlerAbortControllers = /* @__PURE__ */ new Map();
|
|
1445
|
+
this._notificationHandlers = /* @__PURE__ */ new Map();
|
|
1446
|
+
this._responseHandlers = /* @__PURE__ */ new Map();
|
|
1447
|
+
this._progressHandlers = /* @__PURE__ */ new Map();
|
|
1448
|
+
this._timeoutInfo = /* @__PURE__ */ new Map();
|
|
1449
|
+
this._pendingDebouncedNotifications = /* @__PURE__ */ new Set();
|
|
1450
|
+
this._taskProgressTokens = /* @__PURE__ */ new Map();
|
|
1451
|
+
this._requestResolvers = /* @__PURE__ */ new Map();
|
|
1452
|
+
this.setNotificationHandler(CancelledNotificationSchema, (notification) => {
|
|
1453
|
+
this._oncancel(notification);
|
|
1454
|
+
});
|
|
1455
|
+
this.setNotificationHandler(ProgressNotificationSchema, (notification) => {
|
|
1456
|
+
this._onprogress(notification);
|
|
1457
|
+
});
|
|
1458
|
+
this.setRequestHandler(PingRequestSchema, (_request) => ({}));
|
|
1459
|
+
this._taskStore = _options?.taskStore;
|
|
1460
|
+
this._taskMessageQueue = _options?.taskMessageQueue;
|
|
1461
|
+
if (this._taskStore) {
|
|
1462
|
+
this.setRequestHandler(GetTaskRequestSchema, async (request, extra) => {
|
|
1463
|
+
const task = await this._taskStore.getTask(request.params.taskId, extra.sessionId);
|
|
1464
|
+
if (!task) throw new McpError(ErrorCode.InvalidParams, "Failed to retrieve task: Task not found");
|
|
1465
|
+
return { ...task };
|
|
1466
|
+
});
|
|
1467
|
+
this.setRequestHandler(GetTaskPayloadRequestSchema, async (request, extra) => {
|
|
1468
|
+
const handleTaskResult = async () => {
|
|
1469
|
+
const taskId = request.params.taskId;
|
|
1470
|
+
if (this._taskMessageQueue) {
|
|
1471
|
+
let queuedMessage;
|
|
1472
|
+
while (queuedMessage = await this._taskMessageQueue.dequeue(taskId, extra.sessionId)) {
|
|
1473
|
+
if (queuedMessage.type === "response" || queuedMessage.type === "error") {
|
|
1474
|
+
const message = queuedMessage.message;
|
|
1475
|
+
const requestId = message.id;
|
|
1476
|
+
const resolver = this._requestResolvers.get(requestId);
|
|
1477
|
+
if (resolver) {
|
|
1478
|
+
this._requestResolvers.delete(requestId);
|
|
1479
|
+
if (queuedMessage.type === "response") resolver(message);
|
|
1480
|
+
else {
|
|
1481
|
+
const errorMessage = message;
|
|
1482
|
+
resolver(new McpError(errorMessage.error.code, errorMessage.error.message, errorMessage.error.data));
|
|
1483
|
+
}
|
|
1484
|
+
} else {
|
|
1485
|
+
const messageType = queuedMessage.type === "response" ? "Response" : "Error";
|
|
1486
|
+
this._onerror(/* @__PURE__ */ new Error(`${messageType} handler missing for request ${requestId}`));
|
|
1487
|
+
}
|
|
1488
|
+
continue;
|
|
1489
|
+
}
|
|
1490
|
+
await this._transport?.send(queuedMessage.message, { relatedRequestId: extra.requestId });
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
const task = await this._taskStore.getTask(taskId, extra.sessionId);
|
|
1494
|
+
if (!task) throw new McpError(ErrorCode.InvalidParams, `Task not found: ${taskId}`);
|
|
1495
|
+
if (!isTerminal(task.status)) {
|
|
1496
|
+
await this._waitForTaskUpdate(taskId, extra.signal);
|
|
1497
|
+
return await handleTaskResult();
|
|
1498
|
+
}
|
|
1499
|
+
if (isTerminal(task.status)) {
|
|
1500
|
+
const result = await this._taskStore.getTaskResult(taskId, extra.sessionId);
|
|
1501
|
+
this._clearTaskQueue(taskId);
|
|
1502
|
+
return {
|
|
1503
|
+
...result,
|
|
1504
|
+
_meta: {
|
|
1505
|
+
...result._meta,
|
|
1506
|
+
[RELATED_TASK_META_KEY]: { taskId }
|
|
1507
|
+
}
|
|
1508
|
+
};
|
|
1509
|
+
}
|
|
1510
|
+
return await handleTaskResult();
|
|
1511
|
+
};
|
|
1512
|
+
return await handleTaskResult();
|
|
1513
|
+
});
|
|
1514
|
+
this.setRequestHandler(ListTasksRequestSchema, async (request, extra) => {
|
|
1515
|
+
try {
|
|
1516
|
+
const { tasks, nextCursor } = await this._taskStore.listTasks(request.params?.cursor, extra.sessionId);
|
|
1517
|
+
return {
|
|
1518
|
+
tasks,
|
|
1519
|
+
nextCursor,
|
|
1520
|
+
_meta: {}
|
|
1521
|
+
};
|
|
1522
|
+
} catch (error) {
|
|
1523
|
+
throw new McpError(ErrorCode.InvalidParams, `Failed to list tasks: ${error instanceof Error ? error.message : String(error)}`);
|
|
1524
|
+
}
|
|
1525
|
+
});
|
|
1526
|
+
this.setRequestHandler(CancelTaskRequestSchema, async (request, extra) => {
|
|
1527
|
+
try {
|
|
1528
|
+
const task = await this._taskStore.getTask(request.params.taskId, extra.sessionId);
|
|
1529
|
+
if (!task) throw new McpError(ErrorCode.InvalidParams, `Task not found: ${request.params.taskId}`);
|
|
1530
|
+
if (isTerminal(task.status)) throw new McpError(ErrorCode.InvalidParams, `Cannot cancel task in terminal status: ${task.status}`);
|
|
1531
|
+
await this._taskStore.updateTaskStatus(request.params.taskId, "cancelled", "Client cancelled task execution.", extra.sessionId);
|
|
1532
|
+
this._clearTaskQueue(request.params.taskId);
|
|
1533
|
+
const cancelledTask = await this._taskStore.getTask(request.params.taskId, extra.sessionId);
|
|
1534
|
+
if (!cancelledTask) throw new McpError(ErrorCode.InvalidParams, `Task not found after cancellation: ${request.params.taskId}`);
|
|
1535
|
+
return {
|
|
1536
|
+
_meta: {},
|
|
1537
|
+
...cancelledTask
|
|
1538
|
+
};
|
|
1539
|
+
} catch (error) {
|
|
1540
|
+
if (error instanceof McpError) throw error;
|
|
1541
|
+
throw new McpError(ErrorCode.InvalidRequest, `Failed to cancel task: ${error instanceof Error ? error.message : String(error)}`);
|
|
1542
|
+
}
|
|
1543
|
+
});
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
async _oncancel(notification) {
|
|
1547
|
+
if (!notification.params.requestId) return;
|
|
1548
|
+
this._requestHandlerAbortControllers.get(notification.params.requestId)?.abort(notification.params.reason);
|
|
1549
|
+
}
|
|
1550
|
+
_setupTimeout(messageId, timeout, maxTotalTimeout, onTimeout, resetTimeoutOnProgress = false) {
|
|
1551
|
+
this._timeoutInfo.set(messageId, {
|
|
1552
|
+
timeoutId: setTimeout(onTimeout, timeout),
|
|
1553
|
+
startTime: Date.now(),
|
|
1554
|
+
timeout,
|
|
1555
|
+
maxTotalTimeout,
|
|
1556
|
+
resetTimeoutOnProgress,
|
|
1557
|
+
onTimeout
|
|
1558
|
+
});
|
|
1559
|
+
}
|
|
1560
|
+
_resetTimeout(messageId) {
|
|
1561
|
+
const info = this._timeoutInfo.get(messageId);
|
|
1562
|
+
if (!info) return false;
|
|
1563
|
+
const totalElapsed = Date.now() - info.startTime;
|
|
1564
|
+
if (info.maxTotalTimeout && totalElapsed >= info.maxTotalTimeout) {
|
|
1565
|
+
this._timeoutInfo.delete(messageId);
|
|
1566
|
+
throw McpError.fromError(ErrorCode.RequestTimeout, "Maximum total timeout exceeded", {
|
|
1567
|
+
maxTotalTimeout: info.maxTotalTimeout,
|
|
1568
|
+
totalElapsed
|
|
1569
|
+
});
|
|
1570
|
+
}
|
|
1571
|
+
clearTimeout(info.timeoutId);
|
|
1572
|
+
info.timeoutId = setTimeout(info.onTimeout, info.timeout);
|
|
1573
|
+
return true;
|
|
1574
|
+
}
|
|
1575
|
+
_cleanupTimeout(messageId) {
|
|
1576
|
+
const info = this._timeoutInfo.get(messageId);
|
|
1577
|
+
if (info) {
|
|
1578
|
+
clearTimeout(info.timeoutId);
|
|
1579
|
+
this._timeoutInfo.delete(messageId);
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1582
|
+
/**
|
|
1583
|
+
* Attaches to the given transport, starts it, and starts listening for messages.
|
|
1584
|
+
*
|
|
1585
|
+
* The Protocol object assumes ownership of the Transport, replacing any callbacks that have already been set, and expects that it is the only user of the Transport instance going forward.
|
|
1586
|
+
*/
|
|
1587
|
+
async connect(transport) {
|
|
1588
|
+
if (this._transport) throw new Error("Already connected to a transport. Call close() before connecting to a new transport, or use a separate Protocol instance per connection.");
|
|
1589
|
+
this._transport = transport;
|
|
1590
|
+
const _onclose = this.transport?.onclose;
|
|
1591
|
+
this._transport.onclose = () => {
|
|
1592
|
+
_onclose?.();
|
|
1593
|
+
this._onclose();
|
|
1594
|
+
};
|
|
1595
|
+
const _onerror = this.transport?.onerror;
|
|
1596
|
+
this._transport.onerror = (error) => {
|
|
1597
|
+
_onerror?.(error);
|
|
1598
|
+
this._onerror(error);
|
|
1599
|
+
};
|
|
1600
|
+
const _onmessage = this._transport?.onmessage;
|
|
1601
|
+
this._transport.onmessage = (message, extra) => {
|
|
1602
|
+
_onmessage?.(message, extra);
|
|
1603
|
+
if (isJSONRPCResultResponse(message) || isJSONRPCErrorResponse(message)) this._onresponse(message);
|
|
1604
|
+
else if (isJSONRPCRequest(message)) this._onrequest(message, extra);
|
|
1605
|
+
else if (isJSONRPCNotification(message)) this._onnotification(message);
|
|
1606
|
+
else this._onerror(/* @__PURE__ */ new Error(`Unknown message type: ${JSON.stringify(message)}`));
|
|
1607
|
+
};
|
|
1608
|
+
await this._transport.start();
|
|
1609
|
+
}
|
|
1610
|
+
_onclose() {
|
|
1611
|
+
const responseHandlers = this._responseHandlers;
|
|
1612
|
+
this._responseHandlers = /* @__PURE__ */ new Map();
|
|
1613
|
+
this._progressHandlers.clear();
|
|
1614
|
+
this._taskProgressTokens.clear();
|
|
1615
|
+
this._pendingDebouncedNotifications.clear();
|
|
1616
|
+
for (const controller of this._requestHandlerAbortControllers.values()) controller.abort();
|
|
1617
|
+
this._requestHandlerAbortControllers.clear();
|
|
1618
|
+
const error = McpError.fromError(ErrorCode.ConnectionClosed, "Connection closed");
|
|
1619
|
+
this._transport = void 0;
|
|
1620
|
+
this.onclose?.();
|
|
1621
|
+
for (const handler of responseHandlers.values()) handler(error);
|
|
1622
|
+
}
|
|
1623
|
+
_onerror(error) {
|
|
1624
|
+
this.onerror?.(error);
|
|
1625
|
+
}
|
|
1626
|
+
_onnotification(notification) {
|
|
1627
|
+
const handler = this._notificationHandlers.get(notification.method) ?? this.fallbackNotificationHandler;
|
|
1628
|
+
if (handler === void 0) return;
|
|
1629
|
+
Promise.resolve().then(() => handler(notification)).catch((error) => this._onerror(/* @__PURE__ */ new Error(`Uncaught error in notification handler: ${error}`)));
|
|
1630
|
+
}
|
|
1631
|
+
_onrequest(request, extra) {
|
|
1632
|
+
const handler = this._requestHandlers.get(request.method) ?? this.fallbackRequestHandler;
|
|
1633
|
+
const capturedTransport = this._transport;
|
|
1634
|
+
const relatedTaskId = request.params?._meta?.[RELATED_TASK_META_KEY]?.taskId;
|
|
1635
|
+
if (handler === void 0) {
|
|
1636
|
+
const errorResponse = {
|
|
1637
|
+
jsonrpc: "2.0",
|
|
1638
|
+
id: request.id,
|
|
1639
|
+
error: {
|
|
1640
|
+
code: ErrorCode.MethodNotFound,
|
|
1641
|
+
message: "Method not found"
|
|
1642
|
+
}
|
|
1643
|
+
};
|
|
1644
|
+
if (relatedTaskId && this._taskMessageQueue) this._enqueueTaskMessage(relatedTaskId, {
|
|
1645
|
+
type: "error",
|
|
1646
|
+
message: errorResponse,
|
|
1647
|
+
timestamp: Date.now()
|
|
1648
|
+
}, capturedTransport?.sessionId).catch((error) => this._onerror(/* @__PURE__ */ new Error(`Failed to enqueue error response: ${error}`)));
|
|
1649
|
+
else capturedTransport?.send(errorResponse).catch((error) => this._onerror(/* @__PURE__ */ new Error(`Failed to send an error response: ${error}`)));
|
|
1650
|
+
return;
|
|
1651
|
+
}
|
|
1652
|
+
const abortController = new AbortController();
|
|
1653
|
+
this._requestHandlerAbortControllers.set(request.id, abortController);
|
|
1654
|
+
const taskCreationParams = isTaskAugmentedRequestParams(request.params) ? request.params.task : void 0;
|
|
1655
|
+
const taskStore = this._taskStore ? this.requestTaskStore(request, capturedTransport?.sessionId) : void 0;
|
|
1656
|
+
const fullExtra = {
|
|
1657
|
+
signal: abortController.signal,
|
|
1658
|
+
sessionId: capturedTransport?.sessionId,
|
|
1659
|
+
_meta: request.params?._meta,
|
|
1660
|
+
sendNotification: async (notification) => {
|
|
1661
|
+
if (abortController.signal.aborted) return;
|
|
1662
|
+
const notificationOptions = { relatedRequestId: request.id };
|
|
1663
|
+
if (relatedTaskId) notificationOptions.relatedTask = { taskId: relatedTaskId };
|
|
1664
|
+
await this.notification(notification, notificationOptions);
|
|
1665
|
+
},
|
|
1666
|
+
sendRequest: async (r, resultSchema, options) => {
|
|
1667
|
+
if (abortController.signal.aborted) throw new McpError(ErrorCode.ConnectionClosed, "Request was cancelled");
|
|
1668
|
+
const requestOptions = {
|
|
1669
|
+
...options,
|
|
1670
|
+
relatedRequestId: request.id
|
|
1671
|
+
};
|
|
1672
|
+
if (relatedTaskId && !requestOptions.relatedTask) requestOptions.relatedTask = { taskId: relatedTaskId };
|
|
1673
|
+
const effectiveTaskId = requestOptions.relatedTask?.taskId ?? relatedTaskId;
|
|
1674
|
+
if (effectiveTaskId && taskStore) await taskStore.updateTaskStatus(effectiveTaskId, "input_required");
|
|
1675
|
+
return await this.request(r, resultSchema, requestOptions);
|
|
1676
|
+
},
|
|
1677
|
+
authInfo: extra?.authInfo,
|
|
1678
|
+
requestId: request.id,
|
|
1679
|
+
requestInfo: extra?.requestInfo,
|
|
1680
|
+
taskId: relatedTaskId,
|
|
1681
|
+
taskStore,
|
|
1682
|
+
taskRequestedTtl: taskCreationParams?.ttl,
|
|
1683
|
+
closeSSEStream: extra?.closeSSEStream,
|
|
1684
|
+
closeStandaloneSSEStream: extra?.closeStandaloneSSEStream
|
|
1685
|
+
};
|
|
1686
|
+
Promise.resolve().then(() => {
|
|
1687
|
+
if (taskCreationParams) this.assertTaskHandlerCapability(request.method);
|
|
1688
|
+
}).then(() => handler(request, fullExtra)).then(async (result) => {
|
|
1689
|
+
if (abortController.signal.aborted) return;
|
|
1690
|
+
const response = {
|
|
1691
|
+
result,
|
|
1692
|
+
jsonrpc: "2.0",
|
|
1693
|
+
id: request.id
|
|
1694
|
+
};
|
|
1695
|
+
if (relatedTaskId && this._taskMessageQueue) await this._enqueueTaskMessage(relatedTaskId, {
|
|
1696
|
+
type: "response",
|
|
1697
|
+
message: response,
|
|
1698
|
+
timestamp: Date.now()
|
|
1699
|
+
}, capturedTransport?.sessionId);
|
|
1700
|
+
else await capturedTransport?.send(response);
|
|
1701
|
+
}, async (error) => {
|
|
1702
|
+
if (abortController.signal.aborted) return;
|
|
1703
|
+
const errorResponse = {
|
|
1704
|
+
jsonrpc: "2.0",
|
|
1705
|
+
id: request.id,
|
|
1706
|
+
error: {
|
|
1707
|
+
code: Number.isSafeInteger(error["code"]) ? error["code"] : ErrorCode.InternalError,
|
|
1708
|
+
message: error.message ?? "Internal error",
|
|
1709
|
+
...error["data"] !== void 0 && { data: error["data"] }
|
|
1710
|
+
}
|
|
1711
|
+
};
|
|
1712
|
+
if (relatedTaskId && this._taskMessageQueue) await this._enqueueTaskMessage(relatedTaskId, {
|
|
1713
|
+
type: "error",
|
|
1714
|
+
message: errorResponse,
|
|
1715
|
+
timestamp: Date.now()
|
|
1716
|
+
}, capturedTransport?.sessionId);
|
|
1717
|
+
else await capturedTransport?.send(errorResponse);
|
|
1718
|
+
}).catch((error) => this._onerror(/* @__PURE__ */ new Error(`Failed to send response: ${error}`))).finally(() => {
|
|
1719
|
+
this._requestHandlerAbortControllers.delete(request.id);
|
|
1720
|
+
});
|
|
1721
|
+
}
|
|
1722
|
+
_onprogress(notification) {
|
|
1723
|
+
const { progressToken,...params } = notification.params;
|
|
1724
|
+
const messageId = Number(progressToken);
|
|
1725
|
+
const handler = this._progressHandlers.get(messageId);
|
|
1726
|
+
if (!handler) {
|
|
1727
|
+
this._onerror(/* @__PURE__ */ new Error(`Received a progress notification for an unknown token: ${JSON.stringify(notification)}`));
|
|
1728
|
+
return;
|
|
1729
|
+
}
|
|
1730
|
+
const responseHandler = this._responseHandlers.get(messageId);
|
|
1731
|
+
const timeoutInfo = this._timeoutInfo.get(messageId);
|
|
1732
|
+
if (timeoutInfo && responseHandler && timeoutInfo.resetTimeoutOnProgress) try {
|
|
1733
|
+
this._resetTimeout(messageId);
|
|
1734
|
+
} catch (error) {
|
|
1735
|
+
this._responseHandlers.delete(messageId);
|
|
1736
|
+
this._progressHandlers.delete(messageId);
|
|
1737
|
+
this._cleanupTimeout(messageId);
|
|
1738
|
+
responseHandler(error);
|
|
1739
|
+
return;
|
|
1740
|
+
}
|
|
1741
|
+
handler(params);
|
|
1742
|
+
}
|
|
1743
|
+
_onresponse(response) {
|
|
1744
|
+
const messageId = Number(response.id);
|
|
1745
|
+
const resolver = this._requestResolvers.get(messageId);
|
|
1746
|
+
if (resolver) {
|
|
1747
|
+
this._requestResolvers.delete(messageId);
|
|
1748
|
+
if (isJSONRPCResultResponse(response)) resolver(response);
|
|
1749
|
+
else resolver(new McpError(response.error.code, response.error.message, response.error.data));
|
|
1750
|
+
return;
|
|
1751
|
+
}
|
|
1752
|
+
const handler = this._responseHandlers.get(messageId);
|
|
1753
|
+
if (handler === void 0) {
|
|
1754
|
+
this._onerror(/* @__PURE__ */ new Error(`Received a response for an unknown message ID: ${JSON.stringify(response)}`));
|
|
1755
|
+
return;
|
|
1756
|
+
}
|
|
1757
|
+
this._responseHandlers.delete(messageId);
|
|
1758
|
+
this._cleanupTimeout(messageId);
|
|
1759
|
+
let isTaskResponse = false;
|
|
1760
|
+
if (isJSONRPCResultResponse(response) && response.result && typeof response.result === "object") {
|
|
1761
|
+
const result = response.result;
|
|
1762
|
+
if (result.task && typeof result.task === "object") {
|
|
1763
|
+
const task = result.task;
|
|
1764
|
+
if (typeof task.taskId === "string") {
|
|
1765
|
+
isTaskResponse = true;
|
|
1766
|
+
this._taskProgressTokens.set(task.taskId, messageId);
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1769
|
+
}
|
|
1770
|
+
if (!isTaskResponse) this._progressHandlers.delete(messageId);
|
|
1771
|
+
if (isJSONRPCResultResponse(response)) handler(response);
|
|
1772
|
+
else handler(McpError.fromError(response.error.code, response.error.message, response.error.data));
|
|
1773
|
+
}
|
|
1774
|
+
get transport() {
|
|
1775
|
+
return this._transport;
|
|
1776
|
+
}
|
|
1777
|
+
/**
|
|
1778
|
+
* Closes the connection.
|
|
1779
|
+
*/
|
|
1780
|
+
async close() {
|
|
1781
|
+
await this._transport?.close();
|
|
1782
|
+
}
|
|
1783
|
+
/**
|
|
1784
|
+
* Sends a request and returns an AsyncGenerator that yields response messages.
|
|
1785
|
+
* The generator is guaranteed to end with either a 'result' or 'error' message.
|
|
1786
|
+
*
|
|
1787
|
+
* @example
|
|
1788
|
+
* ```typescript
|
|
1789
|
+
* const stream = protocol.requestStream(request, resultSchema, options);
|
|
1790
|
+
* for await (const message of stream) {
|
|
1791
|
+
* switch (message.type) {
|
|
1792
|
+
* case 'taskCreated':
|
|
1793
|
+
* console.log('Task created:', message.task.taskId);
|
|
1794
|
+
* break;
|
|
1795
|
+
* case 'taskStatus':
|
|
1796
|
+
* console.log('Task status:', message.task.status);
|
|
1797
|
+
* break;
|
|
1798
|
+
* case 'result':
|
|
1799
|
+
* console.log('Final result:', message.result);
|
|
1800
|
+
* break;
|
|
1801
|
+
* case 'error':
|
|
1802
|
+
* console.error('Error:', message.error);
|
|
1803
|
+
* break;
|
|
1804
|
+
* }
|
|
1805
|
+
* }
|
|
1806
|
+
* ```
|
|
1807
|
+
*
|
|
1808
|
+
* @experimental Use `client.experimental.tasks.requestStream()` to access this method.
|
|
1809
|
+
*/
|
|
1810
|
+
async *requestStream(request, resultSchema, options) {
|
|
1811
|
+
const { task } = options ?? {};
|
|
1812
|
+
if (!task) {
|
|
1813
|
+
try {
|
|
1814
|
+
yield {
|
|
1815
|
+
type: "result",
|
|
1816
|
+
result: await this.request(request, resultSchema, options)
|
|
1817
|
+
};
|
|
1818
|
+
} catch (error) {
|
|
1819
|
+
yield {
|
|
1820
|
+
type: "error",
|
|
1821
|
+
error: error instanceof McpError ? error : new McpError(ErrorCode.InternalError, String(error))
|
|
1822
|
+
};
|
|
1823
|
+
}
|
|
1824
|
+
return;
|
|
1825
|
+
}
|
|
1826
|
+
let taskId;
|
|
1827
|
+
try {
|
|
1828
|
+
const createResult = await this.request(request, CreateTaskResultSchema, options);
|
|
1829
|
+
if (createResult.task) {
|
|
1830
|
+
taskId = createResult.task.taskId;
|
|
1831
|
+
yield {
|
|
1832
|
+
type: "taskCreated",
|
|
1833
|
+
task: createResult.task
|
|
1834
|
+
};
|
|
1835
|
+
} else throw new McpError(ErrorCode.InternalError, "Task creation did not return a task");
|
|
1836
|
+
while (true) {
|
|
1837
|
+
const task$1 = await this.getTask({ taskId }, options);
|
|
1838
|
+
yield {
|
|
1839
|
+
type: "taskStatus",
|
|
1840
|
+
task: task$1
|
|
1841
|
+
};
|
|
1842
|
+
if (isTerminal(task$1.status)) {
|
|
1843
|
+
if (task$1.status === "completed") yield {
|
|
1844
|
+
type: "result",
|
|
1845
|
+
result: await this.getTaskResult({ taskId }, resultSchema, options)
|
|
1846
|
+
};
|
|
1847
|
+
else if (task$1.status === "failed") yield {
|
|
1848
|
+
type: "error",
|
|
1849
|
+
error: new McpError(ErrorCode.InternalError, `Task ${taskId} failed`)
|
|
1850
|
+
};
|
|
1851
|
+
else if (task$1.status === "cancelled") yield {
|
|
1852
|
+
type: "error",
|
|
1853
|
+
error: new McpError(ErrorCode.InternalError, `Task ${taskId} was cancelled`)
|
|
1854
|
+
};
|
|
1855
|
+
return;
|
|
1856
|
+
}
|
|
1857
|
+
if (task$1.status === "input_required") {
|
|
1858
|
+
yield {
|
|
1859
|
+
type: "result",
|
|
1860
|
+
result: await this.getTaskResult({ taskId }, resultSchema, options)
|
|
1861
|
+
};
|
|
1862
|
+
return;
|
|
1863
|
+
}
|
|
1864
|
+
const pollInterval = task$1.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
|
|
1865
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
1866
|
+
options?.signal?.throwIfAborted();
|
|
1867
|
+
}
|
|
1868
|
+
} catch (error) {
|
|
1869
|
+
yield {
|
|
1870
|
+
type: "error",
|
|
1871
|
+
error: error instanceof McpError ? error : new McpError(ErrorCode.InternalError, String(error))
|
|
1872
|
+
};
|
|
1873
|
+
}
|
|
1874
|
+
}
|
|
1875
|
+
/**
|
|
1876
|
+
* Sends a request and waits for a response.
|
|
1877
|
+
*
|
|
1878
|
+
* Do not use this method to emit notifications! Use notification() instead.
|
|
1879
|
+
*/
|
|
1880
|
+
request(request, resultSchema, options) {
|
|
1881
|
+
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
1882
|
+
return new Promise((resolve, reject) => {
|
|
1883
|
+
const earlyReject = (error) => {
|
|
1884
|
+
reject(error);
|
|
1885
|
+
};
|
|
1886
|
+
if (!this._transport) {
|
|
1887
|
+
earlyReject(/* @__PURE__ */ new Error("Not connected"));
|
|
1888
|
+
return;
|
|
1889
|
+
}
|
|
1890
|
+
if (this._options?.enforceStrictCapabilities === true) try {
|
|
1891
|
+
this.assertCapabilityForMethod(request.method);
|
|
1892
|
+
if (task) this.assertTaskCapability(request.method);
|
|
1893
|
+
} catch (e) {
|
|
1894
|
+
earlyReject(e);
|
|
1895
|
+
return;
|
|
1896
|
+
}
|
|
1897
|
+
options?.signal?.throwIfAborted();
|
|
1898
|
+
const messageId = this._requestMessageId++;
|
|
1899
|
+
const jsonrpcRequest = {
|
|
1900
|
+
...request,
|
|
1901
|
+
jsonrpc: "2.0",
|
|
1902
|
+
id: messageId
|
|
1903
|
+
};
|
|
1904
|
+
if (options?.onprogress) {
|
|
1905
|
+
this._progressHandlers.set(messageId, options.onprogress);
|
|
1906
|
+
jsonrpcRequest.params = {
|
|
1907
|
+
...request.params,
|
|
1908
|
+
_meta: {
|
|
1909
|
+
...request.params?._meta || {},
|
|
1910
|
+
progressToken: messageId
|
|
1911
|
+
}
|
|
1912
|
+
};
|
|
1913
|
+
}
|
|
1914
|
+
if (task) jsonrpcRequest.params = {
|
|
1915
|
+
...jsonrpcRequest.params,
|
|
1916
|
+
task
|
|
1917
|
+
};
|
|
1918
|
+
if (relatedTask) jsonrpcRequest.params = {
|
|
1919
|
+
...jsonrpcRequest.params,
|
|
1920
|
+
_meta: {
|
|
1921
|
+
...jsonrpcRequest.params?._meta || {},
|
|
1922
|
+
[RELATED_TASK_META_KEY]: relatedTask
|
|
1923
|
+
}
|
|
1924
|
+
};
|
|
1925
|
+
const cancel = (reason) => {
|
|
1926
|
+
this._responseHandlers.delete(messageId);
|
|
1927
|
+
this._progressHandlers.delete(messageId);
|
|
1928
|
+
this._cleanupTimeout(messageId);
|
|
1929
|
+
this._transport?.send({
|
|
1930
|
+
jsonrpc: "2.0",
|
|
1931
|
+
method: "notifications/cancelled",
|
|
1932
|
+
params: {
|
|
1933
|
+
requestId: messageId,
|
|
1934
|
+
reason: String(reason)
|
|
1935
|
+
}
|
|
1936
|
+
}, {
|
|
1937
|
+
relatedRequestId,
|
|
1938
|
+
resumptionToken,
|
|
1939
|
+
onresumptiontoken
|
|
1940
|
+
}).catch((error) => this._onerror(/* @__PURE__ */ new Error(`Failed to send cancellation: ${error}`)));
|
|
1941
|
+
reject(reason instanceof McpError ? reason : new McpError(ErrorCode.RequestTimeout, String(reason)));
|
|
1942
|
+
};
|
|
1943
|
+
this._responseHandlers.set(messageId, (response) => {
|
|
1944
|
+
if (options?.signal?.aborted) return;
|
|
1945
|
+
if (response instanceof Error) return reject(response);
|
|
1946
|
+
try {
|
|
1947
|
+
const parseResult = safeParse(resultSchema, response.result);
|
|
1948
|
+
if (!parseResult.success) reject(parseResult.error);
|
|
1949
|
+
else resolve(parseResult.data);
|
|
1950
|
+
} catch (error) {
|
|
1951
|
+
reject(error);
|
|
1952
|
+
}
|
|
1953
|
+
});
|
|
1954
|
+
options?.signal?.addEventListener("abort", () => {
|
|
1955
|
+
cancel(options?.signal?.reason);
|
|
1956
|
+
});
|
|
1957
|
+
const timeout = options?.timeout ?? DEFAULT_REQUEST_TIMEOUT_MSEC;
|
|
1958
|
+
const timeoutHandler = () => cancel(McpError.fromError(ErrorCode.RequestTimeout, "Request timed out", { timeout }));
|
|
1959
|
+
this._setupTimeout(messageId, timeout, options?.maxTotalTimeout, timeoutHandler, options?.resetTimeoutOnProgress ?? false);
|
|
1960
|
+
const relatedTaskId = relatedTask?.taskId;
|
|
1961
|
+
if (relatedTaskId) {
|
|
1962
|
+
const responseResolver = (response) => {
|
|
1963
|
+
const handler = this._responseHandlers.get(messageId);
|
|
1964
|
+
if (handler) handler(response);
|
|
1965
|
+
else this._onerror(/* @__PURE__ */ new Error(`Response handler missing for side-channeled request ${messageId}`));
|
|
1966
|
+
};
|
|
1967
|
+
this._requestResolvers.set(messageId, responseResolver);
|
|
1968
|
+
this._enqueueTaskMessage(relatedTaskId, {
|
|
1969
|
+
type: "request",
|
|
1970
|
+
message: jsonrpcRequest,
|
|
1971
|
+
timestamp: Date.now()
|
|
1972
|
+
}).catch((error) => {
|
|
1973
|
+
this._cleanupTimeout(messageId);
|
|
1974
|
+
reject(error);
|
|
1975
|
+
});
|
|
1976
|
+
} else this._transport.send(jsonrpcRequest, {
|
|
1977
|
+
relatedRequestId,
|
|
1978
|
+
resumptionToken,
|
|
1979
|
+
onresumptiontoken
|
|
1980
|
+
}).catch((error) => {
|
|
1981
|
+
this._cleanupTimeout(messageId);
|
|
1982
|
+
reject(error);
|
|
1983
|
+
});
|
|
1984
|
+
});
|
|
1985
|
+
}
|
|
1986
|
+
/**
|
|
1987
|
+
* Gets the current status of a task.
|
|
1988
|
+
*
|
|
1989
|
+
* @experimental Use `client.experimental.tasks.getTask()` to access this method.
|
|
1990
|
+
*/
|
|
1991
|
+
async getTask(params, options) {
|
|
1992
|
+
return this.request({
|
|
1993
|
+
method: "tasks/get",
|
|
1994
|
+
params
|
|
1995
|
+
}, GetTaskResultSchema, options);
|
|
1996
|
+
}
|
|
1997
|
+
/**
|
|
1998
|
+
* Retrieves the result of a completed task.
|
|
1999
|
+
*
|
|
2000
|
+
* @experimental Use `client.experimental.tasks.getTaskResult()` to access this method.
|
|
2001
|
+
*/
|
|
2002
|
+
async getTaskResult(params, resultSchema, options) {
|
|
2003
|
+
return this.request({
|
|
2004
|
+
method: "tasks/result",
|
|
2005
|
+
params
|
|
2006
|
+
}, resultSchema, options);
|
|
2007
|
+
}
|
|
2008
|
+
/**
|
|
2009
|
+
* Lists tasks, optionally starting from a pagination cursor.
|
|
2010
|
+
*
|
|
2011
|
+
* @experimental Use `client.experimental.tasks.listTasks()` to access this method.
|
|
2012
|
+
*/
|
|
2013
|
+
async listTasks(params, options) {
|
|
2014
|
+
return this.request({
|
|
2015
|
+
method: "tasks/list",
|
|
2016
|
+
params
|
|
2017
|
+
}, ListTasksResultSchema, options);
|
|
2018
|
+
}
|
|
2019
|
+
/**
|
|
2020
|
+
* Cancels a specific task.
|
|
2021
|
+
*
|
|
2022
|
+
* @experimental Use `client.experimental.tasks.cancelTask()` to access this method.
|
|
2023
|
+
*/
|
|
2024
|
+
async cancelTask(params, options) {
|
|
2025
|
+
return this.request({
|
|
2026
|
+
method: "tasks/cancel",
|
|
2027
|
+
params
|
|
2028
|
+
}, CancelTaskResultSchema, options);
|
|
2029
|
+
}
|
|
2030
|
+
/**
|
|
2031
|
+
* Emits a notification, which is a one-way message that does not expect a response.
|
|
2032
|
+
*/
|
|
2033
|
+
async notification(notification, options) {
|
|
2034
|
+
if (!this._transport) throw new Error("Not connected");
|
|
2035
|
+
this.assertNotificationCapability(notification.method);
|
|
2036
|
+
const relatedTaskId = options?.relatedTask?.taskId;
|
|
2037
|
+
if (relatedTaskId) {
|
|
2038
|
+
const jsonrpcNotification$1 = {
|
|
2039
|
+
...notification,
|
|
2040
|
+
jsonrpc: "2.0",
|
|
2041
|
+
params: {
|
|
2042
|
+
...notification.params,
|
|
2043
|
+
_meta: {
|
|
2044
|
+
...notification.params?._meta || {},
|
|
2045
|
+
[RELATED_TASK_META_KEY]: options.relatedTask
|
|
2046
|
+
}
|
|
2047
|
+
}
|
|
2048
|
+
};
|
|
2049
|
+
await this._enqueueTaskMessage(relatedTaskId, {
|
|
2050
|
+
type: "notification",
|
|
2051
|
+
message: jsonrpcNotification$1,
|
|
2052
|
+
timestamp: Date.now()
|
|
2053
|
+
});
|
|
2054
|
+
return;
|
|
2055
|
+
}
|
|
2056
|
+
if ((this._options?.debouncedNotificationMethods ?? []).includes(notification.method) && !notification.params && !options?.relatedRequestId && !options?.relatedTask) {
|
|
2057
|
+
if (this._pendingDebouncedNotifications.has(notification.method)) return;
|
|
2058
|
+
this._pendingDebouncedNotifications.add(notification.method);
|
|
2059
|
+
Promise.resolve().then(() => {
|
|
2060
|
+
this._pendingDebouncedNotifications.delete(notification.method);
|
|
2061
|
+
if (!this._transport) return;
|
|
2062
|
+
let jsonrpcNotification$1 = {
|
|
2063
|
+
...notification,
|
|
2064
|
+
jsonrpc: "2.0"
|
|
2065
|
+
};
|
|
2066
|
+
if (options?.relatedTask) jsonrpcNotification$1 = {
|
|
2067
|
+
...jsonrpcNotification$1,
|
|
2068
|
+
params: {
|
|
2069
|
+
...jsonrpcNotification$1.params,
|
|
2070
|
+
_meta: {
|
|
2071
|
+
...jsonrpcNotification$1.params?._meta || {},
|
|
2072
|
+
[RELATED_TASK_META_KEY]: options.relatedTask
|
|
2073
|
+
}
|
|
2074
|
+
}
|
|
2075
|
+
};
|
|
2076
|
+
this._transport?.send(jsonrpcNotification$1, options).catch((error) => this._onerror(error));
|
|
2077
|
+
});
|
|
2078
|
+
return;
|
|
2079
|
+
}
|
|
2080
|
+
let jsonrpcNotification = {
|
|
2081
|
+
...notification,
|
|
2082
|
+
jsonrpc: "2.0"
|
|
2083
|
+
};
|
|
2084
|
+
if (options?.relatedTask) jsonrpcNotification = {
|
|
2085
|
+
...jsonrpcNotification,
|
|
2086
|
+
params: {
|
|
2087
|
+
...jsonrpcNotification.params,
|
|
2088
|
+
_meta: {
|
|
2089
|
+
...jsonrpcNotification.params?._meta || {},
|
|
2090
|
+
[RELATED_TASK_META_KEY]: options.relatedTask
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
};
|
|
2094
|
+
await this._transport.send(jsonrpcNotification, options);
|
|
2095
|
+
}
|
|
2096
|
+
/**
|
|
2097
|
+
* Registers a handler to invoke when this protocol object receives a request with the given method.
|
|
2098
|
+
*
|
|
2099
|
+
* Note that this will replace any previous request handler for the same method.
|
|
2100
|
+
*/
|
|
2101
|
+
setRequestHandler(requestSchema, handler) {
|
|
2102
|
+
const method = getMethodLiteral(requestSchema);
|
|
2103
|
+
this.assertRequestHandlerCapability(method);
|
|
2104
|
+
this._requestHandlers.set(method, (request, extra) => {
|
|
2105
|
+
const parsed = parseWithCompat(requestSchema, request);
|
|
2106
|
+
return Promise.resolve(handler(parsed, extra));
|
|
2107
|
+
});
|
|
2108
|
+
}
|
|
2109
|
+
/**
|
|
2110
|
+
* Removes the request handler for the given method.
|
|
2111
|
+
*/
|
|
2112
|
+
removeRequestHandler(method) {
|
|
2113
|
+
this._requestHandlers.delete(method);
|
|
2114
|
+
}
|
|
2115
|
+
/**
|
|
2116
|
+
* Asserts that a request handler has not already been set for the given method, in preparation for a new one being automatically installed.
|
|
2117
|
+
*/
|
|
2118
|
+
assertCanSetRequestHandler(method) {
|
|
2119
|
+
if (this._requestHandlers.has(method)) throw new Error(`A request handler for ${method} already exists, which would be overridden`);
|
|
2120
|
+
}
|
|
2121
|
+
/**
|
|
2122
|
+
* Registers a handler to invoke when this protocol object receives a notification with the given method.
|
|
2123
|
+
*
|
|
2124
|
+
* Note that this will replace any previous notification handler for the same method.
|
|
2125
|
+
*/
|
|
2126
|
+
setNotificationHandler(notificationSchema, handler) {
|
|
2127
|
+
const method = getMethodLiteral(notificationSchema);
|
|
2128
|
+
this._notificationHandlers.set(method, (notification) => {
|
|
2129
|
+
const parsed = parseWithCompat(notificationSchema, notification);
|
|
2130
|
+
return Promise.resolve(handler(parsed));
|
|
2131
|
+
});
|
|
2132
|
+
}
|
|
2133
|
+
/**
|
|
2134
|
+
* Removes the notification handler for the given method.
|
|
2135
|
+
*/
|
|
2136
|
+
removeNotificationHandler(method) {
|
|
2137
|
+
this._notificationHandlers.delete(method);
|
|
2138
|
+
}
|
|
2139
|
+
/**
|
|
2140
|
+
* Cleans up the progress handler associated with a task.
|
|
2141
|
+
* This should be called when a task reaches a terminal status.
|
|
2142
|
+
*/
|
|
2143
|
+
_cleanupTaskProgressHandler(taskId) {
|
|
2144
|
+
const progressToken = this._taskProgressTokens.get(taskId);
|
|
2145
|
+
if (progressToken !== void 0) {
|
|
2146
|
+
this._progressHandlers.delete(progressToken);
|
|
2147
|
+
this._taskProgressTokens.delete(taskId);
|
|
2148
|
+
}
|
|
2149
|
+
}
|
|
2150
|
+
/**
|
|
2151
|
+
* Enqueues a task-related message for side-channel delivery via tasks/result.
|
|
2152
|
+
* @param taskId The task ID to associate the message with
|
|
2153
|
+
* @param message The message to enqueue
|
|
2154
|
+
* @param sessionId Optional session ID for binding the operation to a specific session
|
|
2155
|
+
* @throws Error if taskStore is not configured or if enqueue fails (e.g., queue overflow)
|
|
2156
|
+
*
|
|
2157
|
+
* Note: If enqueue fails, it's the TaskMessageQueue implementation's responsibility to handle
|
|
2158
|
+
* the error appropriately (e.g., by failing the task, logging, etc.). The Protocol layer
|
|
2159
|
+
* simply propagates the error.
|
|
2160
|
+
*/
|
|
2161
|
+
async _enqueueTaskMessage(taskId, message, sessionId) {
|
|
2162
|
+
if (!this._taskStore || !this._taskMessageQueue) throw new Error("Cannot enqueue task message: taskStore and taskMessageQueue are not configured");
|
|
2163
|
+
const maxQueueSize = this._options?.maxTaskQueueSize;
|
|
2164
|
+
await this._taskMessageQueue.enqueue(taskId, message, sessionId, maxQueueSize);
|
|
2165
|
+
}
|
|
2166
|
+
/**
|
|
2167
|
+
* Clears the message queue for a task and rejects any pending request resolvers.
|
|
2168
|
+
* @param taskId The task ID whose queue should be cleared
|
|
2169
|
+
* @param sessionId Optional session ID for binding the operation to a specific session
|
|
2170
|
+
*/
|
|
2171
|
+
async _clearTaskQueue(taskId, sessionId) {
|
|
2172
|
+
if (this._taskMessageQueue) {
|
|
2173
|
+
const messages = await this._taskMessageQueue.dequeueAll(taskId, sessionId);
|
|
2174
|
+
for (const message of messages) if (message.type === "request" && isJSONRPCRequest(message.message)) {
|
|
2175
|
+
const requestId = message.message.id;
|
|
2176
|
+
const resolver = this._requestResolvers.get(requestId);
|
|
2177
|
+
if (resolver) {
|
|
2178
|
+
resolver(new McpError(ErrorCode.InternalError, "Task cancelled or completed"));
|
|
2179
|
+
this._requestResolvers.delete(requestId);
|
|
2180
|
+
} else this._onerror(/* @__PURE__ */ new Error(`Resolver missing for request ${requestId} during task ${taskId} cleanup`));
|
|
2181
|
+
}
|
|
2182
|
+
}
|
|
2183
|
+
}
|
|
2184
|
+
/**
|
|
2185
|
+
* Waits for a task update (new messages or status change) with abort signal support.
|
|
2186
|
+
* Uses polling to check for updates at the task's configured poll interval.
|
|
2187
|
+
* @param taskId The task ID to wait for
|
|
2188
|
+
* @param signal Abort signal to cancel the wait
|
|
2189
|
+
* @returns Promise that resolves when an update occurs or rejects if aborted
|
|
2190
|
+
*/
|
|
2191
|
+
async _waitForTaskUpdate(taskId, signal) {
|
|
2192
|
+
let interval = this._options?.defaultTaskPollInterval ?? 1e3;
|
|
2193
|
+
try {
|
|
2194
|
+
const task = await this._taskStore?.getTask(taskId);
|
|
2195
|
+
if (task?.pollInterval) interval = task.pollInterval;
|
|
2196
|
+
} catch {}
|
|
2197
|
+
return new Promise((resolve, reject) => {
|
|
2198
|
+
if (signal.aborted) {
|
|
2199
|
+
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
2200
|
+
return;
|
|
2201
|
+
}
|
|
2202
|
+
const timeoutId = setTimeout(resolve, interval);
|
|
2203
|
+
signal.addEventListener("abort", () => {
|
|
2204
|
+
clearTimeout(timeoutId);
|
|
2205
|
+
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
2206
|
+
}, { once: true });
|
|
2207
|
+
});
|
|
2208
|
+
}
|
|
2209
|
+
requestTaskStore(request, sessionId) {
|
|
2210
|
+
const taskStore = this._taskStore;
|
|
2211
|
+
if (!taskStore) throw new Error("No task store configured");
|
|
2212
|
+
return {
|
|
2213
|
+
createTask: async (taskParams) => {
|
|
2214
|
+
if (!request) throw new Error("No request provided");
|
|
2215
|
+
return await taskStore.createTask(taskParams, request.id, {
|
|
2216
|
+
method: request.method,
|
|
2217
|
+
params: request.params
|
|
2218
|
+
}, sessionId);
|
|
2219
|
+
},
|
|
2220
|
+
getTask: async (taskId) => {
|
|
2221
|
+
const task = await taskStore.getTask(taskId, sessionId);
|
|
2222
|
+
if (!task) throw new McpError(ErrorCode.InvalidParams, "Failed to retrieve task: Task not found");
|
|
2223
|
+
return task;
|
|
2224
|
+
},
|
|
2225
|
+
storeTaskResult: async (taskId, status, result) => {
|
|
2226
|
+
await taskStore.storeTaskResult(taskId, status, result, sessionId);
|
|
2227
|
+
const task = await taskStore.getTask(taskId, sessionId);
|
|
2228
|
+
if (task) {
|
|
2229
|
+
const notification = TaskStatusNotificationSchema.parse({
|
|
2230
|
+
method: "notifications/tasks/status",
|
|
2231
|
+
params: task
|
|
2232
|
+
});
|
|
2233
|
+
await this.notification(notification);
|
|
2234
|
+
if (isTerminal(task.status)) this._cleanupTaskProgressHandler(taskId);
|
|
2235
|
+
}
|
|
2236
|
+
},
|
|
2237
|
+
getTaskResult: (taskId) => {
|
|
2238
|
+
return taskStore.getTaskResult(taskId, sessionId);
|
|
2239
|
+
},
|
|
2240
|
+
updateTaskStatus: async (taskId, status, statusMessage) => {
|
|
2241
|
+
const task = await taskStore.getTask(taskId, sessionId);
|
|
2242
|
+
if (!task) throw new McpError(ErrorCode.InvalidParams, `Task "${taskId}" not found - it may have been cleaned up`);
|
|
2243
|
+
if (isTerminal(task.status)) throw new McpError(ErrorCode.InvalidParams, `Cannot update task "${taskId}" from terminal status "${task.status}" to "${status}". Terminal states (completed, failed, cancelled) cannot transition to other states.`);
|
|
2244
|
+
await taskStore.updateTaskStatus(taskId, status, statusMessage, sessionId);
|
|
2245
|
+
const updatedTask = await taskStore.getTask(taskId, sessionId);
|
|
2246
|
+
if (updatedTask) {
|
|
2247
|
+
const notification = TaskStatusNotificationSchema.parse({
|
|
2248
|
+
method: "notifications/tasks/status",
|
|
2249
|
+
params: updatedTask
|
|
2250
|
+
});
|
|
2251
|
+
await this.notification(notification);
|
|
2252
|
+
if (isTerminal(updatedTask.status)) this._cleanupTaskProgressHandler(taskId);
|
|
2253
|
+
}
|
|
2254
|
+
},
|
|
2255
|
+
listTasks: (cursor) => {
|
|
2256
|
+
return taskStore.listTasks(cursor, sessionId);
|
|
2257
|
+
}
|
|
2258
|
+
};
|
|
2259
|
+
}
|
|
2260
|
+
};
|
|
2261
|
+
function isPlainObject$2(value) {
|
|
2262
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2263
|
+
}
|
|
2264
|
+
function mergeCapabilities(base, additional) {
|
|
2265
|
+
const result = { ...base };
|
|
2266
|
+
for (const key in additional) {
|
|
2267
|
+
const k = key;
|
|
2268
|
+
const addValue = additional[k];
|
|
2269
|
+
if (addValue === void 0) continue;
|
|
2270
|
+
const baseValue = result[k];
|
|
2271
|
+
if (isPlainObject$2(baseValue) && isPlainObject$2(addValue)) result[k] = {
|
|
2272
|
+
...baseValue,
|
|
2273
|
+
...addValue
|
|
2274
|
+
};
|
|
2275
|
+
else result[k] = addValue;
|
|
2276
|
+
}
|
|
2277
|
+
return result;
|
|
2278
|
+
}
|
|
2279
|
+
|
|
2280
|
+
//#endregion
|
|
2281
|
+
//#region src/stubs/ajv.ts
|
|
2282
|
+
/**
|
|
2283
|
+
* Throwing ajv stub for browser environments.
|
|
2284
|
+
*
|
|
2285
|
+
* The MCP SDK's Server class statically imports AjvJsonSchemaValidator as a
|
|
2286
|
+
* default fallback. BrowserMcpServer always passes PolyfillJsonSchemaValidator,
|
|
2287
|
+
* so ajv is never actually used — but the static import still resolves. This
|
|
2288
|
+
* stub satisfies that import without pulling in the real ajv (CJS-only, breaks
|
|
2289
|
+
* in browsers).
|
|
2290
|
+
*
|
|
2291
|
+
* If any code path unexpectedly reaches this stub, it throws immediately so the
|
|
2292
|
+
* issue is surfaced rather than silently passing all validation.
|
|
2293
|
+
*/
|
|
2294
|
+
var Ajv = class {
|
|
2295
|
+
compile(_schema) {
|
|
2296
|
+
throw new Error("[WebMCP] Ajv stub was invoked. This indicates the MCP SDK is bypassing PolyfillJsonSchemaValidator. Please report this as a bug.");
|
|
2297
|
+
}
|
|
2298
|
+
getSchema(_id) {}
|
|
2299
|
+
errorsText(_errors) {
|
|
2300
|
+
return "";
|
|
2301
|
+
}
|
|
2302
|
+
};
|
|
2303
|
+
var ajv_default = Ajv;
|
|
2304
|
+
|
|
2305
|
+
//#endregion
|
|
2306
|
+
//#region src/stubs/ajv-formats.ts
|
|
2307
|
+
/**
|
|
2308
|
+
* No-op ajv-formats stub for browser environments.
|
|
2309
|
+
* See ./ajv.ts for rationale.
|
|
2310
|
+
*/
|
|
2311
|
+
function addFormats(_ajv) {}
|
|
2312
|
+
|
|
2313
|
+
//#endregion
|
|
2314
|
+
//#region ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.26.0_@cfworker+json-schema@4.1.1_zod@4.3.5/node_modules/@modelcontextprotocol/sdk/dist/esm/validation/ajv-provider.js
|
|
2315
|
+
function createDefaultAjvInstance() {
|
|
2316
|
+
const ajv = new ajv_default({
|
|
2317
|
+
strict: false,
|
|
2318
|
+
validateFormats: true,
|
|
2319
|
+
validateSchema: false,
|
|
2320
|
+
allErrors: true
|
|
2321
|
+
});
|
|
2322
|
+
addFormats(ajv);
|
|
2323
|
+
return ajv;
|
|
2324
|
+
}
|
|
2325
|
+
/**
|
|
2326
|
+
* @example
|
|
2327
|
+
* ```typescript
|
|
2328
|
+
* // Use with default AJV instance (recommended)
|
|
2329
|
+
* import { AjvJsonSchemaValidator } from '@modelcontextprotocol/sdk/validation/ajv';
|
|
2330
|
+
* const validator = new AjvJsonSchemaValidator();
|
|
2331
|
+
*
|
|
2332
|
+
* // Use with custom AJV instance
|
|
2333
|
+
* import { Ajv } from 'ajv';
|
|
2334
|
+
* const ajv = new Ajv({ strict: true, allErrors: true });
|
|
2335
|
+
* const validator = new AjvJsonSchemaValidator(ajv);
|
|
2336
|
+
* ```
|
|
2337
|
+
*/
|
|
2338
|
+
var AjvJsonSchemaValidator = class {
|
|
2339
|
+
/**
|
|
2340
|
+
* Create an AJV validator
|
|
2341
|
+
*
|
|
2342
|
+
* @param ajv - Optional pre-configured AJV instance. If not provided, a default instance will be created.
|
|
2343
|
+
*
|
|
2344
|
+
* @example
|
|
2345
|
+
* ```typescript
|
|
2346
|
+
* // Use default configuration (recommended for most cases)
|
|
2347
|
+
* import { AjvJsonSchemaValidator } from '@modelcontextprotocol/sdk/validation/ajv';
|
|
2348
|
+
* const validator = new AjvJsonSchemaValidator();
|
|
2349
|
+
*
|
|
2350
|
+
* // Or provide custom AJV instance for advanced configuration
|
|
2351
|
+
* import { Ajv } from 'ajv';
|
|
2352
|
+
* import addFormats from 'ajv-formats';
|
|
2353
|
+
*
|
|
2354
|
+
* const ajv = new Ajv({ validateFormats: true });
|
|
2355
|
+
* addFormats(ajv);
|
|
2356
|
+
* const validator = new AjvJsonSchemaValidator(ajv);
|
|
2357
|
+
* ```
|
|
2358
|
+
*/
|
|
2359
|
+
constructor(ajv) {
|
|
2360
|
+
this._ajv = ajv ?? createDefaultAjvInstance();
|
|
2361
|
+
}
|
|
2362
|
+
/**
|
|
2363
|
+
* Create a validator for the given JSON Schema
|
|
2364
|
+
*
|
|
2365
|
+
* The validator is compiled once and can be reused multiple times.
|
|
2366
|
+
* If the schema has an $id, it will be cached by AJV automatically.
|
|
2367
|
+
*
|
|
2368
|
+
* @param schema - Standard JSON Schema object
|
|
2369
|
+
* @returns A validator function that validates input data
|
|
2370
|
+
*/
|
|
2371
|
+
getValidator(schema) {
|
|
2372
|
+
const ajvValidator = "$id" in schema && typeof schema.$id === "string" ? this._ajv.getSchema(schema.$id) ?? this._ajv.compile(schema) : this._ajv.compile(schema);
|
|
2373
|
+
return (input) => {
|
|
2374
|
+
if (ajvValidator(input)) return {
|
|
2375
|
+
valid: true,
|
|
2376
|
+
data: input,
|
|
2377
|
+
errorMessage: void 0
|
|
2378
|
+
};
|
|
2379
|
+
else return {
|
|
2380
|
+
valid: false,
|
|
2381
|
+
data: void 0,
|
|
2382
|
+
errorMessage: this._ajv.errorsText(ajvValidator.errors)
|
|
2383
|
+
};
|
|
2384
|
+
};
|
|
2385
|
+
}
|
|
2386
|
+
};
|
|
2387
|
+
|
|
2388
|
+
//#endregion
|
|
2389
|
+
//#region ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.26.0_@cfworker+json-schema@4.1.1_zod@4.3.5/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/client.js
|
|
2390
|
+
/**
|
|
2391
|
+
* Experimental task features for MCP clients.
|
|
2392
|
+
*
|
|
2393
|
+
* Access via `client.experimental.tasks`:
|
|
2394
|
+
* ```typescript
|
|
2395
|
+
* const stream = client.experimental.tasks.callToolStream({ name: 'tool', arguments: {} });
|
|
2396
|
+
* const task = await client.experimental.tasks.getTask(taskId);
|
|
2397
|
+
* ```
|
|
2398
|
+
*
|
|
2399
|
+
* @experimental
|
|
2400
|
+
*/
|
|
2401
|
+
var ExperimentalClientTasks = class {
|
|
2402
|
+
constructor(_client) {
|
|
2403
|
+
this._client = _client;
|
|
2404
|
+
}
|
|
2405
|
+
/**
|
|
2406
|
+
* Calls a tool and returns an AsyncGenerator that yields response messages.
|
|
2407
|
+
* The generator is guaranteed to end with either a 'result' or 'error' message.
|
|
2408
|
+
*
|
|
2409
|
+
* This method provides streaming access to tool execution, allowing you to
|
|
2410
|
+
* observe intermediate task status updates for long-running tool calls.
|
|
2411
|
+
* Automatically validates structured output if the tool has an outputSchema.
|
|
2412
|
+
*
|
|
2413
|
+
* @example
|
|
2414
|
+
* ```typescript
|
|
2415
|
+
* const stream = client.experimental.tasks.callToolStream({ name: 'myTool', arguments: {} });
|
|
2416
|
+
* for await (const message of stream) {
|
|
2417
|
+
* switch (message.type) {
|
|
2418
|
+
* case 'taskCreated':
|
|
2419
|
+
* console.log('Tool execution started:', message.task.taskId);
|
|
2420
|
+
* break;
|
|
2421
|
+
* case 'taskStatus':
|
|
2422
|
+
* console.log('Tool status:', message.task.status);
|
|
2423
|
+
* break;
|
|
2424
|
+
* case 'result':
|
|
2425
|
+
* console.log('Tool result:', message.result);
|
|
2426
|
+
* break;
|
|
2427
|
+
* case 'error':
|
|
2428
|
+
* console.error('Tool error:', message.error);
|
|
2429
|
+
* break;
|
|
2430
|
+
* }
|
|
2431
|
+
* }
|
|
2432
|
+
* ```
|
|
2433
|
+
*
|
|
2434
|
+
* @param params - Tool call parameters (name and arguments)
|
|
2435
|
+
* @param resultSchema - Zod schema for validating the result (defaults to CallToolResultSchema)
|
|
2436
|
+
* @param options - Optional request options (timeout, signal, task creation params, etc.)
|
|
2437
|
+
* @returns AsyncGenerator that yields ResponseMessage objects
|
|
2438
|
+
*
|
|
2439
|
+
* @experimental
|
|
2440
|
+
*/
|
|
2441
|
+
async *callToolStream(params, resultSchema = CallToolResultSchema, options) {
|
|
2442
|
+
const clientInternal = this._client;
|
|
2443
|
+
const optionsWithTask = {
|
|
2444
|
+
...options,
|
|
2445
|
+
task: options?.task ?? (clientInternal.isToolTask(params.name) ? {} : void 0)
|
|
2446
|
+
};
|
|
2447
|
+
const stream = clientInternal.requestStream({
|
|
2448
|
+
method: "tools/call",
|
|
2449
|
+
params
|
|
2450
|
+
}, resultSchema, optionsWithTask);
|
|
2451
|
+
const validator = clientInternal.getToolOutputValidator(params.name);
|
|
2452
|
+
for await (const message of stream) {
|
|
2453
|
+
if (message.type === "result" && validator) {
|
|
2454
|
+
const result = message.result;
|
|
2455
|
+
if (!result.structuredContent && !result.isError) {
|
|
2456
|
+
yield {
|
|
2457
|
+
type: "error",
|
|
2458
|
+
error: new McpError(ErrorCode.InvalidRequest, `Tool ${params.name} has an output schema but did not return structured content`)
|
|
2459
|
+
};
|
|
2460
|
+
return;
|
|
2461
|
+
}
|
|
2462
|
+
if (result.structuredContent) try {
|
|
2463
|
+
const validationResult = validator(result.structuredContent);
|
|
2464
|
+
if (!validationResult.valid) {
|
|
2465
|
+
yield {
|
|
2466
|
+
type: "error",
|
|
2467
|
+
error: new McpError(ErrorCode.InvalidParams, `Structured content does not match the tool's output schema: ${validationResult.errorMessage}`)
|
|
2468
|
+
};
|
|
2469
|
+
return;
|
|
2470
|
+
}
|
|
2471
|
+
} catch (error) {
|
|
2472
|
+
if (error instanceof McpError) {
|
|
2473
|
+
yield {
|
|
2474
|
+
type: "error",
|
|
2475
|
+
error
|
|
2476
|
+
};
|
|
2477
|
+
return;
|
|
2478
|
+
}
|
|
2479
|
+
yield {
|
|
2480
|
+
type: "error",
|
|
2481
|
+
error: new McpError(ErrorCode.InvalidParams, `Failed to validate structured content: ${error instanceof Error ? error.message : String(error)}`)
|
|
2482
|
+
};
|
|
2483
|
+
return;
|
|
2484
|
+
}
|
|
2485
|
+
}
|
|
2486
|
+
yield message;
|
|
2487
|
+
}
|
|
2488
|
+
}
|
|
2489
|
+
/**
|
|
2490
|
+
* Gets the current status of a task.
|
|
2491
|
+
*
|
|
2492
|
+
* @param taskId - The task identifier
|
|
2493
|
+
* @param options - Optional request options
|
|
2494
|
+
* @returns The task status
|
|
2495
|
+
*
|
|
2496
|
+
* @experimental
|
|
2497
|
+
*/
|
|
2498
|
+
async getTask(taskId, options) {
|
|
2499
|
+
return this._client.getTask({ taskId }, options);
|
|
2500
|
+
}
|
|
2501
|
+
/**
|
|
2502
|
+
* Retrieves the result of a completed task.
|
|
2503
|
+
*
|
|
2504
|
+
* @param taskId - The task identifier
|
|
2505
|
+
* @param resultSchema - Zod schema for validating the result
|
|
2506
|
+
* @param options - Optional request options
|
|
2507
|
+
* @returns The task result
|
|
2508
|
+
*
|
|
2509
|
+
* @experimental
|
|
2510
|
+
*/
|
|
2511
|
+
async getTaskResult(taskId, resultSchema, options) {
|
|
2512
|
+
return this._client.getTaskResult({ taskId }, resultSchema, options);
|
|
2513
|
+
}
|
|
2514
|
+
/**
|
|
2515
|
+
* Lists tasks with optional pagination.
|
|
2516
|
+
*
|
|
2517
|
+
* @param cursor - Optional pagination cursor
|
|
2518
|
+
* @param options - Optional request options
|
|
2519
|
+
* @returns List of tasks with optional next cursor
|
|
2520
|
+
*
|
|
2521
|
+
* @experimental
|
|
2522
|
+
*/
|
|
2523
|
+
async listTasks(cursor, options) {
|
|
2524
|
+
return this._client.listTasks(cursor ? { cursor } : void 0, options);
|
|
2525
|
+
}
|
|
2526
|
+
/**
|
|
2527
|
+
* Cancels a running task.
|
|
2528
|
+
*
|
|
2529
|
+
* @param taskId - The task identifier
|
|
2530
|
+
* @param options - Optional request options
|
|
2531
|
+
*
|
|
2532
|
+
* @experimental
|
|
2533
|
+
*/
|
|
2534
|
+
async cancelTask(taskId, options) {
|
|
2535
|
+
return this._client.cancelTask({ taskId }, options);
|
|
2536
|
+
}
|
|
2537
|
+
/**
|
|
2538
|
+
* Sends a request and returns an AsyncGenerator that yields response messages.
|
|
2539
|
+
* The generator is guaranteed to end with either a 'result' or 'error' message.
|
|
2540
|
+
*
|
|
2541
|
+
* This method provides streaming access to request processing, allowing you to
|
|
2542
|
+
* observe intermediate task status updates for task-augmented requests.
|
|
2543
|
+
*
|
|
2544
|
+
* @param request - The request to send
|
|
2545
|
+
* @param resultSchema - Zod schema for validating the result
|
|
2546
|
+
* @param options - Optional request options (timeout, signal, task creation params, etc.)
|
|
2547
|
+
* @returns AsyncGenerator that yields ResponseMessage objects
|
|
2548
|
+
*
|
|
2549
|
+
* @experimental
|
|
2550
|
+
*/
|
|
2551
|
+
requestStream(request, resultSchema, options) {
|
|
2552
|
+
return this._client.requestStream(request, resultSchema, options);
|
|
2553
|
+
}
|
|
2554
|
+
};
|
|
2555
|
+
|
|
2556
|
+
//#endregion
|
|
2557
|
+
//#region ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.26.0_@cfworker+json-schema@4.1.1_zod@4.3.5/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/helpers.js
|
|
2558
|
+
/**
|
|
2559
|
+
* Experimental task capability assertion helpers.
|
|
2560
|
+
* WARNING: These APIs are experimental and may change without notice.
|
|
2561
|
+
*
|
|
2562
|
+
* @experimental
|
|
2563
|
+
*/
|
|
2564
|
+
/**
|
|
2565
|
+
* Asserts that task creation is supported for tools/call.
|
|
2566
|
+
* Used by Client.assertTaskCapability and Server.assertTaskHandlerCapability.
|
|
2567
|
+
*
|
|
2568
|
+
* @param requests - The task requests capability object
|
|
2569
|
+
* @param method - The method being checked
|
|
2570
|
+
* @param entityName - 'Server' or 'Client' for error messages
|
|
2571
|
+
* @throws Error if the capability is not supported
|
|
2572
|
+
*
|
|
2573
|
+
* @experimental
|
|
2574
|
+
*/
|
|
2575
|
+
function assertToolsCallTaskCapability(requests, method, entityName) {
|
|
2576
|
+
if (!requests) throw new Error(`${entityName} does not support task creation (required for ${method})`);
|
|
2577
|
+
switch (method) {
|
|
2578
|
+
case "tools/call":
|
|
2579
|
+
if (!requests.tools?.call) throw new Error(`${entityName} does not support task creation for tools/call (required for ${method})`);
|
|
2580
|
+
break;
|
|
2581
|
+
default: break;
|
|
2582
|
+
}
|
|
2583
|
+
}
|
|
2584
|
+
/**
|
|
2585
|
+
* Asserts that task creation is supported for sampling/createMessage or elicitation/create.
|
|
2586
|
+
* Used by Server.assertTaskCapability and Client.assertTaskHandlerCapability.
|
|
2587
|
+
*
|
|
2588
|
+
* @param requests - The task requests capability object
|
|
2589
|
+
* @param method - The method being checked
|
|
2590
|
+
* @param entityName - 'Server' or 'Client' for error messages
|
|
2591
|
+
* @throws Error if the capability is not supported
|
|
2592
|
+
*
|
|
2593
|
+
* @experimental
|
|
2594
|
+
*/
|
|
2595
|
+
function assertClientRequestTaskCapability(requests, method, entityName) {
|
|
2596
|
+
if (!requests) throw new Error(`${entityName} does not support task creation (required for ${method})`);
|
|
2597
|
+
switch (method) {
|
|
2598
|
+
case "sampling/createMessage":
|
|
2599
|
+
if (!requests.sampling?.createMessage) throw new Error(`${entityName} does not support task creation for sampling/createMessage (required for ${method})`);
|
|
2600
|
+
break;
|
|
2601
|
+
case "elicitation/create":
|
|
2602
|
+
if (!requests.elicitation?.create) throw new Error(`${entityName} does not support task creation for elicitation/create (required for ${method})`);
|
|
2603
|
+
break;
|
|
2604
|
+
default: break;
|
|
2605
|
+
}
|
|
2606
|
+
}
|
|
2607
|
+
|
|
2608
|
+
//#endregion
|
|
2609
|
+
//#region ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.26.0_@cfworker+json-schema@4.1.1_zod@4.3.5/node_modules/@modelcontextprotocol/sdk/dist/esm/client/index.js
|
|
2610
|
+
/**
|
|
2611
|
+
* Elicitation default application helper. Applies defaults to the data based on the schema.
|
|
2612
|
+
*
|
|
2613
|
+
* @param schema - The schema to apply defaults to.
|
|
2614
|
+
* @param data - The data to apply defaults to.
|
|
2615
|
+
*/
|
|
2616
|
+
function applyElicitationDefaults(schema, data) {
|
|
2617
|
+
if (!schema || data === null || typeof data !== "object") return;
|
|
2618
|
+
if (schema.type === "object" && schema.properties && typeof schema.properties === "object") {
|
|
2619
|
+
const obj = data;
|
|
2620
|
+
const props = schema.properties;
|
|
2621
|
+
for (const key of Object.keys(props)) {
|
|
2622
|
+
const propSchema = props[key];
|
|
2623
|
+
if (obj[key] === void 0 && Object.prototype.hasOwnProperty.call(propSchema, "default")) obj[key] = propSchema.default;
|
|
2624
|
+
if (obj[key] !== void 0) applyElicitationDefaults(propSchema, obj[key]);
|
|
2625
|
+
}
|
|
2626
|
+
}
|
|
2627
|
+
if (Array.isArray(schema.anyOf)) {
|
|
2628
|
+
for (const sub of schema.anyOf) if (typeof sub !== "boolean") applyElicitationDefaults(sub, data);
|
|
2629
|
+
}
|
|
2630
|
+
if (Array.isArray(schema.oneOf)) {
|
|
2631
|
+
for (const sub of schema.oneOf) if (typeof sub !== "boolean") applyElicitationDefaults(sub, data);
|
|
2632
|
+
}
|
|
2633
|
+
}
|
|
2634
|
+
/**
|
|
2635
|
+
* Determines which elicitation modes are supported based on declared client capabilities.
|
|
2636
|
+
*
|
|
2637
|
+
* According to the spec:
|
|
2638
|
+
* - An empty elicitation capability object defaults to form mode support (backwards compatibility)
|
|
2639
|
+
* - URL mode is only supported if explicitly declared
|
|
2640
|
+
*
|
|
2641
|
+
* @param capabilities - The client's elicitation capabilities
|
|
2642
|
+
* @returns An object indicating which modes are supported
|
|
2643
|
+
*/
|
|
2644
|
+
function getSupportedElicitationModes(capabilities) {
|
|
2645
|
+
if (!capabilities) return {
|
|
2646
|
+
supportsFormMode: false,
|
|
2647
|
+
supportsUrlMode: false
|
|
2648
|
+
};
|
|
2649
|
+
const hasFormCapability = capabilities.form !== void 0;
|
|
2650
|
+
const hasUrlCapability = capabilities.url !== void 0;
|
|
2651
|
+
return {
|
|
2652
|
+
supportsFormMode: hasFormCapability || !hasFormCapability && !hasUrlCapability,
|
|
2653
|
+
supportsUrlMode: hasUrlCapability
|
|
2654
|
+
};
|
|
2655
|
+
}
|
|
2656
|
+
/**
|
|
2657
|
+
* An MCP client on top of a pluggable transport.
|
|
2658
|
+
*
|
|
2659
|
+
* The client will automatically begin the initialization flow with the server when connect() is called.
|
|
2660
|
+
*
|
|
2661
|
+
* To use with custom types, extend the base Request/Notification/Result types and pass them as type parameters:
|
|
2662
|
+
*
|
|
2663
|
+
* ```typescript
|
|
2664
|
+
* // Custom schemas
|
|
2665
|
+
* const CustomRequestSchema = RequestSchema.extend({...})
|
|
2666
|
+
* const CustomNotificationSchema = NotificationSchema.extend({...})
|
|
2667
|
+
* const CustomResultSchema = ResultSchema.extend({...})
|
|
2668
|
+
*
|
|
2669
|
+
* // Type aliases
|
|
2670
|
+
* type CustomRequest = z.infer<typeof CustomRequestSchema>
|
|
2671
|
+
* type CustomNotification = z.infer<typeof CustomNotificationSchema>
|
|
2672
|
+
* type CustomResult = z.infer<typeof CustomResultSchema>
|
|
2673
|
+
*
|
|
2674
|
+
* // Create typed client
|
|
2675
|
+
* const client = new Client<CustomRequest, CustomNotification, CustomResult>({
|
|
2676
|
+
* name: "CustomClient",
|
|
2677
|
+
* version: "1.0.0"
|
|
2678
|
+
* })
|
|
2679
|
+
* ```
|
|
2680
|
+
*/
|
|
2681
|
+
var Client = class extends Protocol {
|
|
2682
|
+
/**
|
|
2683
|
+
* Initializes this client with the given name and version information.
|
|
2684
|
+
*/
|
|
2685
|
+
constructor(_clientInfo, options) {
|
|
2686
|
+
super(options);
|
|
2687
|
+
this._clientInfo = _clientInfo;
|
|
2688
|
+
this._cachedToolOutputValidators = /* @__PURE__ */ new Map();
|
|
2689
|
+
this._cachedKnownTaskTools = /* @__PURE__ */ new Set();
|
|
2690
|
+
this._cachedRequiredTaskTools = /* @__PURE__ */ new Set();
|
|
2691
|
+
this._listChangedDebounceTimers = /* @__PURE__ */ new Map();
|
|
2692
|
+
this._capabilities = options?.capabilities ?? {};
|
|
2693
|
+
this._jsonSchemaValidator = options?.jsonSchemaValidator ?? new AjvJsonSchemaValidator();
|
|
2694
|
+
if (options?.listChanged) this._pendingListChangedConfig = options.listChanged;
|
|
2695
|
+
}
|
|
2696
|
+
/**
|
|
2697
|
+
* Set up handlers for list changed notifications based on config and server capabilities.
|
|
2698
|
+
* This should only be called after initialization when server capabilities are known.
|
|
2699
|
+
* Handlers are silently skipped if the server doesn't advertise the corresponding listChanged capability.
|
|
2700
|
+
* @internal
|
|
2701
|
+
*/
|
|
2702
|
+
_setupListChangedHandlers(config) {
|
|
2703
|
+
if (config.tools && this._serverCapabilities?.tools?.listChanged) this._setupListChangedHandler("tools", ToolListChangedNotificationSchema, config.tools, async () => {
|
|
2704
|
+
return (await this.listTools()).tools;
|
|
2705
|
+
});
|
|
2706
|
+
if (config.prompts && this._serverCapabilities?.prompts?.listChanged) this._setupListChangedHandler("prompts", PromptListChangedNotificationSchema, config.prompts, async () => {
|
|
2707
|
+
return (await this.listPrompts()).prompts;
|
|
2708
|
+
});
|
|
2709
|
+
if (config.resources && this._serverCapabilities?.resources?.listChanged) this._setupListChangedHandler("resources", ResourceListChangedNotificationSchema, config.resources, async () => {
|
|
2710
|
+
return (await this.listResources()).resources;
|
|
2711
|
+
});
|
|
2712
|
+
}
|
|
2713
|
+
/**
|
|
2714
|
+
* Access experimental features.
|
|
2715
|
+
*
|
|
2716
|
+
* WARNING: These APIs are experimental and may change without notice.
|
|
2717
|
+
*
|
|
2718
|
+
* @experimental
|
|
2719
|
+
*/
|
|
2720
|
+
get experimental() {
|
|
2721
|
+
if (!this._experimental) this._experimental = { tasks: new ExperimentalClientTasks(this) };
|
|
2722
|
+
return this._experimental;
|
|
2723
|
+
}
|
|
2724
|
+
/**
|
|
2725
|
+
* Registers new capabilities. This can only be called before connecting to a transport.
|
|
2726
|
+
*
|
|
2727
|
+
* The new capabilities will be merged with any existing capabilities previously given (e.g., at initialization).
|
|
2728
|
+
*/
|
|
2729
|
+
registerCapabilities(capabilities) {
|
|
2730
|
+
if (this.transport) throw new Error("Cannot register capabilities after connecting to transport");
|
|
2731
|
+
this._capabilities = mergeCapabilities(this._capabilities, capabilities);
|
|
2732
|
+
}
|
|
2733
|
+
/**
|
|
2734
|
+
* Override request handler registration to enforce client-side validation for elicitation.
|
|
2735
|
+
*/
|
|
2736
|
+
setRequestHandler(requestSchema, handler) {
|
|
2737
|
+
const methodSchema = getObjectShape(requestSchema)?.method;
|
|
2738
|
+
if (!methodSchema) throw new Error("Schema is missing a method literal");
|
|
2739
|
+
let methodValue;
|
|
2740
|
+
if (isZ4Schema(methodSchema)) {
|
|
2741
|
+
const v4Schema = methodSchema;
|
|
2742
|
+
methodValue = (v4Schema._zod?.def)?.value ?? v4Schema.value;
|
|
2743
|
+
} else {
|
|
2744
|
+
const v3Schema = methodSchema;
|
|
2745
|
+
methodValue = v3Schema._def?.value ?? v3Schema.value;
|
|
2746
|
+
}
|
|
2747
|
+
if (typeof methodValue !== "string") throw new Error("Schema method literal must be a string");
|
|
2748
|
+
const method = methodValue;
|
|
2749
|
+
if (method === "elicitation/create") {
|
|
2750
|
+
const wrappedHandler = async (request, extra) => {
|
|
2751
|
+
const validatedRequest = safeParse(ElicitRequestSchema, request);
|
|
2752
|
+
if (!validatedRequest.success) {
|
|
2753
|
+
const errorMessage = validatedRequest.error instanceof Error ? validatedRequest.error.message : String(validatedRequest.error);
|
|
2754
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid elicitation request: ${errorMessage}`);
|
|
2755
|
+
}
|
|
2756
|
+
const { params } = validatedRequest.data;
|
|
2757
|
+
params.mode = params.mode ?? "form";
|
|
2758
|
+
const { supportsFormMode, supportsUrlMode } = getSupportedElicitationModes(this._capabilities.elicitation);
|
|
2759
|
+
if (params.mode === "form" && !supportsFormMode) throw new McpError(ErrorCode.InvalidParams, "Client does not support form-mode elicitation requests");
|
|
2760
|
+
if (params.mode === "url" && !supportsUrlMode) throw new McpError(ErrorCode.InvalidParams, "Client does not support URL-mode elicitation requests");
|
|
2761
|
+
const result = await Promise.resolve(handler(request, extra));
|
|
2762
|
+
if (params.task) {
|
|
2763
|
+
const taskValidationResult = safeParse(CreateTaskResultSchema, result);
|
|
2764
|
+
if (!taskValidationResult.success) {
|
|
2765
|
+
const errorMessage = taskValidationResult.error instanceof Error ? taskValidationResult.error.message : String(taskValidationResult.error);
|
|
2766
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid task creation result: ${errorMessage}`);
|
|
2767
|
+
}
|
|
2768
|
+
return taskValidationResult.data;
|
|
2769
|
+
}
|
|
2770
|
+
const validationResult = safeParse(ElicitResultSchema, result);
|
|
2771
|
+
if (!validationResult.success) {
|
|
2772
|
+
const errorMessage = validationResult.error instanceof Error ? validationResult.error.message : String(validationResult.error);
|
|
2773
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid elicitation result: ${errorMessage}`);
|
|
2774
|
+
}
|
|
2775
|
+
const validatedResult = validationResult.data;
|
|
2776
|
+
const requestedSchema = params.mode === "form" ? params.requestedSchema : void 0;
|
|
2777
|
+
if (params.mode === "form" && validatedResult.action === "accept" && validatedResult.content && requestedSchema) {
|
|
2778
|
+
if (this._capabilities.elicitation?.form?.applyDefaults) try {
|
|
2779
|
+
applyElicitationDefaults(requestedSchema, validatedResult.content);
|
|
2780
|
+
} catch {}
|
|
2781
|
+
}
|
|
2782
|
+
return validatedResult;
|
|
2783
|
+
};
|
|
2784
|
+
return super.setRequestHandler(requestSchema, wrappedHandler);
|
|
2785
|
+
}
|
|
2786
|
+
if (method === "sampling/createMessage") {
|
|
2787
|
+
const wrappedHandler = async (request, extra) => {
|
|
2788
|
+
const validatedRequest = safeParse(CreateMessageRequestSchema, request);
|
|
2789
|
+
if (!validatedRequest.success) {
|
|
2790
|
+
const errorMessage = validatedRequest.error instanceof Error ? validatedRequest.error.message : String(validatedRequest.error);
|
|
2791
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid sampling request: ${errorMessage}`);
|
|
2792
|
+
}
|
|
2793
|
+
const { params } = validatedRequest.data;
|
|
2794
|
+
const result = await Promise.resolve(handler(request, extra));
|
|
2795
|
+
if (params.task) {
|
|
2796
|
+
const taskValidationResult = safeParse(CreateTaskResultSchema, result);
|
|
2797
|
+
if (!taskValidationResult.success) {
|
|
2798
|
+
const errorMessage = taskValidationResult.error instanceof Error ? taskValidationResult.error.message : String(taskValidationResult.error);
|
|
2799
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid task creation result: ${errorMessage}`);
|
|
2800
|
+
}
|
|
2801
|
+
return taskValidationResult.data;
|
|
2802
|
+
}
|
|
2803
|
+
const validationResult = safeParse(params.tools || params.toolChoice ? CreateMessageResultWithToolsSchema : CreateMessageResultSchema, result);
|
|
2804
|
+
if (!validationResult.success) {
|
|
2805
|
+
const errorMessage = validationResult.error instanceof Error ? validationResult.error.message : String(validationResult.error);
|
|
2806
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid sampling result: ${errorMessage}`);
|
|
2807
|
+
}
|
|
2808
|
+
return validationResult.data;
|
|
2809
|
+
};
|
|
2810
|
+
return super.setRequestHandler(requestSchema, wrappedHandler);
|
|
2811
|
+
}
|
|
2812
|
+
return super.setRequestHandler(requestSchema, handler);
|
|
2813
|
+
}
|
|
2814
|
+
assertCapability(capability, method) {
|
|
2815
|
+
if (!this._serverCapabilities?.[capability]) throw new Error(`Server does not support ${capability} (required for ${method})`);
|
|
2816
|
+
}
|
|
2817
|
+
async connect(transport, options) {
|
|
2818
|
+
await super.connect(transport);
|
|
2819
|
+
if (transport.sessionId !== void 0) return;
|
|
2820
|
+
try {
|
|
2821
|
+
const result = await this.request({
|
|
2822
|
+
method: "initialize",
|
|
2823
|
+
params: {
|
|
2824
|
+
protocolVersion: LATEST_PROTOCOL_VERSION,
|
|
2825
|
+
capabilities: this._capabilities,
|
|
2826
|
+
clientInfo: this._clientInfo
|
|
2827
|
+
}
|
|
2828
|
+
}, InitializeResultSchema, options);
|
|
2829
|
+
if (result === void 0) throw new Error(`Server sent invalid initialize result: ${result}`);
|
|
2830
|
+
if (!SUPPORTED_PROTOCOL_VERSIONS.includes(result.protocolVersion)) throw new Error(`Server's protocol version is not supported: ${result.protocolVersion}`);
|
|
2831
|
+
this._serverCapabilities = result.capabilities;
|
|
2832
|
+
this._serverVersion = result.serverInfo;
|
|
2833
|
+
if (transport.setProtocolVersion) transport.setProtocolVersion(result.protocolVersion);
|
|
2834
|
+
this._instructions = result.instructions;
|
|
2835
|
+
await this.notification({ method: "notifications/initialized" });
|
|
2836
|
+
if (this._pendingListChangedConfig) {
|
|
2837
|
+
this._setupListChangedHandlers(this._pendingListChangedConfig);
|
|
2838
|
+
this._pendingListChangedConfig = void 0;
|
|
2839
|
+
}
|
|
2840
|
+
} catch (error) {
|
|
2841
|
+
this.close();
|
|
2842
|
+
throw error;
|
|
2843
|
+
}
|
|
2844
|
+
}
|
|
2845
|
+
/**
|
|
2846
|
+
* After initialization has completed, this will be populated with the server's reported capabilities.
|
|
2847
|
+
*/
|
|
2848
|
+
getServerCapabilities() {
|
|
2849
|
+
return this._serverCapabilities;
|
|
2850
|
+
}
|
|
2851
|
+
/**
|
|
2852
|
+
* After initialization has completed, this will be populated with information about the server's name and version.
|
|
2853
|
+
*/
|
|
2854
|
+
getServerVersion() {
|
|
2855
|
+
return this._serverVersion;
|
|
2856
|
+
}
|
|
2857
|
+
/**
|
|
2858
|
+
* After initialization has completed, this may be populated with information about the server's instructions.
|
|
2859
|
+
*/
|
|
2860
|
+
getInstructions() {
|
|
2861
|
+
return this._instructions;
|
|
2862
|
+
}
|
|
2863
|
+
assertCapabilityForMethod(method) {
|
|
2864
|
+
switch (method) {
|
|
2865
|
+
case "logging/setLevel":
|
|
2866
|
+
if (!this._serverCapabilities?.logging) throw new Error(`Server does not support logging (required for ${method})`);
|
|
2867
|
+
break;
|
|
2868
|
+
case "prompts/get":
|
|
2869
|
+
case "prompts/list":
|
|
2870
|
+
if (!this._serverCapabilities?.prompts) throw new Error(`Server does not support prompts (required for ${method})`);
|
|
2871
|
+
break;
|
|
2872
|
+
case "resources/list":
|
|
2873
|
+
case "resources/templates/list":
|
|
2874
|
+
case "resources/read":
|
|
2875
|
+
case "resources/subscribe":
|
|
2876
|
+
case "resources/unsubscribe":
|
|
2877
|
+
if (!this._serverCapabilities?.resources) throw new Error(`Server does not support resources (required for ${method})`);
|
|
2878
|
+
if (method === "resources/subscribe" && !this._serverCapabilities.resources.subscribe) throw new Error(`Server does not support resource subscriptions (required for ${method})`);
|
|
2879
|
+
break;
|
|
2880
|
+
case "tools/call":
|
|
2881
|
+
case "tools/list":
|
|
2882
|
+
if (!this._serverCapabilities?.tools) throw new Error(`Server does not support tools (required for ${method})`);
|
|
2883
|
+
break;
|
|
2884
|
+
case "completion/complete":
|
|
2885
|
+
if (!this._serverCapabilities?.completions) throw new Error(`Server does not support completions (required for ${method})`);
|
|
2886
|
+
break;
|
|
2887
|
+
case "initialize": break;
|
|
2888
|
+
case "ping": break;
|
|
2889
|
+
}
|
|
2890
|
+
}
|
|
2891
|
+
assertNotificationCapability(method) {
|
|
2892
|
+
switch (method) {
|
|
2893
|
+
case "notifications/roots/list_changed":
|
|
2894
|
+
if (!this._capabilities.roots?.listChanged) throw new Error(`Client does not support roots list changed notifications (required for ${method})`);
|
|
2895
|
+
break;
|
|
2896
|
+
case "notifications/initialized": break;
|
|
2897
|
+
case "notifications/cancelled": break;
|
|
2898
|
+
case "notifications/progress": break;
|
|
2899
|
+
}
|
|
2900
|
+
}
|
|
2901
|
+
assertRequestHandlerCapability(method) {
|
|
2902
|
+
if (!this._capabilities) return;
|
|
2903
|
+
switch (method) {
|
|
2904
|
+
case "sampling/createMessage":
|
|
2905
|
+
if (!this._capabilities.sampling) throw new Error(`Client does not support sampling capability (required for ${method})`);
|
|
2906
|
+
break;
|
|
2907
|
+
case "elicitation/create":
|
|
2908
|
+
if (!this._capabilities.elicitation) throw new Error(`Client does not support elicitation capability (required for ${method})`);
|
|
2909
|
+
break;
|
|
2910
|
+
case "roots/list":
|
|
2911
|
+
if (!this._capabilities.roots) throw new Error(`Client does not support roots capability (required for ${method})`);
|
|
2912
|
+
break;
|
|
2913
|
+
case "tasks/get":
|
|
2914
|
+
case "tasks/list":
|
|
2915
|
+
case "tasks/result":
|
|
2916
|
+
case "tasks/cancel":
|
|
2917
|
+
if (!this._capabilities.tasks) throw new Error(`Client does not support tasks capability (required for ${method})`);
|
|
2918
|
+
break;
|
|
2919
|
+
case "ping": break;
|
|
2920
|
+
}
|
|
2921
|
+
}
|
|
2922
|
+
assertTaskCapability(method) {
|
|
2923
|
+
assertToolsCallTaskCapability(this._serverCapabilities?.tasks?.requests, method, "Server");
|
|
2924
|
+
}
|
|
2925
|
+
assertTaskHandlerCapability(method) {
|
|
2926
|
+
if (!this._capabilities) return;
|
|
2927
|
+
assertClientRequestTaskCapability(this._capabilities.tasks?.requests, method, "Client");
|
|
2928
|
+
}
|
|
2929
|
+
async ping(options) {
|
|
2930
|
+
return this.request({ method: "ping" }, EmptyResultSchema, options);
|
|
2931
|
+
}
|
|
2932
|
+
async complete(params, options) {
|
|
2933
|
+
return this.request({
|
|
2934
|
+
method: "completion/complete",
|
|
2935
|
+
params
|
|
2936
|
+
}, CompleteResultSchema, options);
|
|
2937
|
+
}
|
|
2938
|
+
async setLoggingLevel(level, options) {
|
|
2939
|
+
return this.request({
|
|
2940
|
+
method: "logging/setLevel",
|
|
2941
|
+
params: { level }
|
|
2942
|
+
}, EmptyResultSchema, options);
|
|
2943
|
+
}
|
|
2944
|
+
async getPrompt(params, options) {
|
|
2945
|
+
return this.request({
|
|
2946
|
+
method: "prompts/get",
|
|
2947
|
+
params
|
|
2948
|
+
}, GetPromptResultSchema, options);
|
|
2949
|
+
}
|
|
2950
|
+
async listPrompts(params, options) {
|
|
2951
|
+
return this.request({
|
|
2952
|
+
method: "prompts/list",
|
|
2953
|
+
params
|
|
2954
|
+
}, ListPromptsResultSchema, options);
|
|
2955
|
+
}
|
|
2956
|
+
async listResources(params, options) {
|
|
2957
|
+
return this.request({
|
|
2958
|
+
method: "resources/list",
|
|
2959
|
+
params
|
|
2960
|
+
}, ListResourcesResultSchema, options);
|
|
2961
|
+
}
|
|
2962
|
+
async listResourceTemplates(params, options) {
|
|
2963
|
+
return this.request({
|
|
2964
|
+
method: "resources/templates/list",
|
|
2965
|
+
params
|
|
2966
|
+
}, ListResourceTemplatesResultSchema, options);
|
|
2967
|
+
}
|
|
2968
|
+
async readResource(params, options) {
|
|
2969
|
+
return this.request({
|
|
2970
|
+
method: "resources/read",
|
|
2971
|
+
params
|
|
2972
|
+
}, ReadResourceResultSchema, options);
|
|
2973
|
+
}
|
|
2974
|
+
async subscribeResource(params, options) {
|
|
2975
|
+
return this.request({
|
|
2976
|
+
method: "resources/subscribe",
|
|
2977
|
+
params
|
|
2978
|
+
}, EmptyResultSchema, options);
|
|
2979
|
+
}
|
|
2980
|
+
async unsubscribeResource(params, options) {
|
|
2981
|
+
return this.request({
|
|
2982
|
+
method: "resources/unsubscribe",
|
|
2983
|
+
params
|
|
2984
|
+
}, EmptyResultSchema, options);
|
|
2985
|
+
}
|
|
2986
|
+
/**
|
|
2987
|
+
* Calls a tool and waits for the result. Automatically validates structured output if the tool has an outputSchema.
|
|
2988
|
+
*
|
|
2989
|
+
* For task-based execution with streaming behavior, use client.experimental.tasks.callToolStream() instead.
|
|
2990
|
+
*/
|
|
2991
|
+
async callTool(params, resultSchema = CallToolResultSchema, options) {
|
|
2992
|
+
if (this.isToolTaskRequired(params.name)) throw new McpError(ErrorCode.InvalidRequest, `Tool "${params.name}" requires task-based execution. Use client.experimental.tasks.callToolStream() instead.`);
|
|
2993
|
+
const result = await this.request({
|
|
2994
|
+
method: "tools/call",
|
|
2995
|
+
params
|
|
2996
|
+
}, resultSchema, options);
|
|
2997
|
+
const validator = this.getToolOutputValidator(params.name);
|
|
2998
|
+
if (validator) {
|
|
2999
|
+
if (!result.structuredContent && !result.isError) throw new McpError(ErrorCode.InvalidRequest, `Tool ${params.name} has an output schema but did not return structured content`);
|
|
3000
|
+
if (result.structuredContent) try {
|
|
3001
|
+
const validationResult = validator(result.structuredContent);
|
|
3002
|
+
if (!validationResult.valid) throw new McpError(ErrorCode.InvalidParams, `Structured content does not match the tool's output schema: ${validationResult.errorMessage}`);
|
|
3003
|
+
} catch (error) {
|
|
3004
|
+
if (error instanceof McpError) throw error;
|
|
3005
|
+
throw new McpError(ErrorCode.InvalidParams, `Failed to validate structured content: ${error instanceof Error ? error.message : String(error)}`);
|
|
3006
|
+
}
|
|
3007
|
+
}
|
|
3008
|
+
return result;
|
|
3009
|
+
}
|
|
3010
|
+
isToolTask(toolName) {
|
|
3011
|
+
if (!this._serverCapabilities?.tasks?.requests?.tools?.call) return false;
|
|
3012
|
+
return this._cachedKnownTaskTools.has(toolName);
|
|
3013
|
+
}
|
|
3014
|
+
/**
|
|
3015
|
+
* Check if a tool requires task-based execution.
|
|
3016
|
+
* Unlike isToolTask which includes 'optional' tools, this only checks for 'required'.
|
|
3017
|
+
*/
|
|
3018
|
+
isToolTaskRequired(toolName) {
|
|
3019
|
+
return this._cachedRequiredTaskTools.has(toolName);
|
|
3020
|
+
}
|
|
3021
|
+
/**
|
|
3022
|
+
* Cache validators for tool output schemas.
|
|
3023
|
+
* Called after listTools() to pre-compile validators for better performance.
|
|
3024
|
+
*/
|
|
3025
|
+
cacheToolMetadata(tools) {
|
|
3026
|
+
this._cachedToolOutputValidators.clear();
|
|
3027
|
+
this._cachedKnownTaskTools.clear();
|
|
3028
|
+
this._cachedRequiredTaskTools.clear();
|
|
3029
|
+
for (const tool of tools) {
|
|
3030
|
+
if (tool.outputSchema) {
|
|
3031
|
+
const toolValidator = this._jsonSchemaValidator.getValidator(tool.outputSchema);
|
|
3032
|
+
this._cachedToolOutputValidators.set(tool.name, toolValidator);
|
|
3033
|
+
}
|
|
3034
|
+
const taskSupport = tool.execution?.taskSupport;
|
|
3035
|
+
if (taskSupport === "required" || taskSupport === "optional") this._cachedKnownTaskTools.add(tool.name);
|
|
3036
|
+
if (taskSupport === "required") this._cachedRequiredTaskTools.add(tool.name);
|
|
3037
|
+
}
|
|
3038
|
+
}
|
|
3039
|
+
/**
|
|
3040
|
+
* Get cached validator for a tool
|
|
3041
|
+
*/
|
|
3042
|
+
getToolOutputValidator(toolName) {
|
|
3043
|
+
return this._cachedToolOutputValidators.get(toolName);
|
|
3044
|
+
}
|
|
3045
|
+
async listTools(params, options) {
|
|
3046
|
+
const result = await this.request({
|
|
3047
|
+
method: "tools/list",
|
|
3048
|
+
params
|
|
3049
|
+
}, ListToolsResultSchema, options);
|
|
3050
|
+
this.cacheToolMetadata(result.tools);
|
|
3051
|
+
return result;
|
|
3052
|
+
}
|
|
3053
|
+
/**
|
|
3054
|
+
* Set up a single list changed handler.
|
|
3055
|
+
* @internal
|
|
3056
|
+
*/
|
|
3057
|
+
_setupListChangedHandler(listType, notificationSchema, options, fetcher) {
|
|
3058
|
+
const parseResult = ListChangedOptionsBaseSchema.safeParse(options);
|
|
3059
|
+
if (!parseResult.success) throw new Error(`Invalid ${listType} listChanged options: ${parseResult.error.message}`);
|
|
3060
|
+
if (typeof options.onChanged !== "function") throw new Error(`Invalid ${listType} listChanged options: onChanged must be a function`);
|
|
3061
|
+
const { autoRefresh, debounceMs } = parseResult.data;
|
|
3062
|
+
const { onChanged } = options;
|
|
3063
|
+
const refresh = async () => {
|
|
3064
|
+
if (!autoRefresh) {
|
|
3065
|
+
onChanged(null, null);
|
|
3066
|
+
return;
|
|
3067
|
+
}
|
|
3068
|
+
try {
|
|
3069
|
+
onChanged(null, await fetcher());
|
|
3070
|
+
} catch (e) {
|
|
3071
|
+
onChanged(e instanceof Error ? e : new Error(String(e)), null);
|
|
3072
|
+
}
|
|
3073
|
+
};
|
|
3074
|
+
const handler = () => {
|
|
3075
|
+
if (debounceMs) {
|
|
3076
|
+
const existingTimer = this._listChangedDebounceTimers.get(listType);
|
|
3077
|
+
if (existingTimer) clearTimeout(existingTimer);
|
|
3078
|
+
const timer = setTimeout(refresh, debounceMs);
|
|
3079
|
+
this._listChangedDebounceTimers.set(listType, timer);
|
|
3080
|
+
} else refresh();
|
|
3081
|
+
};
|
|
3082
|
+
this.setNotificationHandler(notificationSchema, handler);
|
|
3083
|
+
}
|
|
3084
|
+
async sendRootsListChanged() {
|
|
3085
|
+
return this.notification({ method: "notifications/roots/list_changed" });
|
|
3086
|
+
}
|
|
3087
|
+
};
|
|
3088
|
+
|
|
3089
|
+
//#endregion
|
|
3090
|
+
//#region ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.26.0_@cfworker+json-schema@4.1.1_zod@4.3.5/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
|
|
3091
|
+
/**
|
|
3092
|
+
* Buffers a continuous stdio stream into discrete JSON-RPC messages.
|
|
3093
|
+
*/
|
|
3094
|
+
var ReadBuffer = class {
|
|
3095
|
+
append(chunk) {
|
|
3096
|
+
this._buffer = this._buffer ? Buffer.concat([this._buffer, chunk]) : chunk;
|
|
3097
|
+
}
|
|
3098
|
+
readMessage() {
|
|
3099
|
+
if (!this._buffer) return null;
|
|
3100
|
+
const index = this._buffer.indexOf("\n");
|
|
3101
|
+
if (index === -1) return null;
|
|
3102
|
+
const line = this._buffer.toString("utf8", 0, index).replace(/\r$/, "");
|
|
3103
|
+
this._buffer = this._buffer.subarray(index + 1);
|
|
3104
|
+
return deserializeMessage(line);
|
|
3105
|
+
}
|
|
3106
|
+
clear() {
|
|
3107
|
+
this._buffer = void 0;
|
|
3108
|
+
}
|
|
3109
|
+
};
|
|
3110
|
+
function deserializeMessage(line) {
|
|
3111
|
+
return JSONRPCMessageSchema.parse(JSON.parse(line));
|
|
3112
|
+
}
|
|
3113
|
+
function serializeMessage(message) {
|
|
3114
|
+
return JSON.stringify(message) + "\n";
|
|
3115
|
+
}
|
|
3116
|
+
|
|
3117
|
+
//#endregion
|
|
3118
|
+
//#region ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.26.0_@cfworker+json-schema@4.1.1_zod@4.3.5/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/server.js
|
|
3119
|
+
/**
|
|
3120
|
+
* Experimental server task features for MCP SDK.
|
|
3121
|
+
* WARNING: These APIs are experimental and may change without notice.
|
|
3122
|
+
*
|
|
3123
|
+
* @experimental
|
|
3124
|
+
*/
|
|
3125
|
+
/**
|
|
3126
|
+
* Experimental task features for low-level MCP servers.
|
|
3127
|
+
*
|
|
3128
|
+
* Access via `server.experimental.tasks`:
|
|
3129
|
+
* ```typescript
|
|
3130
|
+
* const stream = server.experimental.tasks.requestStream(request, schema, options);
|
|
3131
|
+
* ```
|
|
3132
|
+
*
|
|
3133
|
+
* For high-level server usage with task-based tools, use `McpServer.experimental.tasks` instead.
|
|
3134
|
+
*
|
|
3135
|
+
* @experimental
|
|
3136
|
+
*/
|
|
3137
|
+
var ExperimentalServerTasks = class {
|
|
3138
|
+
constructor(_server) {
|
|
3139
|
+
this._server = _server;
|
|
3140
|
+
}
|
|
3141
|
+
/**
|
|
3142
|
+
* Sends a request and returns an AsyncGenerator that yields response messages.
|
|
3143
|
+
* The generator is guaranteed to end with either a 'result' or 'error' message.
|
|
3144
|
+
*
|
|
3145
|
+
* This method provides streaming access to request processing, allowing you to
|
|
3146
|
+
* observe intermediate task status updates for task-augmented requests.
|
|
3147
|
+
*
|
|
3148
|
+
* @param request - The request to send
|
|
3149
|
+
* @param resultSchema - Zod schema for validating the result
|
|
3150
|
+
* @param options - Optional request options (timeout, signal, task creation params, etc.)
|
|
3151
|
+
* @returns AsyncGenerator that yields ResponseMessage objects
|
|
3152
|
+
*
|
|
3153
|
+
* @experimental
|
|
3154
|
+
*/
|
|
3155
|
+
requestStream(request, resultSchema, options) {
|
|
3156
|
+
return this._server.requestStream(request, resultSchema, options);
|
|
3157
|
+
}
|
|
3158
|
+
/**
|
|
3159
|
+
* Gets the current status of a task.
|
|
3160
|
+
*
|
|
3161
|
+
* @param taskId - The task identifier
|
|
3162
|
+
* @param options - Optional request options
|
|
3163
|
+
* @returns The task status
|
|
3164
|
+
*
|
|
3165
|
+
* @experimental
|
|
3166
|
+
*/
|
|
3167
|
+
async getTask(taskId, options) {
|
|
3168
|
+
return this._server.getTask({ taskId }, options);
|
|
3169
|
+
}
|
|
3170
|
+
/**
|
|
3171
|
+
* Retrieves the result of a completed task.
|
|
3172
|
+
*
|
|
3173
|
+
* @param taskId - The task identifier
|
|
3174
|
+
* @param resultSchema - Zod schema for validating the result
|
|
3175
|
+
* @param options - Optional request options
|
|
3176
|
+
* @returns The task result
|
|
3177
|
+
*
|
|
3178
|
+
* @experimental
|
|
3179
|
+
*/
|
|
3180
|
+
async getTaskResult(taskId, resultSchema, options) {
|
|
3181
|
+
return this._server.getTaskResult({ taskId }, resultSchema, options);
|
|
3182
|
+
}
|
|
3183
|
+
/**
|
|
3184
|
+
* Lists tasks with optional pagination.
|
|
3185
|
+
*
|
|
3186
|
+
* @param cursor - Optional pagination cursor
|
|
3187
|
+
* @param options - Optional request options
|
|
3188
|
+
* @returns List of tasks with optional next cursor
|
|
3189
|
+
*
|
|
3190
|
+
* @experimental
|
|
3191
|
+
*/
|
|
3192
|
+
async listTasks(cursor, options) {
|
|
3193
|
+
return this._server.listTasks(cursor ? { cursor } : void 0, options);
|
|
3194
|
+
}
|
|
3195
|
+
/**
|
|
3196
|
+
* Cancels a running task.
|
|
3197
|
+
*
|
|
3198
|
+
* @param taskId - The task identifier
|
|
3199
|
+
* @param options - Optional request options
|
|
3200
|
+
*
|
|
3201
|
+
* @experimental
|
|
3202
|
+
*/
|
|
3203
|
+
async cancelTask(taskId, options) {
|
|
3204
|
+
return this._server.cancelTask({ taskId }, options);
|
|
3205
|
+
}
|
|
3206
|
+
};
|
|
3207
|
+
|
|
3208
|
+
//#endregion
|
|
3209
|
+
//#region ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.26.0_@cfworker+json-schema@4.1.1_zod@4.3.5/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js
|
|
3210
|
+
/**
|
|
3211
|
+
* An MCP server on top of a pluggable transport.
|
|
3212
|
+
*
|
|
3213
|
+
* This server will automatically respond to the initialization flow as initiated from the client.
|
|
3214
|
+
*
|
|
3215
|
+
* To use with custom types, extend the base Request/Notification/Result types and pass them as type parameters:
|
|
3216
|
+
*
|
|
3217
|
+
* ```typescript
|
|
3218
|
+
* // Custom schemas
|
|
3219
|
+
* const CustomRequestSchema = RequestSchema.extend({...})
|
|
3220
|
+
* const CustomNotificationSchema = NotificationSchema.extend({...})
|
|
3221
|
+
* const CustomResultSchema = ResultSchema.extend({...})
|
|
3222
|
+
*
|
|
3223
|
+
* // Type aliases
|
|
3224
|
+
* type CustomRequest = z.infer<typeof CustomRequestSchema>
|
|
3225
|
+
* type CustomNotification = z.infer<typeof CustomNotificationSchema>
|
|
3226
|
+
* type CustomResult = z.infer<typeof CustomResultSchema>
|
|
3227
|
+
*
|
|
3228
|
+
* // Create typed server
|
|
3229
|
+
* const server = new Server<CustomRequest, CustomNotification, CustomResult>({
|
|
3230
|
+
* name: "CustomServer",
|
|
3231
|
+
* version: "1.0.0"
|
|
3232
|
+
* })
|
|
3233
|
+
* ```
|
|
3234
|
+
* @deprecated Use `McpServer` instead for the high-level API. Only use `Server` for advanced use cases.
|
|
3235
|
+
*/
|
|
3236
|
+
var Server = class extends Protocol {
|
|
3237
|
+
/**
|
|
3238
|
+
* Initializes this server with the given name and version information.
|
|
3239
|
+
*/
|
|
3240
|
+
constructor(_serverInfo, options) {
|
|
3241
|
+
super(options);
|
|
3242
|
+
this._serverInfo = _serverInfo;
|
|
3243
|
+
this._loggingLevels = /* @__PURE__ */ new Map();
|
|
3244
|
+
this.LOG_LEVEL_SEVERITY = new Map(LoggingLevelSchema.options.map((level, index) => [level, index]));
|
|
3245
|
+
this.isMessageIgnored = (level, sessionId) => {
|
|
3246
|
+
const currentLevel = this._loggingLevels.get(sessionId);
|
|
3247
|
+
return currentLevel ? this.LOG_LEVEL_SEVERITY.get(level) < this.LOG_LEVEL_SEVERITY.get(currentLevel) : false;
|
|
3248
|
+
};
|
|
3249
|
+
this._capabilities = options?.capabilities ?? {};
|
|
3250
|
+
this._instructions = options?.instructions;
|
|
3251
|
+
this._jsonSchemaValidator = options?.jsonSchemaValidator ?? new AjvJsonSchemaValidator();
|
|
3252
|
+
this.setRequestHandler(InitializeRequestSchema, (request) => this._oninitialize(request));
|
|
3253
|
+
this.setNotificationHandler(InitializedNotificationSchema, () => this.oninitialized?.());
|
|
3254
|
+
if (this._capabilities.logging) this.setRequestHandler(SetLevelRequestSchema, async (request, extra) => {
|
|
3255
|
+
const transportSessionId = extra.sessionId || extra.requestInfo?.headers["mcp-session-id"] || void 0;
|
|
3256
|
+
const { level } = request.params;
|
|
3257
|
+
const parseResult = LoggingLevelSchema.safeParse(level);
|
|
3258
|
+
if (parseResult.success) this._loggingLevels.set(transportSessionId, parseResult.data);
|
|
3259
|
+
return {};
|
|
3260
|
+
});
|
|
3261
|
+
}
|
|
3262
|
+
/**
|
|
3263
|
+
* Access experimental features.
|
|
3264
|
+
*
|
|
3265
|
+
* WARNING: These APIs are experimental and may change without notice.
|
|
3266
|
+
*
|
|
3267
|
+
* @experimental
|
|
3268
|
+
*/
|
|
3269
|
+
get experimental() {
|
|
3270
|
+
if (!this._experimental) this._experimental = { tasks: new ExperimentalServerTasks(this) };
|
|
3271
|
+
return this._experimental;
|
|
3272
|
+
}
|
|
3273
|
+
/**
|
|
3274
|
+
* Registers new capabilities. This can only be called before connecting to a transport.
|
|
3275
|
+
*
|
|
3276
|
+
* The new capabilities will be merged with any existing capabilities previously given (e.g., at initialization).
|
|
3277
|
+
*/
|
|
3278
|
+
registerCapabilities(capabilities) {
|
|
3279
|
+
if (this.transport) throw new Error("Cannot register capabilities after connecting to transport");
|
|
3280
|
+
this._capabilities = mergeCapabilities(this._capabilities, capabilities);
|
|
3281
|
+
}
|
|
3282
|
+
/**
|
|
3283
|
+
* Override request handler registration to enforce server-side validation for tools/call.
|
|
3284
|
+
*/
|
|
3285
|
+
setRequestHandler(requestSchema, handler) {
|
|
3286
|
+
const methodSchema = getObjectShape(requestSchema)?.method;
|
|
3287
|
+
if (!methodSchema) throw new Error("Schema is missing a method literal");
|
|
3288
|
+
let methodValue;
|
|
3289
|
+
if (isZ4Schema(methodSchema)) {
|
|
3290
|
+
const v4Schema = methodSchema;
|
|
3291
|
+
methodValue = (v4Schema._zod?.def)?.value ?? v4Schema.value;
|
|
3292
|
+
} else {
|
|
3293
|
+
const v3Schema = methodSchema;
|
|
3294
|
+
methodValue = v3Schema._def?.value ?? v3Schema.value;
|
|
3295
|
+
}
|
|
3296
|
+
if (typeof methodValue !== "string") throw new Error("Schema method literal must be a string");
|
|
3297
|
+
if (methodValue === "tools/call") {
|
|
3298
|
+
const wrappedHandler = async (request, extra) => {
|
|
3299
|
+
const validatedRequest = safeParse(CallToolRequestSchema, request);
|
|
3300
|
+
if (!validatedRequest.success) {
|
|
3301
|
+
const errorMessage = validatedRequest.error instanceof Error ? validatedRequest.error.message : String(validatedRequest.error);
|
|
3302
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid tools/call request: ${errorMessage}`);
|
|
3303
|
+
}
|
|
3304
|
+
const { params } = validatedRequest.data;
|
|
3305
|
+
const result = await Promise.resolve(handler(request, extra));
|
|
3306
|
+
if (params.task) {
|
|
3307
|
+
const taskValidationResult = safeParse(CreateTaskResultSchema, result);
|
|
3308
|
+
if (!taskValidationResult.success) {
|
|
3309
|
+
const errorMessage = taskValidationResult.error instanceof Error ? taskValidationResult.error.message : String(taskValidationResult.error);
|
|
3310
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid task creation result: ${errorMessage}`);
|
|
3311
|
+
}
|
|
3312
|
+
return taskValidationResult.data;
|
|
3313
|
+
}
|
|
3314
|
+
const validationResult = safeParse(CallToolResultSchema, result);
|
|
3315
|
+
if (!validationResult.success) {
|
|
3316
|
+
const errorMessage = validationResult.error instanceof Error ? validationResult.error.message : String(validationResult.error);
|
|
3317
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid tools/call result: ${errorMessage}`);
|
|
3318
|
+
}
|
|
3319
|
+
return validationResult.data;
|
|
3320
|
+
};
|
|
3321
|
+
return super.setRequestHandler(requestSchema, wrappedHandler);
|
|
3322
|
+
}
|
|
3323
|
+
return super.setRequestHandler(requestSchema, handler);
|
|
3324
|
+
}
|
|
3325
|
+
assertCapabilityForMethod(method) {
|
|
3326
|
+
switch (method) {
|
|
3327
|
+
case "sampling/createMessage":
|
|
3328
|
+
if (!this._clientCapabilities?.sampling) throw new Error(`Client does not support sampling (required for ${method})`);
|
|
3329
|
+
break;
|
|
3330
|
+
case "elicitation/create":
|
|
3331
|
+
if (!this._clientCapabilities?.elicitation) throw new Error(`Client does not support elicitation (required for ${method})`);
|
|
3332
|
+
break;
|
|
3333
|
+
case "roots/list":
|
|
3334
|
+
if (!this._clientCapabilities?.roots) throw new Error(`Client does not support listing roots (required for ${method})`);
|
|
3335
|
+
break;
|
|
3336
|
+
case "ping": break;
|
|
3337
|
+
}
|
|
3338
|
+
}
|
|
3339
|
+
assertNotificationCapability(method) {
|
|
3340
|
+
switch (method) {
|
|
3341
|
+
case "notifications/message":
|
|
3342
|
+
if (!this._capabilities.logging) throw new Error(`Server does not support logging (required for ${method})`);
|
|
3343
|
+
break;
|
|
3344
|
+
case "notifications/resources/updated":
|
|
3345
|
+
case "notifications/resources/list_changed":
|
|
3346
|
+
if (!this._capabilities.resources) throw new Error(`Server does not support notifying about resources (required for ${method})`);
|
|
3347
|
+
break;
|
|
3348
|
+
case "notifications/tools/list_changed":
|
|
3349
|
+
if (!this._capabilities.tools) throw new Error(`Server does not support notifying of tool list changes (required for ${method})`);
|
|
3350
|
+
break;
|
|
3351
|
+
case "notifications/prompts/list_changed":
|
|
3352
|
+
if (!this._capabilities.prompts) throw new Error(`Server does not support notifying of prompt list changes (required for ${method})`);
|
|
3353
|
+
break;
|
|
3354
|
+
case "notifications/elicitation/complete":
|
|
3355
|
+
if (!this._clientCapabilities?.elicitation?.url) throw new Error(`Client does not support URL elicitation (required for ${method})`);
|
|
3356
|
+
break;
|
|
3357
|
+
case "notifications/cancelled": break;
|
|
3358
|
+
case "notifications/progress": break;
|
|
3359
|
+
}
|
|
3360
|
+
}
|
|
3361
|
+
assertRequestHandlerCapability(method) {
|
|
3362
|
+
if (!this._capabilities) return;
|
|
3363
|
+
switch (method) {
|
|
3364
|
+
case "completion/complete":
|
|
3365
|
+
if (!this._capabilities.completions) throw new Error(`Server does not support completions (required for ${method})`);
|
|
3366
|
+
break;
|
|
3367
|
+
case "logging/setLevel":
|
|
3368
|
+
if (!this._capabilities.logging) throw new Error(`Server does not support logging (required for ${method})`);
|
|
3369
|
+
break;
|
|
3370
|
+
case "prompts/get":
|
|
3371
|
+
case "prompts/list":
|
|
3372
|
+
if (!this._capabilities.prompts) throw new Error(`Server does not support prompts (required for ${method})`);
|
|
3373
|
+
break;
|
|
3374
|
+
case "resources/list":
|
|
3375
|
+
case "resources/templates/list":
|
|
3376
|
+
case "resources/read":
|
|
3377
|
+
if (!this._capabilities.resources) throw new Error(`Server does not support resources (required for ${method})`);
|
|
3378
|
+
break;
|
|
3379
|
+
case "tools/call":
|
|
3380
|
+
case "tools/list":
|
|
3381
|
+
if (!this._capabilities.tools) throw new Error(`Server does not support tools (required for ${method})`);
|
|
3382
|
+
break;
|
|
3383
|
+
case "tasks/get":
|
|
3384
|
+
case "tasks/list":
|
|
3385
|
+
case "tasks/result":
|
|
3386
|
+
case "tasks/cancel":
|
|
3387
|
+
if (!this._capabilities.tasks) throw new Error(`Server does not support tasks capability (required for ${method})`);
|
|
3388
|
+
break;
|
|
3389
|
+
case "ping":
|
|
3390
|
+
case "initialize": break;
|
|
3391
|
+
}
|
|
3392
|
+
}
|
|
3393
|
+
assertTaskCapability(method) {
|
|
3394
|
+
assertClientRequestTaskCapability(this._clientCapabilities?.tasks?.requests, method, "Client");
|
|
3395
|
+
}
|
|
3396
|
+
assertTaskHandlerCapability(method) {
|
|
3397
|
+
if (!this._capabilities) return;
|
|
3398
|
+
assertToolsCallTaskCapability(this._capabilities.tasks?.requests, method, "Server");
|
|
3399
|
+
}
|
|
3400
|
+
async _oninitialize(request) {
|
|
3401
|
+
const requestedVersion = request.params.protocolVersion;
|
|
3402
|
+
this._clientCapabilities = request.params.capabilities;
|
|
3403
|
+
this._clientVersion = request.params.clientInfo;
|
|
3404
|
+
return {
|
|
3405
|
+
protocolVersion: SUPPORTED_PROTOCOL_VERSIONS.includes(requestedVersion) ? requestedVersion : LATEST_PROTOCOL_VERSION,
|
|
3406
|
+
capabilities: this.getCapabilities(),
|
|
3407
|
+
serverInfo: this._serverInfo,
|
|
3408
|
+
...this._instructions && { instructions: this._instructions }
|
|
3409
|
+
};
|
|
3410
|
+
}
|
|
3411
|
+
/**
|
|
3412
|
+
* After initialization has completed, this will be populated with the client's reported capabilities.
|
|
3413
|
+
*/
|
|
3414
|
+
getClientCapabilities() {
|
|
3415
|
+
return this._clientCapabilities;
|
|
3416
|
+
}
|
|
3417
|
+
/**
|
|
3418
|
+
* After initialization has completed, this will be populated with information about the client's name and version.
|
|
3419
|
+
*/
|
|
3420
|
+
getClientVersion() {
|
|
3421
|
+
return this._clientVersion;
|
|
3422
|
+
}
|
|
3423
|
+
getCapabilities() {
|
|
3424
|
+
return this._capabilities;
|
|
3425
|
+
}
|
|
3426
|
+
async ping() {
|
|
3427
|
+
return this.request({ method: "ping" }, EmptyResultSchema);
|
|
3428
|
+
}
|
|
3429
|
+
async createMessage(params, options) {
|
|
3430
|
+
if (params.tools || params.toolChoice) {
|
|
3431
|
+
if (!this._clientCapabilities?.sampling?.tools) throw new Error("Client does not support sampling tools capability.");
|
|
3432
|
+
}
|
|
3433
|
+
if (params.messages.length > 0) {
|
|
3434
|
+
const lastMessage = params.messages[params.messages.length - 1];
|
|
3435
|
+
const lastContent = Array.isArray(lastMessage.content) ? lastMessage.content : [lastMessage.content];
|
|
3436
|
+
const hasToolResults = lastContent.some((c) => c.type === "tool_result");
|
|
3437
|
+
const previousMessage = params.messages.length > 1 ? params.messages[params.messages.length - 2] : void 0;
|
|
3438
|
+
const previousContent = previousMessage ? Array.isArray(previousMessage.content) ? previousMessage.content : [previousMessage.content] : [];
|
|
3439
|
+
const hasPreviousToolUse = previousContent.some((c) => c.type === "tool_use");
|
|
3440
|
+
if (hasToolResults) {
|
|
3441
|
+
if (lastContent.some((c) => c.type !== "tool_result")) throw new Error("The last message must contain only tool_result content if any is present");
|
|
3442
|
+
if (!hasPreviousToolUse) throw new Error("tool_result blocks are not matching any tool_use from the previous message");
|
|
3443
|
+
}
|
|
3444
|
+
if (hasPreviousToolUse) {
|
|
3445
|
+
const toolUseIds = new Set(previousContent.filter((c) => c.type === "tool_use").map((c) => c.id));
|
|
3446
|
+
const toolResultIds = new Set(lastContent.filter((c) => c.type === "tool_result").map((c) => c.toolUseId));
|
|
3447
|
+
if (toolUseIds.size !== toolResultIds.size || ![...toolUseIds].every((id) => toolResultIds.has(id))) throw new Error("ids of tool_result blocks and tool_use blocks from previous message do not match");
|
|
3448
|
+
}
|
|
3449
|
+
}
|
|
3450
|
+
if (params.tools) return this.request({
|
|
3451
|
+
method: "sampling/createMessage",
|
|
3452
|
+
params
|
|
3453
|
+
}, CreateMessageResultWithToolsSchema, options);
|
|
3454
|
+
return this.request({
|
|
3455
|
+
method: "sampling/createMessage",
|
|
3456
|
+
params
|
|
3457
|
+
}, CreateMessageResultSchema, options);
|
|
3458
|
+
}
|
|
3459
|
+
/**
|
|
3460
|
+
* Creates an elicitation request for the given parameters.
|
|
3461
|
+
* For backwards compatibility, `mode` may be omitted for form requests and will default to `'form'`.
|
|
3462
|
+
* @param params The parameters for the elicitation request.
|
|
3463
|
+
* @param options Optional request options.
|
|
3464
|
+
* @returns The result of the elicitation request.
|
|
3465
|
+
*/
|
|
3466
|
+
async elicitInput(params, options) {
|
|
3467
|
+
switch (params.mode ?? "form") {
|
|
3468
|
+
case "url": {
|
|
3469
|
+
if (!this._clientCapabilities?.elicitation?.url) throw new Error("Client does not support url elicitation.");
|
|
3470
|
+
const urlParams = params;
|
|
3471
|
+
return this.request({
|
|
3472
|
+
method: "elicitation/create",
|
|
3473
|
+
params: urlParams
|
|
3474
|
+
}, ElicitResultSchema, options);
|
|
3475
|
+
}
|
|
3476
|
+
case "form": {
|
|
3477
|
+
if (!this._clientCapabilities?.elicitation?.form) throw new Error("Client does not support form elicitation.");
|
|
3478
|
+
const formParams = params.mode === "form" ? params : {
|
|
3479
|
+
...params,
|
|
3480
|
+
mode: "form"
|
|
3481
|
+
};
|
|
3482
|
+
const result = await this.request({
|
|
3483
|
+
method: "elicitation/create",
|
|
3484
|
+
params: formParams
|
|
3485
|
+
}, ElicitResultSchema, options);
|
|
3486
|
+
if (result.action === "accept" && result.content && formParams.requestedSchema) try {
|
|
3487
|
+
const validationResult = this._jsonSchemaValidator.getValidator(formParams.requestedSchema)(result.content);
|
|
3488
|
+
if (!validationResult.valid) throw new McpError(ErrorCode.InvalidParams, `Elicitation response content does not match requested schema: ${validationResult.errorMessage}`);
|
|
3489
|
+
} catch (error) {
|
|
3490
|
+
if (error instanceof McpError) throw error;
|
|
3491
|
+
throw new McpError(ErrorCode.InternalError, `Error validating elicitation response: ${error instanceof Error ? error.message : String(error)}`);
|
|
3492
|
+
}
|
|
3493
|
+
return result;
|
|
3494
|
+
}
|
|
3495
|
+
}
|
|
3496
|
+
}
|
|
3497
|
+
/**
|
|
3498
|
+
* Creates a reusable callback that, when invoked, will send a `notifications/elicitation/complete`
|
|
3499
|
+
* notification for the specified elicitation ID.
|
|
3500
|
+
*
|
|
3501
|
+
* @param elicitationId The ID of the elicitation to mark as complete.
|
|
3502
|
+
* @param options Optional notification options. Useful when the completion notification should be related to a prior request.
|
|
3503
|
+
* @returns A function that emits the completion notification when awaited.
|
|
3504
|
+
*/
|
|
3505
|
+
createElicitationCompletionNotifier(elicitationId, options) {
|
|
3506
|
+
if (!this._clientCapabilities?.elicitation?.url) throw new Error("Client does not support URL elicitation (required for notifications/elicitation/complete)");
|
|
3507
|
+
return () => this.notification({
|
|
3508
|
+
method: "notifications/elicitation/complete",
|
|
3509
|
+
params: { elicitationId }
|
|
3510
|
+
}, options);
|
|
3511
|
+
}
|
|
3512
|
+
async listRoots(params, options) {
|
|
3513
|
+
return this.request({
|
|
3514
|
+
method: "roots/list",
|
|
3515
|
+
params
|
|
3516
|
+
}, ListRootsResultSchema, options);
|
|
3517
|
+
}
|
|
3518
|
+
/**
|
|
3519
|
+
* Sends a logging message to the client, if connected.
|
|
3520
|
+
* Note: You only need to send the parameters object, not the entire JSON RPC message
|
|
3521
|
+
* @see LoggingMessageNotification
|
|
3522
|
+
* @param params
|
|
3523
|
+
* @param sessionId optional for stateless and backward compatibility
|
|
3524
|
+
*/
|
|
3525
|
+
async sendLoggingMessage(params, sessionId) {
|
|
3526
|
+
if (this._capabilities.logging) {
|
|
3527
|
+
if (!this.isMessageIgnored(params.level, sessionId)) return this.notification({
|
|
3528
|
+
method: "notifications/message",
|
|
3529
|
+
params
|
|
3530
|
+
});
|
|
3531
|
+
}
|
|
3532
|
+
}
|
|
3533
|
+
async sendResourceUpdated(params) {
|
|
3534
|
+
return this.notification({
|
|
3535
|
+
method: "notifications/resources/updated",
|
|
3536
|
+
params
|
|
3537
|
+
});
|
|
3538
|
+
}
|
|
3539
|
+
async sendResourceListChanged() {
|
|
3540
|
+
return this.notification({ method: "notifications/resources/list_changed" });
|
|
3541
|
+
}
|
|
3542
|
+
async sendToolListChanged() {
|
|
3543
|
+
return this.notification({ method: "notifications/tools/list_changed" });
|
|
3544
|
+
}
|
|
3545
|
+
async sendPromptListChanged() {
|
|
3546
|
+
return this.notification({ method: "notifications/prompts/list_changed" });
|
|
3547
|
+
}
|
|
3548
|
+
};
|
|
3549
|
+
|
|
3550
|
+
//#endregion
|
|
3551
|
+
//#region ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.26.0_@cfworker+json-schema@4.1.1_zod@4.3.5/node_modules/@modelcontextprotocol/sdk/dist/esm/server/completable.js
|
|
3552
|
+
const COMPLETABLE_SYMBOL = Symbol.for("mcp.completable");
|
|
9
3553
|
/**
|
|
10
|
-
*
|
|
3554
|
+
* Checks if a schema is completable (has completion metadata).
|
|
3555
|
+
*/
|
|
3556
|
+
function isCompletable(schema) {
|
|
3557
|
+
return !!schema && typeof schema === "object" && COMPLETABLE_SYMBOL in schema;
|
|
3558
|
+
}
|
|
3559
|
+
/**
|
|
3560
|
+
* Gets the completer callback from a completable schema, if it exists.
|
|
3561
|
+
*/
|
|
3562
|
+
function getCompleter(schema) {
|
|
3563
|
+
return schema[COMPLETABLE_SYMBOL]?.complete;
|
|
3564
|
+
}
|
|
3565
|
+
var McpZodTypeKind;
|
|
3566
|
+
(function(McpZodTypeKind$1) {
|
|
3567
|
+
McpZodTypeKind$1["Completable"] = "McpCompletable";
|
|
3568
|
+
})(McpZodTypeKind || (McpZodTypeKind = {}));
|
|
3569
|
+
|
|
3570
|
+
//#endregion
|
|
3571
|
+
//#region ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.26.0_@cfworker+json-schema@4.1.1_zod@4.3.5/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/toolNameValidation.js
|
|
3572
|
+
/**
|
|
3573
|
+
* Tool name validation utilities according to SEP: Specify Format for Tool Names
|
|
11
3574
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* -
|
|
3575
|
+
* Tool names SHOULD be between 1 and 128 characters in length (inclusive).
|
|
3576
|
+
* Tool names are case-sensitive.
|
|
3577
|
+
* Allowed characters: uppercase and lowercase ASCII letters (A-Z, a-z), digits
|
|
3578
|
+
* (0-9), underscore (_), dash (-), and dot (.).
|
|
3579
|
+
* Tool names SHOULD NOT contain spaces, commas, or other special characters.
|
|
3580
|
+
*/
|
|
3581
|
+
/**
|
|
3582
|
+
* Regular expression for valid tool names according to SEP-986 specification
|
|
3583
|
+
*/
|
|
3584
|
+
const TOOL_NAME_REGEX = /^[A-Za-z0-9._-]{1,128}$/;
|
|
3585
|
+
/**
|
|
3586
|
+
* Validates a tool name according to the SEP specification
|
|
3587
|
+
* @param name - The tool name to validate
|
|
3588
|
+
* @returns An object containing validation result and any warnings
|
|
3589
|
+
*/
|
|
3590
|
+
function validateToolName(name) {
|
|
3591
|
+
const warnings = [];
|
|
3592
|
+
if (name.length === 0) return {
|
|
3593
|
+
isValid: false,
|
|
3594
|
+
warnings: ["Tool name cannot be empty"]
|
|
3595
|
+
};
|
|
3596
|
+
if (name.length > 128) return {
|
|
3597
|
+
isValid: false,
|
|
3598
|
+
warnings: [`Tool name exceeds maximum length of 128 characters (current: ${name.length})`]
|
|
3599
|
+
};
|
|
3600
|
+
if (name.includes(" ")) warnings.push("Tool name contains spaces, which may cause parsing issues");
|
|
3601
|
+
if (name.includes(",")) warnings.push("Tool name contains commas, which may cause parsing issues");
|
|
3602
|
+
if (name.startsWith("-") || name.endsWith("-")) warnings.push("Tool name starts or ends with a dash, which may cause parsing issues in some contexts");
|
|
3603
|
+
if (name.startsWith(".") || name.endsWith(".")) warnings.push("Tool name starts or ends with a dot, which may cause parsing issues in some contexts");
|
|
3604
|
+
if (!TOOL_NAME_REGEX.test(name)) {
|
|
3605
|
+
const invalidChars = name.split("").filter((char) => !/[A-Za-z0-9._-]/.test(char)).filter((char, index, arr) => arr.indexOf(char) === index);
|
|
3606
|
+
warnings.push(`Tool name contains invalid characters: ${invalidChars.map((c) => `"${c}"`).join(", ")}`, "Allowed characters are: A-Z, a-z, 0-9, underscore (_), dash (-), and dot (.)");
|
|
3607
|
+
return {
|
|
3608
|
+
isValid: false,
|
|
3609
|
+
warnings
|
|
3610
|
+
};
|
|
3611
|
+
}
|
|
3612
|
+
return {
|
|
3613
|
+
isValid: true,
|
|
3614
|
+
warnings
|
|
3615
|
+
};
|
|
3616
|
+
}
|
|
3617
|
+
/**
|
|
3618
|
+
* Issues warnings for non-conforming tool names
|
|
3619
|
+
* @param name - The tool name that triggered the warnings
|
|
3620
|
+
* @param warnings - Array of warning messages
|
|
3621
|
+
*/
|
|
3622
|
+
function issueToolNameWarning(name, warnings) {
|
|
3623
|
+
if (warnings.length > 0) {
|
|
3624
|
+
console.warn(`Tool name validation warning for "${name}":`);
|
|
3625
|
+
for (const warning of warnings) console.warn(` - ${warning}`);
|
|
3626
|
+
console.warn("Tool registration will proceed, but this may cause compatibility issues.");
|
|
3627
|
+
console.warn("Consider updating the tool name to conform to the MCP tool naming standard.");
|
|
3628
|
+
console.warn("See SEP: Specify Format for Tool Names (https://github.com/modelcontextprotocol/modelcontextprotocol/issues/986) for more details.");
|
|
3629
|
+
}
|
|
3630
|
+
}
|
|
3631
|
+
/**
|
|
3632
|
+
* Validates a tool name and issues warnings for non-conforming names
|
|
3633
|
+
* @param name - The tool name to validate
|
|
3634
|
+
* @returns true if the name is valid, false otherwise
|
|
3635
|
+
*/
|
|
3636
|
+
function validateAndWarnToolName(name) {
|
|
3637
|
+
const result = validateToolName(name);
|
|
3638
|
+
issueToolNameWarning(name, result.warnings);
|
|
3639
|
+
return result.isValid;
|
|
3640
|
+
}
|
|
3641
|
+
|
|
3642
|
+
//#endregion
|
|
3643
|
+
//#region ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.26.0_@cfworker+json-schema@4.1.1_zod@4.3.5/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/mcp-server.js
|
|
3644
|
+
/**
|
|
3645
|
+
* Experimental McpServer task features for MCP SDK.
|
|
3646
|
+
* WARNING: These APIs are experimental and may change without notice.
|
|
16
3647
|
*
|
|
17
|
-
* @
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
*
|
|
3648
|
+
* @experimental
|
|
3649
|
+
*/
|
|
3650
|
+
/**
|
|
3651
|
+
* Experimental task features for McpServer.
|
|
21
3652
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* );
|
|
3653
|
+
* Access via `server.experimental.tasks`:
|
|
3654
|
+
* ```typescript
|
|
3655
|
+
* server.experimental.tasks.registerToolTask('long-running', config, handler);
|
|
26
3656
|
* ```
|
|
3657
|
+
*
|
|
3658
|
+
* @experimental
|
|
27
3659
|
*/
|
|
28
|
-
var
|
|
3660
|
+
var ExperimentalMcpServerTasks = class {
|
|
3661
|
+
constructor(_mcpServer) {
|
|
3662
|
+
this._mcpServer = _mcpServer;
|
|
3663
|
+
}
|
|
3664
|
+
registerToolTask(name, config, handler) {
|
|
3665
|
+
const execution = {
|
|
3666
|
+
taskSupport: "required",
|
|
3667
|
+
...config.execution
|
|
3668
|
+
};
|
|
3669
|
+
if (execution.taskSupport === "forbidden") throw new Error(`Cannot register task-based tool '${name}' with taskSupport 'forbidden'. Use registerTool() instead.`);
|
|
3670
|
+
return this._mcpServer._createRegisteredTool(name, config.title, config.description, config.inputSchema, config.outputSchema, config.annotations, execution, config._meta, handler);
|
|
3671
|
+
}
|
|
3672
|
+
};
|
|
3673
|
+
|
|
3674
|
+
//#endregion
|
|
3675
|
+
//#region ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.26.0_@cfworker+json-schema@4.1.1_zod@4.3.5/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js
|
|
3676
|
+
/**
|
|
3677
|
+
* High-level MCP server that provides a simpler API for working with resources, tools, and prompts.
|
|
3678
|
+
* For advanced usage (like sending notifications or setting custom request handlers), use the underlying
|
|
3679
|
+
* Server instance available via the `server` property.
|
|
3680
|
+
*/
|
|
3681
|
+
var McpServer = class {
|
|
3682
|
+
constructor(serverInfo, options) {
|
|
3683
|
+
this._registeredResources = {};
|
|
3684
|
+
this._registeredResourceTemplates = {};
|
|
3685
|
+
this._registeredTools = {};
|
|
3686
|
+
this._registeredPrompts = {};
|
|
3687
|
+
this._toolHandlersInitialized = false;
|
|
3688
|
+
this._completionHandlerInitialized = false;
|
|
3689
|
+
this._resourceHandlersInitialized = false;
|
|
3690
|
+
this._promptHandlersInitialized = false;
|
|
3691
|
+
this.server = new Server(serverInfo, options);
|
|
3692
|
+
}
|
|
29
3693
|
/**
|
|
30
|
-
*
|
|
31
|
-
* The input data is passed through unchanged.
|
|
3694
|
+
* Access experimental features.
|
|
32
3695
|
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
3696
|
+
* WARNING: These APIs are experimental and may change without notice.
|
|
3697
|
+
*
|
|
3698
|
+
* @experimental
|
|
35
3699
|
*/
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
3700
|
+
get experimental() {
|
|
3701
|
+
if (!this._experimental) this._experimental = { tasks: new ExperimentalMcpServerTasks(this) };
|
|
3702
|
+
return this._experimental;
|
|
3703
|
+
}
|
|
3704
|
+
/**
|
|
3705
|
+
* Attaches to the given transport, starts it, and starts listening for messages.
|
|
3706
|
+
*
|
|
3707
|
+
* The `server` object assumes ownership of the Transport, replacing any callbacks that have already been set, and expects that it is the only user of the Transport instance going forward.
|
|
3708
|
+
*/
|
|
3709
|
+
async connect(transport) {
|
|
3710
|
+
return await this.server.connect(transport);
|
|
3711
|
+
}
|
|
3712
|
+
/**
|
|
3713
|
+
* Closes the connection.
|
|
3714
|
+
*/
|
|
3715
|
+
async close() {
|
|
3716
|
+
await this.server.close();
|
|
3717
|
+
}
|
|
3718
|
+
setToolRequestHandlers() {
|
|
3719
|
+
if (this._toolHandlersInitialized) return;
|
|
3720
|
+
this.server.assertCanSetRequestHandler(getMethodValue(ListToolsRequestSchema));
|
|
3721
|
+
this.server.assertCanSetRequestHandler(getMethodValue(CallToolRequestSchema));
|
|
3722
|
+
this.server.registerCapabilities({ tools: { listChanged: true } });
|
|
3723
|
+
this.server.setRequestHandler(ListToolsRequestSchema, () => ({ tools: Object.entries(this._registeredTools).filter(([, tool]) => tool.enabled).map(([name, tool]) => {
|
|
3724
|
+
const toolDefinition = {
|
|
3725
|
+
name,
|
|
3726
|
+
title: tool.title,
|
|
3727
|
+
description: tool.description,
|
|
3728
|
+
inputSchema: (() => {
|
|
3729
|
+
const obj = normalizeObjectSchema(tool.inputSchema);
|
|
3730
|
+
return obj ? toJsonSchemaCompat(obj, {
|
|
3731
|
+
strictUnions: true,
|
|
3732
|
+
pipeStrategy: "input"
|
|
3733
|
+
}) : EMPTY_OBJECT_JSON_SCHEMA;
|
|
3734
|
+
})(),
|
|
3735
|
+
annotations: tool.annotations,
|
|
3736
|
+
execution: tool.execution,
|
|
3737
|
+
_meta: tool._meta
|
|
3738
|
+
};
|
|
3739
|
+
if (tool.outputSchema) {
|
|
3740
|
+
const obj = normalizeObjectSchema(tool.outputSchema);
|
|
3741
|
+
if (obj) toolDefinition.outputSchema = toJsonSchemaCompat(obj, {
|
|
3742
|
+
strictUnions: true,
|
|
3743
|
+
pipeStrategy: "output"
|
|
3744
|
+
});
|
|
3745
|
+
}
|
|
3746
|
+
return toolDefinition;
|
|
3747
|
+
}) }));
|
|
3748
|
+
this.server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
|
|
3749
|
+
try {
|
|
3750
|
+
const tool = this._registeredTools[request.params.name];
|
|
3751
|
+
if (!tool) throw new McpError(ErrorCode.InvalidParams, `Tool ${request.params.name} not found`);
|
|
3752
|
+
if (!tool.enabled) throw new McpError(ErrorCode.InvalidParams, `Tool ${request.params.name} disabled`);
|
|
3753
|
+
const isTaskRequest = !!request.params.task;
|
|
3754
|
+
const taskSupport = tool.execution?.taskSupport;
|
|
3755
|
+
const isTaskHandler = "createTask" in tool.handler;
|
|
3756
|
+
if ((taskSupport === "required" || taskSupport === "optional") && !isTaskHandler) throw new McpError(ErrorCode.InternalError, `Tool ${request.params.name} has taskSupport '${taskSupport}' but was not registered with registerToolTask`);
|
|
3757
|
+
if (taskSupport === "required" && !isTaskRequest) throw new McpError(ErrorCode.MethodNotFound, `Tool ${request.params.name} requires task augmentation (taskSupport: 'required')`);
|
|
3758
|
+
if (taskSupport === "optional" && !isTaskRequest && isTaskHandler) return await this.handleAutomaticTaskPolling(tool, request, extra);
|
|
3759
|
+
const args = await this.validateToolInput(tool, request.params.arguments, request.params.name);
|
|
3760
|
+
const result = await this.executeToolHandler(tool, args, extra);
|
|
3761
|
+
if (isTaskRequest) return result;
|
|
3762
|
+
await this.validateToolOutput(tool, result, request.params.name);
|
|
3763
|
+
return result;
|
|
3764
|
+
} catch (error) {
|
|
3765
|
+
if (error instanceof McpError) {
|
|
3766
|
+
if (error.code === ErrorCode.UrlElicitationRequired) throw error;
|
|
3767
|
+
}
|
|
3768
|
+
return this.createToolError(error instanceof Error ? error.message : String(error));
|
|
3769
|
+
}
|
|
3770
|
+
});
|
|
3771
|
+
this._toolHandlersInitialized = true;
|
|
3772
|
+
}
|
|
3773
|
+
/**
|
|
3774
|
+
* Creates a tool error result.
|
|
3775
|
+
*
|
|
3776
|
+
* @param errorMessage - The error message.
|
|
3777
|
+
* @returns The tool error result.
|
|
3778
|
+
*/
|
|
3779
|
+
createToolError(errorMessage) {
|
|
3780
|
+
return {
|
|
3781
|
+
content: [{
|
|
3782
|
+
type: "text",
|
|
3783
|
+
text: errorMessage
|
|
3784
|
+
}],
|
|
3785
|
+
isError: true
|
|
3786
|
+
};
|
|
3787
|
+
}
|
|
3788
|
+
/**
|
|
3789
|
+
* Validates tool input arguments against the tool's input schema.
|
|
3790
|
+
*/
|
|
3791
|
+
async validateToolInput(tool, args, toolName) {
|
|
3792
|
+
if (!tool.inputSchema) return;
|
|
3793
|
+
const parseResult = await safeParseAsync(normalizeObjectSchema(tool.inputSchema) ?? tool.inputSchema, args);
|
|
3794
|
+
if (!parseResult.success) {
|
|
3795
|
+
const errorMessage = getParseErrorMessage("error" in parseResult ? parseResult.error : "Unknown error");
|
|
3796
|
+
throw new McpError(ErrorCode.InvalidParams, `Input validation error: Invalid arguments for tool ${toolName}: ${errorMessage}`);
|
|
3797
|
+
}
|
|
3798
|
+
return parseResult.data;
|
|
3799
|
+
}
|
|
3800
|
+
/**
|
|
3801
|
+
* Validates tool output against the tool's output schema.
|
|
3802
|
+
*/
|
|
3803
|
+
async validateToolOutput(tool, result, toolName) {
|
|
3804
|
+
if (!tool.outputSchema) return;
|
|
3805
|
+
if (!("content" in result)) return;
|
|
3806
|
+
if (result.isError) return;
|
|
3807
|
+
if (!result.structuredContent) throw new McpError(ErrorCode.InvalidParams, `Output validation error: Tool ${toolName} has an output schema but no structured content was provided`);
|
|
3808
|
+
const parseResult = await safeParseAsync(normalizeObjectSchema(tool.outputSchema), result.structuredContent);
|
|
3809
|
+
if (!parseResult.success) {
|
|
3810
|
+
const errorMessage = getParseErrorMessage("error" in parseResult ? parseResult.error : "Unknown error");
|
|
3811
|
+
throw new McpError(ErrorCode.InvalidParams, `Output validation error: Invalid structured content for tool ${toolName}: ${errorMessage}`);
|
|
3812
|
+
}
|
|
3813
|
+
}
|
|
3814
|
+
/**
|
|
3815
|
+
* Executes a tool handler (either regular or task-based).
|
|
3816
|
+
*/
|
|
3817
|
+
async executeToolHandler(tool, args, extra) {
|
|
3818
|
+
const handler = tool.handler;
|
|
3819
|
+
if ("createTask" in handler) {
|
|
3820
|
+
if (!extra.taskStore) throw new Error("No task store provided.");
|
|
3821
|
+
const taskExtra = {
|
|
3822
|
+
...extra,
|
|
3823
|
+
taskStore: extra.taskStore
|
|
3824
|
+
};
|
|
3825
|
+
if (tool.inputSchema) {
|
|
3826
|
+
const typedHandler = handler;
|
|
3827
|
+
return await Promise.resolve(typedHandler.createTask(args, taskExtra));
|
|
3828
|
+
} else {
|
|
3829
|
+
const typedHandler = handler;
|
|
3830
|
+
return await Promise.resolve(typedHandler.createTask(taskExtra));
|
|
3831
|
+
}
|
|
3832
|
+
}
|
|
3833
|
+
if (tool.inputSchema) {
|
|
3834
|
+
const typedHandler = handler;
|
|
3835
|
+
return await Promise.resolve(typedHandler(args, extra));
|
|
3836
|
+
} else {
|
|
3837
|
+
const typedHandler = handler;
|
|
3838
|
+
return await Promise.resolve(typedHandler(extra));
|
|
3839
|
+
}
|
|
3840
|
+
}
|
|
3841
|
+
/**
|
|
3842
|
+
* Handles automatic task polling for tools with taskSupport 'optional'.
|
|
3843
|
+
*/
|
|
3844
|
+
async handleAutomaticTaskPolling(tool, request, extra) {
|
|
3845
|
+
if (!extra.taskStore) throw new Error("No task store provided for task-capable tool.");
|
|
3846
|
+
const args = await this.validateToolInput(tool, request.params.arguments, request.params.name);
|
|
3847
|
+
const handler = tool.handler;
|
|
3848
|
+
const taskExtra = {
|
|
3849
|
+
...extra,
|
|
3850
|
+
taskStore: extra.taskStore
|
|
3851
|
+
};
|
|
3852
|
+
const createTaskResult = args ? await Promise.resolve(handler.createTask(args, taskExtra)) : await Promise.resolve(handler.createTask(taskExtra));
|
|
3853
|
+
const taskId = createTaskResult.task.taskId;
|
|
3854
|
+
let task = createTaskResult.task;
|
|
3855
|
+
const pollInterval = task.pollInterval ?? 5e3;
|
|
3856
|
+
while (task.status !== "completed" && task.status !== "failed" && task.status !== "cancelled") {
|
|
3857
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
3858
|
+
const updatedTask = await extra.taskStore.getTask(taskId);
|
|
3859
|
+
if (!updatedTask) throw new McpError(ErrorCode.InternalError, `Task ${taskId} not found during polling`);
|
|
3860
|
+
task = updatedTask;
|
|
3861
|
+
}
|
|
3862
|
+
return await extra.taskStore.getTaskResult(taskId);
|
|
3863
|
+
}
|
|
3864
|
+
setCompletionRequestHandler() {
|
|
3865
|
+
if (this._completionHandlerInitialized) return;
|
|
3866
|
+
this.server.assertCanSetRequestHandler(getMethodValue(CompleteRequestSchema));
|
|
3867
|
+
this.server.registerCapabilities({ completions: {} });
|
|
3868
|
+
this.server.setRequestHandler(CompleteRequestSchema, async (request) => {
|
|
3869
|
+
switch (request.params.ref.type) {
|
|
3870
|
+
case "ref/prompt":
|
|
3871
|
+
assertCompleteRequestPrompt(request);
|
|
3872
|
+
return this.handlePromptCompletion(request, request.params.ref);
|
|
3873
|
+
case "ref/resource":
|
|
3874
|
+
assertCompleteRequestResourceTemplate(request);
|
|
3875
|
+
return this.handleResourceCompletion(request, request.params.ref);
|
|
3876
|
+
default: throw new McpError(ErrorCode.InvalidParams, `Invalid completion reference: ${request.params.ref}`);
|
|
3877
|
+
}
|
|
3878
|
+
});
|
|
3879
|
+
this._completionHandlerInitialized = true;
|
|
3880
|
+
}
|
|
3881
|
+
async handlePromptCompletion(request, ref) {
|
|
3882
|
+
const prompt = this._registeredPrompts[ref.name];
|
|
3883
|
+
if (!prompt) throw new McpError(ErrorCode.InvalidParams, `Prompt ${ref.name} not found`);
|
|
3884
|
+
if (!prompt.enabled) throw new McpError(ErrorCode.InvalidParams, `Prompt ${ref.name} disabled`);
|
|
3885
|
+
if (!prompt.argsSchema) return EMPTY_COMPLETION_RESULT;
|
|
3886
|
+
const field = getObjectShape(prompt.argsSchema)?.[request.params.argument.name];
|
|
3887
|
+
if (!isCompletable(field)) return EMPTY_COMPLETION_RESULT;
|
|
3888
|
+
const completer = getCompleter(field);
|
|
3889
|
+
if (!completer) return EMPTY_COMPLETION_RESULT;
|
|
3890
|
+
return createCompletionResult(await completer(request.params.argument.value, request.params.context));
|
|
3891
|
+
}
|
|
3892
|
+
async handleResourceCompletion(request, ref) {
|
|
3893
|
+
const template = Object.values(this._registeredResourceTemplates).find((t) => t.resourceTemplate.uriTemplate.toString() === ref.uri);
|
|
3894
|
+
if (!template) {
|
|
3895
|
+
if (this._registeredResources[ref.uri]) return EMPTY_COMPLETION_RESULT;
|
|
3896
|
+
throw new McpError(ErrorCode.InvalidParams, `Resource template ${request.params.ref.uri} not found`);
|
|
3897
|
+
}
|
|
3898
|
+
const completer = template.resourceTemplate.completeCallback(request.params.argument.name);
|
|
3899
|
+
if (!completer) return EMPTY_COMPLETION_RESULT;
|
|
3900
|
+
return createCompletionResult(await completer(request.params.argument.value, request.params.context));
|
|
3901
|
+
}
|
|
3902
|
+
setResourceRequestHandlers() {
|
|
3903
|
+
if (this._resourceHandlersInitialized) return;
|
|
3904
|
+
this.server.assertCanSetRequestHandler(getMethodValue(ListResourcesRequestSchema));
|
|
3905
|
+
this.server.assertCanSetRequestHandler(getMethodValue(ListResourceTemplatesRequestSchema));
|
|
3906
|
+
this.server.assertCanSetRequestHandler(getMethodValue(ReadResourceRequestSchema));
|
|
3907
|
+
this.server.registerCapabilities({ resources: { listChanged: true } });
|
|
3908
|
+
this.server.setRequestHandler(ListResourcesRequestSchema, async (request, extra) => {
|
|
3909
|
+
const resources = Object.entries(this._registeredResources).filter(([_, resource]) => resource.enabled).map(([uri, resource]) => ({
|
|
3910
|
+
uri,
|
|
3911
|
+
name: resource.name,
|
|
3912
|
+
...resource.metadata
|
|
3913
|
+
}));
|
|
3914
|
+
const templateResources = [];
|
|
3915
|
+
for (const template of Object.values(this._registeredResourceTemplates)) {
|
|
3916
|
+
if (!template.resourceTemplate.listCallback) continue;
|
|
3917
|
+
const result = await template.resourceTemplate.listCallback(extra);
|
|
3918
|
+
for (const resource of result.resources) templateResources.push({
|
|
3919
|
+
...template.metadata,
|
|
3920
|
+
...resource
|
|
3921
|
+
});
|
|
3922
|
+
}
|
|
3923
|
+
return { resources: [...resources, ...templateResources] };
|
|
3924
|
+
});
|
|
3925
|
+
this.server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => {
|
|
3926
|
+
return { resourceTemplates: Object.entries(this._registeredResourceTemplates).map(([name, template]) => ({
|
|
3927
|
+
name,
|
|
3928
|
+
uriTemplate: template.resourceTemplate.uriTemplate.toString(),
|
|
3929
|
+
...template.metadata
|
|
3930
|
+
})) };
|
|
3931
|
+
});
|
|
3932
|
+
this.server.setRequestHandler(ReadResourceRequestSchema, async (request, extra) => {
|
|
3933
|
+
const uri = new URL(request.params.uri);
|
|
3934
|
+
const resource = this._registeredResources[uri.toString()];
|
|
3935
|
+
if (resource) {
|
|
3936
|
+
if (!resource.enabled) throw new McpError(ErrorCode.InvalidParams, `Resource ${uri} disabled`);
|
|
3937
|
+
return resource.readCallback(uri, extra);
|
|
3938
|
+
}
|
|
3939
|
+
for (const template of Object.values(this._registeredResourceTemplates)) {
|
|
3940
|
+
const variables = template.resourceTemplate.uriTemplate.match(uri.toString());
|
|
3941
|
+
if (variables) return template.readCallback(uri, variables, extra);
|
|
3942
|
+
}
|
|
3943
|
+
throw new McpError(ErrorCode.InvalidParams, `Resource ${uri} not found`);
|
|
41
3944
|
});
|
|
3945
|
+
this._resourceHandlersInitialized = true;
|
|
3946
|
+
}
|
|
3947
|
+
setPromptRequestHandlers() {
|
|
3948
|
+
if (this._promptHandlersInitialized) return;
|
|
3949
|
+
this.server.assertCanSetRequestHandler(getMethodValue(ListPromptsRequestSchema));
|
|
3950
|
+
this.server.assertCanSetRequestHandler(getMethodValue(GetPromptRequestSchema));
|
|
3951
|
+
this.server.registerCapabilities({ prompts: { listChanged: true } });
|
|
3952
|
+
this.server.setRequestHandler(ListPromptsRequestSchema, () => ({ prompts: Object.entries(this._registeredPrompts).filter(([, prompt]) => prompt.enabled).map(([name, prompt]) => {
|
|
3953
|
+
return {
|
|
3954
|
+
name,
|
|
3955
|
+
title: prompt.title,
|
|
3956
|
+
description: prompt.description,
|
|
3957
|
+
arguments: prompt.argsSchema ? promptArgumentsFromSchema(prompt.argsSchema) : void 0
|
|
3958
|
+
};
|
|
3959
|
+
}) }));
|
|
3960
|
+
this.server.setRequestHandler(GetPromptRequestSchema, async (request, extra) => {
|
|
3961
|
+
const prompt = this._registeredPrompts[request.params.name];
|
|
3962
|
+
if (!prompt) throw new McpError(ErrorCode.InvalidParams, `Prompt ${request.params.name} not found`);
|
|
3963
|
+
if (!prompt.enabled) throw new McpError(ErrorCode.InvalidParams, `Prompt ${request.params.name} disabled`);
|
|
3964
|
+
if (prompt.argsSchema) {
|
|
3965
|
+
const parseResult = await safeParseAsync(normalizeObjectSchema(prompt.argsSchema), request.params.arguments);
|
|
3966
|
+
if (!parseResult.success) {
|
|
3967
|
+
const errorMessage = getParseErrorMessage("error" in parseResult ? parseResult.error : "Unknown error");
|
|
3968
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid arguments for prompt ${request.params.name}: ${errorMessage}`);
|
|
3969
|
+
}
|
|
3970
|
+
const args = parseResult.data;
|
|
3971
|
+
const cb = prompt.callback;
|
|
3972
|
+
return await Promise.resolve(cb(args, extra));
|
|
3973
|
+
} else {
|
|
3974
|
+
const cb = prompt.callback;
|
|
3975
|
+
return await Promise.resolve(cb(extra));
|
|
3976
|
+
}
|
|
3977
|
+
});
|
|
3978
|
+
this._promptHandlersInitialized = true;
|
|
3979
|
+
}
|
|
3980
|
+
resource(name, uriOrTemplate, ...rest) {
|
|
3981
|
+
let metadata;
|
|
3982
|
+
if (typeof rest[0] === "object") metadata = rest.shift();
|
|
3983
|
+
const readCallback = rest[0];
|
|
3984
|
+
if (typeof uriOrTemplate === "string") {
|
|
3985
|
+
if (this._registeredResources[uriOrTemplate]) throw new Error(`Resource ${uriOrTemplate} is already registered`);
|
|
3986
|
+
const registeredResource = this._createRegisteredResource(name, void 0, uriOrTemplate, metadata, readCallback);
|
|
3987
|
+
this.setResourceRequestHandlers();
|
|
3988
|
+
this.sendResourceListChanged();
|
|
3989
|
+
return registeredResource;
|
|
3990
|
+
} else {
|
|
3991
|
+
if (this._registeredResourceTemplates[name]) throw new Error(`Resource template ${name} is already registered`);
|
|
3992
|
+
const registeredResourceTemplate = this._createRegisteredResourceTemplate(name, void 0, uriOrTemplate, metadata, readCallback);
|
|
3993
|
+
this.setResourceRequestHandlers();
|
|
3994
|
+
this.sendResourceListChanged();
|
|
3995
|
+
return registeredResourceTemplate;
|
|
3996
|
+
}
|
|
3997
|
+
}
|
|
3998
|
+
registerResource(name, uriOrTemplate, config, readCallback) {
|
|
3999
|
+
if (typeof uriOrTemplate === "string") {
|
|
4000
|
+
if (this._registeredResources[uriOrTemplate]) throw new Error(`Resource ${uriOrTemplate} is already registered`);
|
|
4001
|
+
const registeredResource = this._createRegisteredResource(name, config.title, uriOrTemplate, config, readCallback);
|
|
4002
|
+
this.setResourceRequestHandlers();
|
|
4003
|
+
this.sendResourceListChanged();
|
|
4004
|
+
return registeredResource;
|
|
4005
|
+
} else {
|
|
4006
|
+
if (this._registeredResourceTemplates[name]) throw new Error(`Resource template ${name} is already registered`);
|
|
4007
|
+
const registeredResourceTemplate = this._createRegisteredResourceTemplate(name, config.title, uriOrTemplate, config, readCallback);
|
|
4008
|
+
this.setResourceRequestHandlers();
|
|
4009
|
+
this.sendResourceListChanged();
|
|
4010
|
+
return registeredResourceTemplate;
|
|
4011
|
+
}
|
|
4012
|
+
}
|
|
4013
|
+
_createRegisteredResource(name, title, uri, metadata, readCallback) {
|
|
4014
|
+
const registeredResource = {
|
|
4015
|
+
name,
|
|
4016
|
+
title,
|
|
4017
|
+
metadata,
|
|
4018
|
+
readCallback,
|
|
4019
|
+
enabled: true,
|
|
4020
|
+
disable: () => registeredResource.update({ enabled: false }),
|
|
4021
|
+
enable: () => registeredResource.update({ enabled: true }),
|
|
4022
|
+
remove: () => registeredResource.update({ uri: null }),
|
|
4023
|
+
update: (updates) => {
|
|
4024
|
+
if (typeof updates.uri !== "undefined" && updates.uri !== uri) {
|
|
4025
|
+
delete this._registeredResources[uri];
|
|
4026
|
+
if (updates.uri) this._registeredResources[updates.uri] = registeredResource;
|
|
4027
|
+
}
|
|
4028
|
+
if (typeof updates.name !== "undefined") registeredResource.name = updates.name;
|
|
4029
|
+
if (typeof updates.title !== "undefined") registeredResource.title = updates.title;
|
|
4030
|
+
if (typeof updates.metadata !== "undefined") registeredResource.metadata = updates.metadata;
|
|
4031
|
+
if (typeof updates.callback !== "undefined") registeredResource.readCallback = updates.callback;
|
|
4032
|
+
if (typeof updates.enabled !== "undefined") registeredResource.enabled = updates.enabled;
|
|
4033
|
+
this.sendResourceListChanged();
|
|
4034
|
+
}
|
|
4035
|
+
};
|
|
4036
|
+
this._registeredResources[uri] = registeredResource;
|
|
4037
|
+
return registeredResource;
|
|
4038
|
+
}
|
|
4039
|
+
_createRegisteredResourceTemplate(name, title, template, metadata, readCallback) {
|
|
4040
|
+
const registeredResourceTemplate = {
|
|
4041
|
+
resourceTemplate: template,
|
|
4042
|
+
title,
|
|
4043
|
+
metadata,
|
|
4044
|
+
readCallback,
|
|
4045
|
+
enabled: true,
|
|
4046
|
+
disable: () => registeredResourceTemplate.update({ enabled: false }),
|
|
4047
|
+
enable: () => registeredResourceTemplate.update({ enabled: true }),
|
|
4048
|
+
remove: () => registeredResourceTemplate.update({ name: null }),
|
|
4049
|
+
update: (updates) => {
|
|
4050
|
+
if (typeof updates.name !== "undefined" && updates.name !== name) {
|
|
4051
|
+
delete this._registeredResourceTemplates[name];
|
|
4052
|
+
if (updates.name) this._registeredResourceTemplates[updates.name] = registeredResourceTemplate;
|
|
4053
|
+
}
|
|
4054
|
+
if (typeof updates.title !== "undefined") registeredResourceTemplate.title = updates.title;
|
|
4055
|
+
if (typeof updates.template !== "undefined") registeredResourceTemplate.resourceTemplate = updates.template;
|
|
4056
|
+
if (typeof updates.metadata !== "undefined") registeredResourceTemplate.metadata = updates.metadata;
|
|
4057
|
+
if (typeof updates.callback !== "undefined") registeredResourceTemplate.readCallback = updates.callback;
|
|
4058
|
+
if (typeof updates.enabled !== "undefined") registeredResourceTemplate.enabled = updates.enabled;
|
|
4059
|
+
this.sendResourceListChanged();
|
|
4060
|
+
}
|
|
4061
|
+
};
|
|
4062
|
+
this._registeredResourceTemplates[name] = registeredResourceTemplate;
|
|
4063
|
+
const variableNames = template.uriTemplate.variableNames;
|
|
4064
|
+
if (Array.isArray(variableNames) && variableNames.some((v) => !!template.completeCallback(v))) this.setCompletionRequestHandler();
|
|
4065
|
+
return registeredResourceTemplate;
|
|
4066
|
+
}
|
|
4067
|
+
_createRegisteredPrompt(name, title, description, argsSchema, callback) {
|
|
4068
|
+
const registeredPrompt = {
|
|
4069
|
+
title,
|
|
4070
|
+
description,
|
|
4071
|
+
argsSchema: argsSchema === void 0 ? void 0 : objectFromShape(argsSchema),
|
|
4072
|
+
callback,
|
|
4073
|
+
enabled: true,
|
|
4074
|
+
disable: () => registeredPrompt.update({ enabled: false }),
|
|
4075
|
+
enable: () => registeredPrompt.update({ enabled: true }),
|
|
4076
|
+
remove: () => registeredPrompt.update({ name: null }),
|
|
4077
|
+
update: (updates) => {
|
|
4078
|
+
if (typeof updates.name !== "undefined" && updates.name !== name) {
|
|
4079
|
+
delete this._registeredPrompts[name];
|
|
4080
|
+
if (updates.name) this._registeredPrompts[updates.name] = registeredPrompt;
|
|
4081
|
+
}
|
|
4082
|
+
if (typeof updates.title !== "undefined") registeredPrompt.title = updates.title;
|
|
4083
|
+
if (typeof updates.description !== "undefined") registeredPrompt.description = updates.description;
|
|
4084
|
+
if (typeof updates.argsSchema !== "undefined") registeredPrompt.argsSchema = objectFromShape(updates.argsSchema);
|
|
4085
|
+
if (typeof updates.callback !== "undefined") registeredPrompt.callback = updates.callback;
|
|
4086
|
+
if (typeof updates.enabled !== "undefined") registeredPrompt.enabled = updates.enabled;
|
|
4087
|
+
this.sendPromptListChanged();
|
|
4088
|
+
}
|
|
4089
|
+
};
|
|
4090
|
+
this._registeredPrompts[name] = registeredPrompt;
|
|
4091
|
+
if (argsSchema) {
|
|
4092
|
+
if (Object.values(argsSchema).some((field) => {
|
|
4093
|
+
return isCompletable(field instanceof ZodOptional ? field._def?.innerType : field);
|
|
4094
|
+
})) this.setCompletionRequestHandler();
|
|
4095
|
+
}
|
|
4096
|
+
return registeredPrompt;
|
|
4097
|
+
}
|
|
4098
|
+
_createRegisteredTool(name, title, description, inputSchema, outputSchema, annotations, execution, _meta, handler) {
|
|
4099
|
+
validateAndWarnToolName(name);
|
|
4100
|
+
const registeredTool = {
|
|
4101
|
+
title,
|
|
4102
|
+
description,
|
|
4103
|
+
inputSchema: getZodSchemaObject(inputSchema),
|
|
4104
|
+
outputSchema: getZodSchemaObject(outputSchema),
|
|
4105
|
+
annotations,
|
|
4106
|
+
execution,
|
|
4107
|
+
_meta,
|
|
4108
|
+
handler,
|
|
4109
|
+
enabled: true,
|
|
4110
|
+
disable: () => registeredTool.update({ enabled: false }),
|
|
4111
|
+
enable: () => registeredTool.update({ enabled: true }),
|
|
4112
|
+
remove: () => registeredTool.update({ name: null }),
|
|
4113
|
+
update: (updates) => {
|
|
4114
|
+
if (typeof updates.name !== "undefined" && updates.name !== name) {
|
|
4115
|
+
if (typeof updates.name === "string") validateAndWarnToolName(updates.name);
|
|
4116
|
+
delete this._registeredTools[name];
|
|
4117
|
+
if (updates.name) this._registeredTools[updates.name] = registeredTool;
|
|
4118
|
+
}
|
|
4119
|
+
if (typeof updates.title !== "undefined") registeredTool.title = updates.title;
|
|
4120
|
+
if (typeof updates.description !== "undefined") registeredTool.description = updates.description;
|
|
4121
|
+
if (typeof updates.paramsSchema !== "undefined") registeredTool.inputSchema = objectFromShape(updates.paramsSchema);
|
|
4122
|
+
if (typeof updates.outputSchema !== "undefined") registeredTool.outputSchema = objectFromShape(updates.outputSchema);
|
|
4123
|
+
if (typeof updates.callback !== "undefined") registeredTool.handler = updates.callback;
|
|
4124
|
+
if (typeof updates.annotations !== "undefined") registeredTool.annotations = updates.annotations;
|
|
4125
|
+
if (typeof updates._meta !== "undefined") registeredTool._meta = updates._meta;
|
|
4126
|
+
if (typeof updates.enabled !== "undefined") registeredTool.enabled = updates.enabled;
|
|
4127
|
+
this.sendToolListChanged();
|
|
4128
|
+
}
|
|
4129
|
+
};
|
|
4130
|
+
this._registeredTools[name] = registeredTool;
|
|
4131
|
+
this.setToolRequestHandlers();
|
|
4132
|
+
this.sendToolListChanged();
|
|
4133
|
+
return registeredTool;
|
|
4134
|
+
}
|
|
4135
|
+
/**
|
|
4136
|
+
* tool() implementation. Parses arguments passed to overrides defined above.
|
|
4137
|
+
*/
|
|
4138
|
+
tool(name, ...rest) {
|
|
4139
|
+
if (this._registeredTools[name]) throw new Error(`Tool ${name} is already registered`);
|
|
4140
|
+
let description;
|
|
4141
|
+
let inputSchema;
|
|
4142
|
+
let outputSchema;
|
|
4143
|
+
let annotations;
|
|
4144
|
+
if (typeof rest[0] === "string") description = rest.shift();
|
|
4145
|
+
if (rest.length > 1) {
|
|
4146
|
+
const firstArg = rest[0];
|
|
4147
|
+
if (isZodRawShapeCompat(firstArg)) {
|
|
4148
|
+
inputSchema = rest.shift();
|
|
4149
|
+
if (rest.length > 1 && typeof rest[0] === "object" && rest[0] !== null && !isZodRawShapeCompat(rest[0])) annotations = rest.shift();
|
|
4150
|
+
} else if (typeof firstArg === "object" && firstArg !== null) annotations = rest.shift();
|
|
4151
|
+
}
|
|
4152
|
+
const callback = rest[0];
|
|
4153
|
+
return this._createRegisteredTool(name, void 0, description, inputSchema, outputSchema, annotations, { taskSupport: "forbidden" }, void 0, callback);
|
|
4154
|
+
}
|
|
4155
|
+
/**
|
|
4156
|
+
* Registers a tool with a config object and callback.
|
|
4157
|
+
*/
|
|
4158
|
+
registerTool(name, config, cb) {
|
|
4159
|
+
if (this._registeredTools[name]) throw new Error(`Tool ${name} is already registered`);
|
|
4160
|
+
const { title, description, inputSchema, outputSchema, annotations, _meta } = config;
|
|
4161
|
+
return this._createRegisteredTool(name, title, description, inputSchema, outputSchema, annotations, { taskSupport: "forbidden" }, _meta, cb);
|
|
4162
|
+
}
|
|
4163
|
+
prompt(name, ...rest) {
|
|
4164
|
+
if (this._registeredPrompts[name]) throw new Error(`Prompt ${name} is already registered`);
|
|
4165
|
+
let description;
|
|
4166
|
+
if (typeof rest[0] === "string") description = rest.shift();
|
|
4167
|
+
let argsSchema;
|
|
4168
|
+
if (rest.length > 1) argsSchema = rest.shift();
|
|
4169
|
+
const cb = rest[0];
|
|
4170
|
+
const registeredPrompt = this._createRegisteredPrompt(name, void 0, description, argsSchema, cb);
|
|
4171
|
+
this.setPromptRequestHandlers();
|
|
4172
|
+
this.sendPromptListChanged();
|
|
4173
|
+
return registeredPrompt;
|
|
4174
|
+
}
|
|
4175
|
+
/**
|
|
4176
|
+
* Registers a prompt with a config object and callback.
|
|
4177
|
+
*/
|
|
4178
|
+
registerPrompt(name, config, cb) {
|
|
4179
|
+
if (this._registeredPrompts[name]) throw new Error(`Prompt ${name} is already registered`);
|
|
4180
|
+
const { title, description, argsSchema } = config;
|
|
4181
|
+
const registeredPrompt = this._createRegisteredPrompt(name, title, description, argsSchema, cb);
|
|
4182
|
+
this.setPromptRequestHandlers();
|
|
4183
|
+
this.sendPromptListChanged();
|
|
4184
|
+
return registeredPrompt;
|
|
4185
|
+
}
|
|
4186
|
+
/**
|
|
4187
|
+
* Checks if the server is connected to a transport.
|
|
4188
|
+
* @returns True if the server is connected
|
|
4189
|
+
*/
|
|
4190
|
+
isConnected() {
|
|
4191
|
+
return this.server.transport !== void 0;
|
|
4192
|
+
}
|
|
4193
|
+
/**
|
|
4194
|
+
* Sends a logging message to the client, if connected.
|
|
4195
|
+
* Note: You only need to send the parameters object, not the entire JSON RPC message
|
|
4196
|
+
* @see LoggingMessageNotification
|
|
4197
|
+
* @param params
|
|
4198
|
+
* @param sessionId optional for stateless and backward compatibility
|
|
4199
|
+
*/
|
|
4200
|
+
async sendLoggingMessage(params, sessionId) {
|
|
4201
|
+
return this.server.sendLoggingMessage(params, sessionId);
|
|
4202
|
+
}
|
|
4203
|
+
/**
|
|
4204
|
+
* Sends a resource list changed event to the client, if connected.
|
|
4205
|
+
*/
|
|
4206
|
+
sendResourceListChanged() {
|
|
4207
|
+
if (this.isConnected()) this.server.sendResourceListChanged();
|
|
4208
|
+
}
|
|
4209
|
+
/**
|
|
4210
|
+
* Sends a tool list changed event to the client, if connected.
|
|
4211
|
+
*/
|
|
4212
|
+
sendToolListChanged() {
|
|
4213
|
+
if (this.isConnected()) this.server.sendToolListChanged();
|
|
4214
|
+
}
|
|
4215
|
+
/**
|
|
4216
|
+
* Sends a prompt list changed event to the client, if connected.
|
|
4217
|
+
*/
|
|
4218
|
+
sendPromptListChanged() {
|
|
4219
|
+
if (this.isConnected()) this.server.sendPromptListChanged();
|
|
4220
|
+
}
|
|
4221
|
+
};
|
|
4222
|
+
const EMPTY_OBJECT_JSON_SCHEMA = {
|
|
4223
|
+
type: "object",
|
|
4224
|
+
properties: {}
|
|
4225
|
+
};
|
|
4226
|
+
/**
|
|
4227
|
+
* Checks if a value looks like a Zod schema by checking for parse/safeParse methods.
|
|
4228
|
+
*/
|
|
4229
|
+
function isZodTypeLike(value) {
|
|
4230
|
+
return value !== null && typeof value === "object" && "parse" in value && typeof value.parse === "function" && "safeParse" in value && typeof value.safeParse === "function";
|
|
4231
|
+
}
|
|
4232
|
+
/**
|
|
4233
|
+
* Checks if an object is a Zod schema instance (v3 or v4).
|
|
4234
|
+
*
|
|
4235
|
+
* Zod schemas have internal markers:
|
|
4236
|
+
* - v3: `_def` property
|
|
4237
|
+
* - v4: `_zod` property
|
|
4238
|
+
*
|
|
4239
|
+
* This includes transformed schemas like z.preprocess(), z.transform(), z.pipe().
|
|
4240
|
+
*/
|
|
4241
|
+
function isZodSchemaInstance(obj) {
|
|
4242
|
+
return "_def" in obj || "_zod" in obj || isZodTypeLike(obj);
|
|
4243
|
+
}
|
|
4244
|
+
/**
|
|
4245
|
+
* Checks if an object is a "raw shape" - a plain object where values are Zod schemas.
|
|
4246
|
+
*
|
|
4247
|
+
* Raw shapes are used as shorthand: `{ name: z.string() }` instead of `z.object({ name: z.string() })`.
|
|
4248
|
+
*
|
|
4249
|
+
* IMPORTANT: This must NOT match actual Zod schema instances (like z.preprocess, z.pipe),
|
|
4250
|
+
* which have internal properties that could be mistaken for schema values.
|
|
4251
|
+
*/
|
|
4252
|
+
function isZodRawShapeCompat(obj) {
|
|
4253
|
+
if (typeof obj !== "object" || obj === null) return false;
|
|
4254
|
+
if (isZodSchemaInstance(obj)) return false;
|
|
4255
|
+
if (Object.keys(obj).length === 0) return true;
|
|
4256
|
+
return Object.values(obj).some(isZodTypeLike);
|
|
4257
|
+
}
|
|
4258
|
+
/**
|
|
4259
|
+
* Converts a provided Zod schema to a Zod object if it is a ZodRawShapeCompat,
|
|
4260
|
+
* otherwise returns the schema as is.
|
|
4261
|
+
*/
|
|
4262
|
+
function getZodSchemaObject(schema) {
|
|
4263
|
+
if (!schema) return;
|
|
4264
|
+
if (isZodRawShapeCompat(schema)) return objectFromShape(schema);
|
|
4265
|
+
return schema;
|
|
4266
|
+
}
|
|
4267
|
+
function promptArgumentsFromSchema(schema) {
|
|
4268
|
+
const shape = getObjectShape(schema);
|
|
4269
|
+
if (!shape) return [];
|
|
4270
|
+
return Object.entries(shape).map(([name, field]) => {
|
|
4271
|
+
return {
|
|
4272
|
+
name,
|
|
4273
|
+
description: getSchemaDescription(field),
|
|
4274
|
+
required: !isSchemaOptional(field)
|
|
4275
|
+
};
|
|
4276
|
+
});
|
|
4277
|
+
}
|
|
4278
|
+
function getMethodValue(schema) {
|
|
4279
|
+
const methodSchema = getObjectShape(schema)?.method;
|
|
4280
|
+
if (!methodSchema) throw new Error("Schema is missing a method literal");
|
|
4281
|
+
const value = getLiteralValue(methodSchema);
|
|
4282
|
+
if (typeof value === "string") return value;
|
|
4283
|
+
throw new Error("Schema method literal must be a string");
|
|
4284
|
+
}
|
|
4285
|
+
function createCompletionResult(suggestions) {
|
|
4286
|
+
return { completion: {
|
|
4287
|
+
values: suggestions.slice(0, 100),
|
|
4288
|
+
total: suggestions.length,
|
|
4289
|
+
hasMore: suggestions.length > 100
|
|
4290
|
+
} };
|
|
4291
|
+
}
|
|
4292
|
+
const EMPTY_COMPLETION_RESULT = { completion: {
|
|
4293
|
+
values: [],
|
|
4294
|
+
hasMore: false
|
|
4295
|
+
} };
|
|
4296
|
+
|
|
4297
|
+
//#endregion
|
|
4298
|
+
//#region src/polyfill-validator.ts
|
|
4299
|
+
var PolyfillJsonSchemaValidator = class {
|
|
4300
|
+
getValidator(schema) {
|
|
4301
|
+
return (input) => {
|
|
4302
|
+
if (!isPlainObject(input)) return {
|
|
4303
|
+
valid: false,
|
|
4304
|
+
data: void 0,
|
|
4305
|
+
errorMessage: "expected object arguments"
|
|
4306
|
+
};
|
|
4307
|
+
const issue = validateArgsWithSchema(input, schema);
|
|
4308
|
+
if (issue) return {
|
|
4309
|
+
valid: false,
|
|
4310
|
+
data: void 0,
|
|
4311
|
+
errorMessage: issue.message
|
|
4312
|
+
};
|
|
4313
|
+
return {
|
|
4314
|
+
valid: true,
|
|
4315
|
+
data: input,
|
|
4316
|
+
errorMessage: void 0
|
|
4317
|
+
};
|
|
4318
|
+
};
|
|
42
4319
|
}
|
|
43
4320
|
};
|
|
44
4321
|
|
|
45
4322
|
//#endregion
|
|
46
4323
|
//#region src/browser-server.ts
|
|
4324
|
+
const DEFAULT_INPUT_SCHEMA = {
|
|
4325
|
+
type: "object",
|
|
4326
|
+
properties: {}
|
|
4327
|
+
};
|
|
4328
|
+
const DEFAULT_CLIENT_REQUEST_TIMEOUT = 1e4;
|
|
4329
|
+
function isPlainObject$1(value) {
|
|
4330
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
4331
|
+
}
|
|
4332
|
+
function isCallToolResult(value) {
|
|
4333
|
+
return isPlainObject$1(value) && Array.isArray(value.content);
|
|
4334
|
+
}
|
|
4335
|
+
function isJsonPrimitive(value) {
|
|
4336
|
+
return value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
4337
|
+
}
|
|
4338
|
+
function isJsonValue(value) {
|
|
4339
|
+
if (isJsonPrimitive(value)) return Number.isFinite(value) || typeof value !== "number";
|
|
4340
|
+
if (Array.isArray(value)) return value.every((entry) => isJsonValue(entry));
|
|
4341
|
+
if (!isPlainObject$1(value)) return false;
|
|
4342
|
+
return Object.values(value).every((entry) => isJsonValue(entry));
|
|
4343
|
+
}
|
|
4344
|
+
function toStructuredContent(value) {
|
|
4345
|
+
if (!isPlainObject$1(value) || !isJsonValue(value)) return;
|
|
4346
|
+
return value;
|
|
4347
|
+
}
|
|
4348
|
+
function serializeTextContent(value) {
|
|
4349
|
+
if (typeof value === "string") return value;
|
|
4350
|
+
try {
|
|
4351
|
+
return JSON.stringify(value) ?? String(value);
|
|
4352
|
+
} catch {
|
|
4353
|
+
return String(value);
|
|
4354
|
+
}
|
|
4355
|
+
}
|
|
4356
|
+
function normalizeToolResponse(value) {
|
|
4357
|
+
if (isCallToolResult(value)) return value;
|
|
4358
|
+
const structuredContent = toStructuredContent(value);
|
|
4359
|
+
return {
|
|
4360
|
+
content: [{
|
|
4361
|
+
type: "text",
|
|
4362
|
+
text: serializeTextContent(value)
|
|
4363
|
+
}],
|
|
4364
|
+
...structuredContent ? { structuredContent } : {},
|
|
4365
|
+
isError: false
|
|
4366
|
+
};
|
|
4367
|
+
}
|
|
4368
|
+
function withDefaultTimeout(options) {
|
|
4369
|
+
if (options?.signal) return options;
|
|
4370
|
+
return {
|
|
4371
|
+
...options,
|
|
4372
|
+
signal: AbortSignal.timeout(DEFAULT_CLIENT_REQUEST_TIMEOUT)
|
|
4373
|
+
};
|
|
4374
|
+
}
|
|
47
4375
|
/**
|
|
48
|
-
* Browser-optimized MCP Server
|
|
4376
|
+
* Browser-optimized MCP Server that speaks WebMCP natively.
|
|
49
4377
|
*
|
|
50
|
-
* This
|
|
51
|
-
*
|
|
52
|
-
*
|
|
4378
|
+
* This server IS navigator.modelContext — it implements the WebMCP standard API
|
|
4379
|
+
* (provideContext, registerTool, unregisterTool, clearContext) while retaining
|
|
4380
|
+
* full MCP protocol capabilities (resources, prompts, elicitation, sampling)
|
|
4381
|
+
* via the inherited BaseMcpServer surface.
|
|
53
4382
|
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
* - Allows items to be registered after transport is connected
|
|
57
|
-
* - Uses no-op JSON Schema validator to avoid ajv errors in browser environments
|
|
58
|
-
* - Designed for browser environments where items arrive asynchronously
|
|
4383
|
+
* When `native` is provided, all tool operations are mirrored to it so that
|
|
4384
|
+
* navigator.modelContextTesting (polyfill testing shim) stays in sync.
|
|
59
4385
|
*/
|
|
60
4386
|
var BrowserMcpServer = class extends McpServer {
|
|
4387
|
+
native;
|
|
4388
|
+
_promptSchemas = /* @__PURE__ */ new Map();
|
|
4389
|
+
_jsonValidator;
|
|
4390
|
+
_publicMethodsBound = false;
|
|
61
4391
|
constructor(serverInfo, options) {
|
|
4392
|
+
const validator = new PolyfillJsonSchemaValidator();
|
|
62
4393
|
const enhancedOptions = {
|
|
63
|
-
|
|
64
|
-
capabilities: mergeCapabilities$1(options?.capabilities || {}, {
|
|
4394
|
+
capabilities: mergeCapabilities(options?.capabilities || {}, {
|
|
65
4395
|
tools: { listChanged: true },
|
|
66
4396
|
resources: { listChanged: true },
|
|
67
4397
|
prompts: { listChanged: true }
|
|
68
4398
|
}),
|
|
69
|
-
jsonSchemaValidator: options?.jsonSchemaValidator ??
|
|
4399
|
+
jsonSchemaValidator: options?.jsonSchemaValidator ?? validator
|
|
70
4400
|
};
|
|
71
4401
|
super(serverInfo, enhancedOptions);
|
|
4402
|
+
this._jsonValidator = validator;
|
|
4403
|
+
this.native = options?.native;
|
|
4404
|
+
this.bindPublicApiMethods();
|
|
4405
|
+
}
|
|
4406
|
+
/**
|
|
4407
|
+
* navigator.modelContext consumers may destructure methods (e.g. const { registerTool } = ...).
|
|
4408
|
+
* Bind methods once so they remain callable outside instance-method invocation syntax.
|
|
4409
|
+
*/
|
|
4410
|
+
bindPublicApiMethods() {
|
|
4411
|
+
if (this._publicMethodsBound) return;
|
|
4412
|
+
this.registerTool = this.registerTool.bind(this);
|
|
4413
|
+
this.unregisterTool = this.unregisterTool.bind(this);
|
|
4414
|
+
this.provideContext = this.provideContext.bind(this);
|
|
4415
|
+
this.clearContext = this.clearContext.bind(this);
|
|
4416
|
+
this.listTools = this.listTools.bind(this);
|
|
4417
|
+
this.callTool = this.callTool.bind(this);
|
|
4418
|
+
this.executeTool = this.executeTool.bind(this);
|
|
4419
|
+
this.registerResource = this.registerResource.bind(this);
|
|
4420
|
+
this.listResources = this.listResources.bind(this);
|
|
4421
|
+
this.readResource = this.readResource.bind(this);
|
|
4422
|
+
this.registerPrompt = this.registerPrompt.bind(this);
|
|
4423
|
+
this.listPrompts = this.listPrompts.bind(this);
|
|
4424
|
+
this.getPrompt = this.getPrompt.bind(this);
|
|
4425
|
+
this.createMessage = this.createMessage.bind(this);
|
|
4426
|
+
this.elicitInput = this.elicitInput.bind(this);
|
|
4427
|
+
this._publicMethodsBound = true;
|
|
4428
|
+
}
|
|
4429
|
+
get _parentTools() {
|
|
4430
|
+
return this._registeredTools;
|
|
4431
|
+
}
|
|
4432
|
+
get _parentResources() {
|
|
4433
|
+
return this._registeredResources;
|
|
4434
|
+
}
|
|
4435
|
+
get _parentPrompts() {
|
|
4436
|
+
return this._registeredPrompts;
|
|
4437
|
+
}
|
|
4438
|
+
/**
|
|
4439
|
+
* Converts a schema (Zod or plain JSON Schema) to a transport-ready JSON Schema.
|
|
4440
|
+
* When `requireObjectType` is true (the default, for inputSchema), empty `{}` schemas
|
|
4441
|
+
* are normalized to `{ type: "object", properties: {} }` and schemas missing a root
|
|
4442
|
+
* `type` get `type: "object"` prepended — per MCP spec requirements.
|
|
4443
|
+
* When false (for outputSchema), no object-type normalization is applied.
|
|
4444
|
+
*/
|
|
4445
|
+
toTransportSchema(schema, requireObjectType = true) {
|
|
4446
|
+
if (!schema || typeof schema !== "object") {
|
|
4447
|
+
if (requireObjectType) {
|
|
4448
|
+
console.warn(`[BrowserMcpServer] toTransportSchema received non-object schema (${typeof schema}), using default`);
|
|
4449
|
+
return DEFAULT_INPUT_SCHEMA;
|
|
4450
|
+
}
|
|
4451
|
+
return {};
|
|
4452
|
+
}
|
|
4453
|
+
const normalized = normalizeObjectSchema(schema);
|
|
4454
|
+
const jsonSchema = normalized ? toJsonSchemaCompat(normalized, {
|
|
4455
|
+
strictUnions: true,
|
|
4456
|
+
pipeStrategy: "input"
|
|
4457
|
+
}) : schema;
|
|
4458
|
+
if (Object.keys(jsonSchema).length === 0) {
|
|
4459
|
+
if (requireObjectType) {
|
|
4460
|
+
console.warn("[BrowserMcpServer] toTransportSchema received empty {} schema, normalizing to default object schema");
|
|
4461
|
+
return DEFAULT_INPUT_SCHEMA;
|
|
4462
|
+
}
|
|
4463
|
+
return jsonSchema;
|
|
4464
|
+
}
|
|
4465
|
+
if (requireObjectType && jsonSchema.type === void 0) {
|
|
4466
|
+
console.warn("[BrowserMcpServer] toTransportSchema received schema without root type, prepending type:\"object\"");
|
|
4467
|
+
return {
|
|
4468
|
+
type: "object",
|
|
4469
|
+
...jsonSchema
|
|
4470
|
+
};
|
|
4471
|
+
}
|
|
4472
|
+
return jsonSchema;
|
|
4473
|
+
}
|
|
4474
|
+
isZodSchema(schema) {
|
|
4475
|
+
if (!schema || typeof schema !== "object") return false;
|
|
4476
|
+
const s = schema;
|
|
4477
|
+
return "_zod" in s || "_def" in s;
|
|
4478
|
+
}
|
|
4479
|
+
getNativeToolsApi() {
|
|
4480
|
+
if (!this.native) return;
|
|
4481
|
+
const candidate = this.native;
|
|
4482
|
+
if (typeof candidate.listTools !== "function" || typeof candidate.callTool !== "function") return;
|
|
4483
|
+
return candidate;
|
|
4484
|
+
}
|
|
4485
|
+
registerToolInServer(tool) {
|
|
4486
|
+
const inputSchema = this.toTransportSchema(tool.inputSchema);
|
|
4487
|
+
super.registerTool(tool.name, {
|
|
4488
|
+
description: tool.description,
|
|
4489
|
+
inputSchema,
|
|
4490
|
+
...tool.outputSchema ? { outputSchema: tool.outputSchema } : {},
|
|
4491
|
+
...tool.annotations ? { annotations: tool.annotations } : {}
|
|
4492
|
+
}, async (args) => {
|
|
4493
|
+
return normalizeToolResponse(await tool.execute(args, { requestUserInteraction: async (cb) => cb() }));
|
|
4494
|
+
});
|
|
4495
|
+
return { unregister: () => this.unregisterTool(tool.name) };
|
|
4496
|
+
}
|
|
4497
|
+
backfillTools(tools, execute) {
|
|
4498
|
+
let synced = 0;
|
|
4499
|
+
for (const sourceTool of tools) {
|
|
4500
|
+
if (!sourceTool?.name || this._parentTools[sourceTool.name]) continue;
|
|
4501
|
+
const toolDescriptor = {
|
|
4502
|
+
name: sourceTool.name,
|
|
4503
|
+
description: sourceTool.description ?? "",
|
|
4504
|
+
inputSchema: sourceTool.inputSchema ?? DEFAULT_INPUT_SCHEMA,
|
|
4505
|
+
execute: async (args) => execute(sourceTool.name, args)
|
|
4506
|
+
};
|
|
4507
|
+
if (sourceTool.outputSchema) toolDescriptor.outputSchema = sourceTool.outputSchema;
|
|
4508
|
+
if (sourceTool.annotations) toolDescriptor.annotations = sourceTool.annotations;
|
|
4509
|
+
this.registerToolInServer(toolDescriptor);
|
|
4510
|
+
synced++;
|
|
4511
|
+
}
|
|
4512
|
+
return synced;
|
|
4513
|
+
}
|
|
4514
|
+
registerTool(tool) {
|
|
4515
|
+
if (this.native) this.native.registerTool(tool);
|
|
4516
|
+
try {
|
|
4517
|
+
return this.registerToolInServer(tool);
|
|
4518
|
+
} catch (error) {
|
|
4519
|
+
if (this.native) try {
|
|
4520
|
+
this.native.unregisterTool(tool.name);
|
|
4521
|
+
} catch (rollbackError) {
|
|
4522
|
+
console.error("[BrowserMcpServer] Rollback of native tool registration failed:", rollbackError);
|
|
4523
|
+
}
|
|
4524
|
+
throw error;
|
|
4525
|
+
}
|
|
4526
|
+
}
|
|
4527
|
+
/**
|
|
4528
|
+
* Backfill tools that were already registered on the native/polyfill context
|
|
4529
|
+
* before this BrowserMcpServer wrapper was installed.
|
|
4530
|
+
*/
|
|
4531
|
+
syncNativeTools() {
|
|
4532
|
+
const nativeToolsApi = this.getNativeToolsApi();
|
|
4533
|
+
if (!nativeToolsApi) return 0;
|
|
4534
|
+
const nativeCallTool = nativeToolsApi.callTool.bind(nativeToolsApi);
|
|
4535
|
+
return this.backfillTools(nativeToolsApi.listTools(), async (name, args) => nativeCallTool({
|
|
4536
|
+
name,
|
|
4537
|
+
arguments: args
|
|
4538
|
+
}));
|
|
4539
|
+
}
|
|
4540
|
+
unregisterTool(name) {
|
|
4541
|
+
this._parentTools[name]?.remove();
|
|
4542
|
+
if (this.native) this.native.unregisterTool(name);
|
|
4543
|
+
}
|
|
4544
|
+
registerResource(descriptor) {
|
|
4545
|
+
const registered = super.registerResource(descriptor.name, descriptor.uri, {
|
|
4546
|
+
...descriptor.description !== void 0 && { description: descriptor.description },
|
|
4547
|
+
...descriptor.mimeType !== void 0 && { mimeType: descriptor.mimeType }
|
|
4548
|
+
}, async (uri) => ({ contents: (await descriptor.read(uri)).contents }));
|
|
4549
|
+
return { unregister: () => registered.remove() };
|
|
4550
|
+
}
|
|
4551
|
+
registerPrompt(descriptor) {
|
|
4552
|
+
if (descriptor.argsSchema) this._promptSchemas.set(descriptor.name, descriptor.argsSchema);
|
|
4553
|
+
const registered = super.registerPrompt(descriptor.name, { ...descriptor.description !== void 0 && { description: descriptor.description } }, async (args) => ({ messages: (await descriptor.get(args)).messages }));
|
|
4554
|
+
return { unregister: () => {
|
|
4555
|
+
this._promptSchemas.delete(descriptor.name);
|
|
4556
|
+
registered.remove();
|
|
4557
|
+
} };
|
|
4558
|
+
}
|
|
4559
|
+
provideContext(options) {
|
|
4560
|
+
for (const tool of Object.values(this._parentTools)) tool.remove();
|
|
4561
|
+
if (this.native) this.native.clearContext();
|
|
4562
|
+
for (const tool of options?.tools ?? []) this.registerTool(tool);
|
|
4563
|
+
}
|
|
4564
|
+
clearContext() {
|
|
4565
|
+
for (const tool of Object.values(this._parentTools)) tool.remove();
|
|
4566
|
+
if (this.native) this.native.clearContext();
|
|
4567
|
+
}
|
|
4568
|
+
listResources() {
|
|
4569
|
+
return Object.entries(this._parentResources).filter(([, resource]) => resource.enabled).map(([uri, resource]) => ({
|
|
4570
|
+
uri,
|
|
4571
|
+
name: resource.name,
|
|
4572
|
+
...resource.metadata
|
|
4573
|
+
}));
|
|
4574
|
+
}
|
|
4575
|
+
async readResource(uri) {
|
|
4576
|
+
const resource = this._parentResources[uri];
|
|
4577
|
+
if (!resource) throw new Error(`Resource not found: ${uri}`);
|
|
4578
|
+
return resource.readCallback(new URL(uri), {});
|
|
4579
|
+
}
|
|
4580
|
+
listPrompts() {
|
|
4581
|
+
return Object.entries(this._parentPrompts).filter(([, prompt]) => prompt.enabled).map(([name, prompt]) => {
|
|
4582
|
+
const schema = this._promptSchemas.get(name);
|
|
4583
|
+
return {
|
|
4584
|
+
name,
|
|
4585
|
+
...prompt.description !== void 0 && { description: prompt.description },
|
|
4586
|
+
...schema?.properties ? { arguments: Object.entries(schema.properties).map(([argName, prop]) => ({
|
|
4587
|
+
name: argName,
|
|
4588
|
+
...typeof prop === "object" && prop !== null && "description" in prop ? { description: prop.description } : {},
|
|
4589
|
+
...schema.required?.includes(argName) ? { required: true } : {}
|
|
4590
|
+
})) } : {}
|
|
4591
|
+
};
|
|
4592
|
+
});
|
|
4593
|
+
}
|
|
4594
|
+
async getPrompt(name, args = {}) {
|
|
4595
|
+
const prompt = this._parentPrompts[name];
|
|
4596
|
+
if (!prompt) throw new Error(`Prompt not found: ${name}`);
|
|
4597
|
+
const schema = this._promptSchemas.get(name);
|
|
4598
|
+
if (schema) {
|
|
4599
|
+
const result = this._jsonValidator.getValidator(schema)(args);
|
|
4600
|
+
if (!result.valid) throw new Error(`Invalid arguments for prompt ${name}: ${result.errorMessage}`);
|
|
4601
|
+
}
|
|
4602
|
+
return prompt.callback(args, {});
|
|
4603
|
+
}
|
|
4604
|
+
listTools() {
|
|
4605
|
+
return Object.entries(this._parentTools).filter(([, tool]) => tool.enabled).map(([name, tool]) => {
|
|
4606
|
+
const item = {
|
|
4607
|
+
name,
|
|
4608
|
+
description: tool.description ?? "",
|
|
4609
|
+
inputSchema: this.toTransportSchema(tool.inputSchema ?? DEFAULT_INPUT_SCHEMA)
|
|
4610
|
+
};
|
|
4611
|
+
if (tool.outputSchema) item.outputSchema = this.toTransportSchema(tool.outputSchema, false);
|
|
4612
|
+
if (tool.annotations) item.annotations = tool.annotations;
|
|
4613
|
+
return item;
|
|
4614
|
+
});
|
|
4615
|
+
}
|
|
4616
|
+
/**
|
|
4617
|
+
* Override SDK's validateToolInput to handle both Zod schemas and plain JSON Schema.
|
|
4618
|
+
* Zod schemas use the SDK's safeParseAsync; plain JSON Schema uses PolyfillJsonSchemaValidator.
|
|
4619
|
+
*/
|
|
4620
|
+
async validateToolInput(tool, args, toolName) {
|
|
4621
|
+
if (!tool.inputSchema) return void 0;
|
|
4622
|
+
if (this.isZodSchema(tool.inputSchema)) {
|
|
4623
|
+
const result$1 = await safeParseAsync(tool.inputSchema, args ?? {});
|
|
4624
|
+
if (!result$1.success) throw new Error(`Invalid arguments for tool ${toolName}: ${getParseErrorMessage(result$1.error)}`);
|
|
4625
|
+
return result$1.data;
|
|
4626
|
+
}
|
|
4627
|
+
const result = this._jsonValidator.getValidator(tool.inputSchema)(args ?? {});
|
|
4628
|
+
if (!result.valid) throw new Error(`Invalid arguments for tool ${toolName}: ${result.errorMessage}`);
|
|
4629
|
+
return result.data;
|
|
4630
|
+
}
|
|
4631
|
+
/**
|
|
4632
|
+
* Override SDK's validateToolOutput to handle both Zod schemas and plain JSON Schema.
|
|
4633
|
+
*/
|
|
4634
|
+
async validateToolOutput(tool, result, toolName) {
|
|
4635
|
+
if (!tool.outputSchema) return;
|
|
4636
|
+
const r = result;
|
|
4637
|
+
if (!("content" in r) || r.isError || !r.structuredContent) return;
|
|
4638
|
+
if (this.isZodSchema(tool.outputSchema)) {
|
|
4639
|
+
const parseResult = await safeParseAsync(tool.outputSchema, r.structuredContent);
|
|
4640
|
+
if (!parseResult.success) throw new Error(`Output validation error: Invalid structured content for tool ${toolName}: ${getParseErrorMessage(parseResult.error)}`);
|
|
4641
|
+
return;
|
|
4642
|
+
}
|
|
4643
|
+
const validationResult = this._jsonValidator.getValidator(tool.outputSchema)(r.structuredContent);
|
|
4644
|
+
if (!validationResult.valid) throw new Error(`Output validation error: Invalid structured content for tool ${toolName}: ${validationResult.errorMessage}`);
|
|
4645
|
+
}
|
|
4646
|
+
async callTool(params) {
|
|
4647
|
+
const tool = this._parentTools[params.name];
|
|
4648
|
+
if (!tool) throw new Error(`Tool not found: ${params.name}`);
|
|
4649
|
+
return tool.handler(params.arguments ?? {}, {});
|
|
4650
|
+
}
|
|
4651
|
+
async executeTool(name, args = {}) {
|
|
4652
|
+
return this.callTool({
|
|
4653
|
+
name,
|
|
4654
|
+
arguments: args
|
|
4655
|
+
});
|
|
72
4656
|
}
|
|
73
4657
|
/**
|
|
74
|
-
* Override connect to
|
|
75
|
-
*
|
|
4658
|
+
* Override connect to initialize request handlers BEFORE the transport connection.
|
|
4659
|
+
* This prevents "Cannot register capabilities after connecting to transport" errors
|
|
4660
|
+
* when tools are registered dynamically after connection.
|
|
76
4661
|
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
4662
|
+
* After the parent sets up its Zod-based handlers, we replace the ones that break
|
|
4663
|
+
* with plain JSON Schema objects (ListTools, ListPrompts, GetPrompt).
|
|
79
4664
|
*/
|
|
80
4665
|
async connect(transport) {
|
|
81
4666
|
this.setToolRequestHandlers();
|
|
4667
|
+
this.setResourceRequestHandlers();
|
|
4668
|
+
this.setPromptRequestHandlers();
|
|
4669
|
+
this.server.setRequestHandler(ListToolsRequestSchema, () => ({ tools: this.listTools() }));
|
|
4670
|
+
this.server.setRequestHandler(ListPromptsRequestSchema, () => ({ prompts: this.listPrompts() }));
|
|
4671
|
+
this.server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
4672
|
+
const prompt = this._parentPrompts[request.params.name];
|
|
4673
|
+
if (!prompt) throw new Error(`Prompt ${request.params.name} not found`);
|
|
4674
|
+
if (!prompt.enabled) throw new Error(`Prompt ${request.params.name} disabled`);
|
|
4675
|
+
const schema = this._promptSchemas.get(request.params.name);
|
|
4676
|
+
if (schema) {
|
|
4677
|
+
const result = this._jsonValidator.getValidator(schema)(request.params.arguments ?? {});
|
|
4678
|
+
if (!result.valid) throw new Error(`Invalid arguments for prompt ${request.params.name}: ${result.errorMessage}`);
|
|
4679
|
+
return prompt.callback(request.params.arguments, {});
|
|
4680
|
+
}
|
|
4681
|
+
return prompt.callback({}, {});
|
|
4682
|
+
});
|
|
82
4683
|
return super.connect(transport);
|
|
83
4684
|
}
|
|
4685
|
+
async createMessage(params, options) {
|
|
4686
|
+
return this.server.createMessage(params, withDefaultTimeout(options));
|
|
4687
|
+
}
|
|
4688
|
+
async elicitInput(params, options) {
|
|
4689
|
+
return this.server.elicitInput(params, withDefaultTimeout(options));
|
|
4690
|
+
}
|
|
4691
|
+
};
|
|
4692
|
+
|
|
4693
|
+
//#endregion
|
|
4694
|
+
//#region src/no-op-validator.ts
|
|
4695
|
+
/**
|
|
4696
|
+
* A no-op JSON Schema validator that always returns valid.
|
|
4697
|
+
*
|
|
4698
|
+
* Use this in browser environments where:
|
|
4699
|
+
* - ajv causes "Error compiling schema" errors
|
|
4700
|
+
* - Validation is already handled elsewhere (e.g., by Zod)
|
|
4701
|
+
* - You need to avoid eval/Function constructor restrictions
|
|
4702
|
+
*
|
|
4703
|
+
* @example
|
|
4704
|
+
* ```typescript
|
|
4705
|
+
* import { BrowserMcpServer } from '@mcp-b/webmcp-ts-sdk';
|
|
4706
|
+
* import { NoOpJsonSchemaValidator } from '@mcp-b/webmcp-ts-sdk/no-op-validator';
|
|
4707
|
+
*
|
|
4708
|
+
* const server = new BrowserMcpServer(
|
|
4709
|
+
* { name: 'my-server', version: '1.0.0' },
|
|
4710
|
+
* { jsonSchemaValidator: new NoOpJsonSchemaValidator() }
|
|
4711
|
+
* );
|
|
4712
|
+
* ```
|
|
4713
|
+
*/
|
|
4714
|
+
var NoOpJsonSchemaValidator = class {
|
|
4715
|
+
/**
|
|
4716
|
+
* Returns a validator function that always passes.
|
|
4717
|
+
* The input data is passed through unchanged.
|
|
4718
|
+
*
|
|
4719
|
+
* @param _schema - The JSON Schema (ignored)
|
|
4720
|
+
* @returns A validator function that always returns valid
|
|
4721
|
+
*/
|
|
4722
|
+
getValidator(_schema) {
|
|
4723
|
+
return (input) => ({
|
|
4724
|
+
valid: true,
|
|
4725
|
+
data: input,
|
|
4726
|
+
errorMessage: void 0
|
|
4727
|
+
});
|
|
4728
|
+
}
|
|
84
4729
|
};
|
|
85
4730
|
|
|
86
4731
|
//#endregion
|
|
87
|
-
export { BrowserMcpServer, BrowserMcpServer as McpServer, CallToolRequestSchema, CallToolResultSchema, Client, CreateMessageRequestSchema, CreateMessageResultSchema, ElicitRequestSchema, ElicitResultSchema, ErrorCode, GetPromptRequestSchema, GetPromptResultSchema, InitializeRequestSchema, InitializeResultSchema, JSONRPCMessageSchema, LATEST_PROTOCOL_VERSION, ListPromptsRequestSchema, ListPromptsResultSchema, ListResourcesRequestSchema, ListResourcesResultSchema, ListToolsRequestSchema, ListToolsResultSchema, LoggingLevelSchema, NoOpJsonSchemaValidator, ReadBuffer, ReadResourceRequestSchema, ReadResourceResultSchema, ResourceListChangedNotificationSchema, SUPPORTED_PROTOCOL_VERSIONS,
|
|
4732
|
+
export { BrowserMcpServer, BrowserMcpServer as McpServer, CallToolRequestSchema, CallToolResultSchema, Client, CreateMessageRequestSchema, CreateMessageResultSchema, ElicitRequestSchema, ElicitResultSchema, ErrorCode, GetPromptRequestSchema, GetPromptResultSchema, InitializeRequestSchema, InitializeResultSchema, JSONRPCMessageSchema, LATEST_PROTOCOL_VERSION, ListPromptsRequestSchema, ListPromptsResultSchema, ListResourcesRequestSchema, ListResourcesResultSchema, ListToolsRequestSchema, ListToolsResultSchema, LoggingLevelSchema, NoOpJsonSchemaValidator, PolyfillJsonSchemaValidator, ReadBuffer, ReadResourceRequestSchema, ReadResourceResultSchema, ResourceListChangedNotificationSchema, SUPPORTED_PROTOCOL_VERSIONS, ToolListChangedNotificationSchema, mergeCapabilities, serializeMessage };
|
|
88
4733
|
//# sourceMappingURL=index.js.map
|