@modelcontextprotocol/server 2.0.0-alpha.2 → 2.0.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -2
- package/dist/{src-IKPjmxu7.mjs → ajvProvider-Birb50r-.mjs} +21 -3421
- package/dist/ajvProvider-Birb50r-.mjs.map +1 -0
- package/dist/ajvProvider-DZ_siXcF.d.mts +983 -0
- package/dist/ajvProvider-DZ_siXcF.d.mts.map +1 -0
- package/dist/cfWorkerProvider-BrJKpSFH.mjs +954 -0
- package/dist/cfWorkerProvider-BrJKpSFH.mjs.map +1 -0
- package/dist/cfWorkerProvider-DUhk5Ewx.d.mts +52 -0
- package/dist/cfWorkerProvider-DUhk5Ewx.d.mts.map +1 -0
- package/dist/chunk-BRhqBsOc.mjs +42 -0
- package/dist/index.d.mts +1526 -334
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +91 -766
- package/dist/index.mjs.map +1 -1
- package/dist/shimsNode.d.mts +1 -1
- package/dist/shimsNode.mjs +1 -1
- package/dist/shimsWorkerd.d.mts +1 -1
- package/dist/shimsWorkerd.mjs +1 -1
- package/dist/shimsWorkerd.mjs.map +1 -1
- package/dist/src-Pa1iAvsj.mjs +3386 -0
- package/dist/src-Pa1iAvsj.mjs.map +1 -0
- package/dist/stdio.d.mts +49 -0
- package/dist/stdio.d.mts.map +1 -0
- package/dist/stdio.mjs +106 -0
- package/dist/stdio.mjs.map +1 -0
- package/dist/{index-Bhfkexnj.d.mts → transport-DMKhEchd.d.mts} +636 -1907
- package/dist/transport-DMKhEchd.d.mts.map +1 -0
- package/dist/types-R2RTIcjk.d.mts +66 -0
- package/dist/types-R2RTIcjk.d.mts.map +1 -0
- package/dist/validators/ajv.d.mts +2 -0
- package/dist/validators/ajv.mjs +4 -0
- package/dist/validators/cfWorker.d.mts +2 -0
- package/dist/validators/cfWorker.mjs +3 -0
- package/package.json +35 -16
- package/dist/index-Bhfkexnj.d.mts.map +0 -1
- package/dist/src-IKPjmxu7.mjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { $ as
|
|
2
|
-
import { DefaultJsonSchemaValidator
|
|
1
|
+
import { $ as LATEST_PROTOCOL_VERSION, A as isTaskAugmentedRequestParams, B as LoggingLevelSchema, C as isInitializeRequest, D as isJSONRPCRequest, E as isJSONRPCNotification, F as CreateMessageResultWithToolsSchema, G as BAGGAGE_META_KEY, H as UnsupportedProtocolVersionError, I as ElicitResultSchema, J as DEFAULT_NEGOTIATED_PROTOCOL_VERSION, K as CLIENT_CAPABILITIES_META_KEY, L as EmptyResultSchema, M as CallToolRequestSchema, N as CallToolResultSchema, O as isJSONRPCResponse, P as CreateMessageResultSchema, Q as JSONRPC_VERSION, R as JSONRPCMessageSchema, S as isCallToolResult, T as isJSONRPCErrorResponse, U as UrlElicitationRequiredError, V as ProtocolError, W as ProtocolErrorCode, X as INVALID_PARAMS, Y as INTERNAL_ERROR, Z as INVALID_REQUEST, _ as validateStandardSchema, a as UriTemplate, at as SUPPORTED_PROTOCOL_VERSIONS, b as assertCompleteRequestPrompt, c as ReadBuffer, ct as getDisplayName, d as serializeMessage, dt as SdkError, et as LOG_LEVEL_META_KEY, f as DEFAULT_REQUEST_TIMEOUT_MSEC, ft as SdkErrorCode, g as standardSchemaToJsonSchema, h as promptArgumentsFromStandardSchema, ht as OAuthErrorCode, i as InMemoryTransport, it as RELATED_TASK_META_KEY, j as parseJSONRPCMessage, k as isJSONRPCResultResponse, l as STDIO_DEFAULT_MAX_BUFFER_SIZE, lt as checkResourceAllowed, m as mergeCapabilities, mt as OAuthError, n as normalizeRawShapeSchema, nt as PARSE_ERROR, o as createFetchWithInit, ot as TRACEPARENT_META_KEY, p as Protocol, pt as SdkHttpError, q as CLIENT_INFO_META_KEY, r as parseSchema, rt as PROTOCOL_VERSION_META_KEY, s as validateAndWarnToolName, st as TRACESTATE_META_KEY, t as fromJsonSchema$1, tt as METHOD_NOT_FOUND, u as deserializeMessage, ut as resourceUrlFromServerUrl, v as isSpecType, w as isInitializedNotification, x as assertCompleteRequestResourceTemplate, y as specTypeSchemas, z as ListRootsResultSchema } from "./src-Pa1iAvsj.mjs";
|
|
2
|
+
import { DefaultJsonSchemaValidator } from "@modelcontextprotocol/server/_shims";
|
|
3
3
|
|
|
4
4
|
//#region src/server/completable.ts
|
|
5
5
|
const COMPLETABLE_SYMBOL = Symbol.for("mcp.completable");
|
|
@@ -56,504 +56,6 @@ function getCompleter(schema) {
|
|
|
56
56
|
return schema[COMPLETABLE_SYMBOL]?.complete;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
//#endregion
|
|
60
|
-
//#region ../core/src/experimental/tasks/helpers.ts
|
|
61
|
-
/**
|
|
62
|
-
* Experimental task capability assertion helpers.
|
|
63
|
-
* WARNING: These APIs are experimental and may change without notice.
|
|
64
|
-
*
|
|
65
|
-
* @experimental
|
|
66
|
-
*/
|
|
67
|
-
/**
|
|
68
|
-
* Asserts that task creation is supported for `tools/call`.
|
|
69
|
-
* Used to implement the `assertTaskCapability` or `assertTaskHandlerCapability` abstract methods on Protocol.
|
|
70
|
-
*
|
|
71
|
-
* @param requests - The task requests capability object
|
|
72
|
-
* @param method - The method being checked
|
|
73
|
-
* @param entityName - `'Server'` or `'Client'` for error messages
|
|
74
|
-
* @throws {@linkcode SdkError} with {@linkcode SdkErrorCode.CapabilityNotSupported} if the capability is not supported
|
|
75
|
-
*
|
|
76
|
-
* @experimental
|
|
77
|
-
*/
|
|
78
|
-
function assertToolsCallTaskCapability(requests, method, entityName) {
|
|
79
|
-
if (!requests) throw new SdkError(SdkErrorCode.CapabilityNotSupported, `${entityName} does not support task creation (required for ${method})`);
|
|
80
|
-
switch (method) {
|
|
81
|
-
case "tools/call":
|
|
82
|
-
if (!requests.tools?.call) throw new SdkError(SdkErrorCode.CapabilityNotSupported, `${entityName} does not support task creation for tools/call (required for ${method})`);
|
|
83
|
-
break;
|
|
84
|
-
default: break;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Asserts that task creation is supported for `sampling/createMessage` or `elicitation/create`.
|
|
89
|
-
* Used to implement the `assertTaskCapability` or `assertTaskHandlerCapability` abstract methods on Protocol.
|
|
90
|
-
*
|
|
91
|
-
* @param requests - The task requests capability object
|
|
92
|
-
* @param method - The method being checked
|
|
93
|
-
* @param entityName - `'Server'` or `'Client'` for error messages
|
|
94
|
-
* @throws {@linkcode SdkError} with {@linkcode SdkErrorCode.CapabilityNotSupported} if the capability is not supported
|
|
95
|
-
*
|
|
96
|
-
* @experimental
|
|
97
|
-
*/
|
|
98
|
-
function assertClientRequestTaskCapability(requests, method, entityName) {
|
|
99
|
-
if (!requests) throw new SdkError(SdkErrorCode.CapabilityNotSupported, `${entityName} does not support task creation (required for ${method})`);
|
|
100
|
-
switch (method) {
|
|
101
|
-
case "sampling/createMessage":
|
|
102
|
-
if (!requests.sampling?.createMessage) throw new SdkError(SdkErrorCode.CapabilityNotSupported, `${entityName} does not support task creation for sampling/createMessage (required for ${method})`);
|
|
103
|
-
break;
|
|
104
|
-
case "elicitation/create":
|
|
105
|
-
if (!requests.elicitation?.create) throw new SdkError(SdkErrorCode.CapabilityNotSupported, `${entityName} does not support task creation for elicitation/create (required for ${method})`);
|
|
106
|
-
break;
|
|
107
|
-
default: break;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
//#endregion
|
|
112
|
-
//#region ../core/src/experimental/tasks/stores/inMemory.ts
|
|
113
|
-
/**
|
|
114
|
-
* In-memory {@linkcode TaskStore} implementation for development and testing.
|
|
115
|
-
* For production, use a database or distributed cache.
|
|
116
|
-
* @experimental
|
|
117
|
-
*/
|
|
118
|
-
var InMemoryTaskStore = class {
|
|
119
|
-
tasks = /* @__PURE__ */ new Map();
|
|
120
|
-
cleanupTimers = /* @__PURE__ */ new Map();
|
|
121
|
-
/**
|
|
122
|
-
* Generates a unique task ID using Web Crypto API.
|
|
123
|
-
*/
|
|
124
|
-
generateTaskId() {
|
|
125
|
-
return crypto.randomUUID().replaceAll("-", "");
|
|
126
|
-
}
|
|
127
|
-
/** {@inheritDoc TaskStore.createTask} */
|
|
128
|
-
async createTask(taskParams, requestId, request, sessionId) {
|
|
129
|
-
const taskId = this.generateTaskId();
|
|
130
|
-
if (this.tasks.has(taskId)) throw new Error(`Task with ID ${taskId} already exists`);
|
|
131
|
-
const actualTtl = taskParams.ttl ?? null;
|
|
132
|
-
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
133
|
-
const task = {
|
|
134
|
-
taskId,
|
|
135
|
-
status: "working",
|
|
136
|
-
ttl: actualTtl,
|
|
137
|
-
createdAt,
|
|
138
|
-
lastUpdatedAt: createdAt,
|
|
139
|
-
pollInterval: taskParams.pollInterval ?? 1e3
|
|
140
|
-
};
|
|
141
|
-
this.tasks.set(taskId, {
|
|
142
|
-
task,
|
|
143
|
-
request,
|
|
144
|
-
requestId,
|
|
145
|
-
sessionId
|
|
146
|
-
});
|
|
147
|
-
if (actualTtl) {
|
|
148
|
-
const timer = setTimeout(() => {
|
|
149
|
-
this.tasks.delete(taskId);
|
|
150
|
-
this.cleanupTimers.delete(taskId);
|
|
151
|
-
}, actualTtl);
|
|
152
|
-
this.cleanupTimers.set(taskId, timer);
|
|
153
|
-
}
|
|
154
|
-
return task;
|
|
155
|
-
}
|
|
156
|
-
/**
|
|
157
|
-
* Retrieves a stored task, enforcing session ownership when a sessionId is provided.
|
|
158
|
-
* Returns undefined if the task does not exist or belongs to a different session.
|
|
159
|
-
*/
|
|
160
|
-
getStoredTask(taskId, sessionId) {
|
|
161
|
-
const stored = this.tasks.get(taskId);
|
|
162
|
-
if (!stored) return;
|
|
163
|
-
if (sessionId !== void 0 && stored.sessionId !== void 0 && stored.sessionId !== sessionId) return;
|
|
164
|
-
return stored;
|
|
165
|
-
}
|
|
166
|
-
async getTask(taskId, sessionId) {
|
|
167
|
-
const stored = this.getStoredTask(taskId, sessionId);
|
|
168
|
-
return stored ? { ...stored.task } : null;
|
|
169
|
-
}
|
|
170
|
-
/** {@inheritDoc TaskStore.storeTaskResult} */
|
|
171
|
-
async storeTaskResult(taskId, status, result, sessionId) {
|
|
172
|
-
const stored = this.getStoredTask(taskId, sessionId);
|
|
173
|
-
if (!stored) throw new Error(`Task with ID ${taskId} not found`);
|
|
174
|
-
if (isTerminal(stored.task.status)) throw new Error(`Cannot store result for task ${taskId} in terminal status '${stored.task.status}'. Task results can only be stored once.`);
|
|
175
|
-
stored.result = result;
|
|
176
|
-
stored.task.status = status;
|
|
177
|
-
stored.task.lastUpdatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
178
|
-
if (stored.task.ttl) {
|
|
179
|
-
const existingTimer = this.cleanupTimers.get(taskId);
|
|
180
|
-
if (existingTimer) clearTimeout(existingTimer);
|
|
181
|
-
const timer = setTimeout(() => {
|
|
182
|
-
this.tasks.delete(taskId);
|
|
183
|
-
this.cleanupTimers.delete(taskId);
|
|
184
|
-
}, stored.task.ttl);
|
|
185
|
-
this.cleanupTimers.set(taskId, timer);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
/** {@inheritDoc TaskStore.getTaskResult} */
|
|
189
|
-
async getTaskResult(taskId, sessionId) {
|
|
190
|
-
const stored = this.getStoredTask(taskId, sessionId);
|
|
191
|
-
if (!stored) throw new Error(`Task with ID ${taskId} not found`);
|
|
192
|
-
if (!stored.result) throw new Error(`Task ${taskId} has no result stored`);
|
|
193
|
-
return stored.result;
|
|
194
|
-
}
|
|
195
|
-
/** {@inheritDoc TaskStore.updateTaskStatus} */
|
|
196
|
-
async updateTaskStatus(taskId, status, statusMessage, sessionId) {
|
|
197
|
-
const stored = this.getStoredTask(taskId, sessionId);
|
|
198
|
-
if (!stored) throw new Error(`Task with ID ${taskId} not found`);
|
|
199
|
-
if (isTerminal(stored.task.status)) throw new Error(`Cannot update task ${taskId} from terminal status '${stored.task.status}' to '${status}'. Terminal states (completed, failed, cancelled) cannot transition to other states.`);
|
|
200
|
-
stored.task.status = status;
|
|
201
|
-
if (statusMessage) stored.task.statusMessage = statusMessage;
|
|
202
|
-
stored.task.lastUpdatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
203
|
-
if (isTerminal(status) && stored.task.ttl) {
|
|
204
|
-
const existingTimer = this.cleanupTimers.get(taskId);
|
|
205
|
-
if (existingTimer) clearTimeout(existingTimer);
|
|
206
|
-
const timer = setTimeout(() => {
|
|
207
|
-
this.tasks.delete(taskId);
|
|
208
|
-
this.cleanupTimers.delete(taskId);
|
|
209
|
-
}, stored.task.ttl);
|
|
210
|
-
this.cleanupTimers.set(taskId, timer);
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
/** {@inheritDoc TaskStore.listTasks} */
|
|
214
|
-
async listTasks(cursor, sessionId) {
|
|
215
|
-
const PAGE_SIZE = 10;
|
|
216
|
-
const filteredTaskIds = [...this.tasks.entries()].filter(([, stored]) => {
|
|
217
|
-
if (sessionId === void 0 || stored.sessionId === void 0) return true;
|
|
218
|
-
return stored.sessionId === sessionId;
|
|
219
|
-
}).map(([taskId]) => taskId);
|
|
220
|
-
let startIndex = 0;
|
|
221
|
-
if (cursor) {
|
|
222
|
-
const cursorIndex = filteredTaskIds.indexOf(cursor);
|
|
223
|
-
if (cursorIndex === -1) throw new Error(`Invalid cursor: ${cursor}`);
|
|
224
|
-
else startIndex = cursorIndex + 1;
|
|
225
|
-
}
|
|
226
|
-
const pageTaskIds = filteredTaskIds.slice(startIndex, startIndex + PAGE_SIZE);
|
|
227
|
-
return {
|
|
228
|
-
tasks: pageTaskIds.map((taskId) => {
|
|
229
|
-
return { ...this.tasks.get(taskId).task };
|
|
230
|
-
}),
|
|
231
|
-
nextCursor: startIndex + PAGE_SIZE < filteredTaskIds.length ? pageTaskIds.at(-1) : void 0
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
|
-
/**
|
|
235
|
-
* Cleanup all timers (useful for testing or graceful shutdown)
|
|
236
|
-
*/
|
|
237
|
-
cleanup() {
|
|
238
|
-
for (const timer of this.cleanupTimers.values()) clearTimeout(timer);
|
|
239
|
-
this.cleanupTimers.clear();
|
|
240
|
-
this.tasks.clear();
|
|
241
|
-
}
|
|
242
|
-
/**
|
|
243
|
-
* Get all tasks (useful for debugging)
|
|
244
|
-
*/
|
|
245
|
-
getAllTasks() {
|
|
246
|
-
return [...this.tasks.values()].map((stored) => ({ ...stored.task }));
|
|
247
|
-
}
|
|
248
|
-
};
|
|
249
|
-
/**
|
|
250
|
-
* In-memory {@linkcode TaskMessageQueue} implementation for development and testing.
|
|
251
|
-
* For production, use Redis or another distributed queue.
|
|
252
|
-
* @experimental
|
|
253
|
-
*/
|
|
254
|
-
var InMemoryTaskMessageQueue = class {
|
|
255
|
-
queues = /* @__PURE__ */ new Map();
|
|
256
|
-
/**
|
|
257
|
-
* Generates a queue key from taskId.
|
|
258
|
-
* SessionId is intentionally ignored because taskIds are globally unique
|
|
259
|
-
* and tasks need to be accessible across HTTP requests/sessions.
|
|
260
|
-
*/
|
|
261
|
-
getQueueKey(taskId, _sessionId) {
|
|
262
|
-
return taskId;
|
|
263
|
-
}
|
|
264
|
-
/**
|
|
265
|
-
* Gets or creates a queue for the given task and session.
|
|
266
|
-
*/
|
|
267
|
-
getQueue(taskId, sessionId) {
|
|
268
|
-
const key = this.getQueueKey(taskId, sessionId);
|
|
269
|
-
let queue = this.queues.get(key);
|
|
270
|
-
if (!queue) {
|
|
271
|
-
queue = [];
|
|
272
|
-
this.queues.set(key, queue);
|
|
273
|
-
}
|
|
274
|
-
return queue;
|
|
275
|
-
}
|
|
276
|
-
/**
|
|
277
|
-
* Adds a message to the end of the queue for a specific task.
|
|
278
|
-
* Atomically checks queue size and throws if maxSize would be exceeded.
|
|
279
|
-
* @param taskId The task identifier
|
|
280
|
-
* @param message The message to enqueue
|
|
281
|
-
* @param sessionId Optional session ID for binding the operation to a specific session
|
|
282
|
-
* @param maxSize Optional maximum queue size - if specified and queue is full, throws an error
|
|
283
|
-
* @throws Error if maxSize is specified and would be exceeded
|
|
284
|
-
*/
|
|
285
|
-
async enqueue(taskId, message, sessionId, maxSize) {
|
|
286
|
-
const queue = this.getQueue(taskId, sessionId);
|
|
287
|
-
if (maxSize !== void 0 && queue.length >= maxSize) throw new Error(`Task message queue overflow: queue size (${queue.length}) exceeds maximum (${maxSize})`);
|
|
288
|
-
queue.push(message);
|
|
289
|
-
}
|
|
290
|
-
/**
|
|
291
|
-
* Removes and returns the first message from the queue for a specific task.
|
|
292
|
-
* @param taskId The task identifier
|
|
293
|
-
* @param sessionId Optional session ID for binding the query to a specific session
|
|
294
|
-
* @returns The first message, or `undefined` if the queue is empty
|
|
295
|
-
*/
|
|
296
|
-
async dequeue(taskId, sessionId) {
|
|
297
|
-
return this.getQueue(taskId, sessionId).shift();
|
|
298
|
-
}
|
|
299
|
-
/**
|
|
300
|
-
* Removes and returns all messages from the queue for a specific task.
|
|
301
|
-
* @param taskId The task identifier
|
|
302
|
-
* @param sessionId Optional session ID for binding the query to a specific session
|
|
303
|
-
* @returns Array of all messages that were in the queue
|
|
304
|
-
*/
|
|
305
|
-
async dequeueAll(taskId, sessionId) {
|
|
306
|
-
const key = this.getQueueKey(taskId, sessionId);
|
|
307
|
-
const queue = this.queues.get(key) ?? [];
|
|
308
|
-
this.queues.delete(key);
|
|
309
|
-
return queue;
|
|
310
|
-
}
|
|
311
|
-
};
|
|
312
|
-
|
|
313
|
-
//#endregion
|
|
314
|
-
//#region src/experimental/tasks/mcpServer.ts
|
|
315
|
-
/**
|
|
316
|
-
* Experimental task features for {@linkcode McpServer}.
|
|
317
|
-
*
|
|
318
|
-
* Access via `server.experimental.tasks`:
|
|
319
|
-
* ```typescript
|
|
320
|
-
* server.experimental.tasks.registerToolTask('long-running', config, handler);
|
|
321
|
-
* ```
|
|
322
|
-
*
|
|
323
|
-
* @experimental
|
|
324
|
-
*/
|
|
325
|
-
var ExperimentalMcpServerTasks = class {
|
|
326
|
-
constructor(_mcpServer) {
|
|
327
|
-
this._mcpServer = _mcpServer;
|
|
328
|
-
}
|
|
329
|
-
registerToolTask(name, config, handler) {
|
|
330
|
-
const execution = {
|
|
331
|
-
taskSupport: "required",
|
|
332
|
-
...config.execution
|
|
333
|
-
};
|
|
334
|
-
if (execution.taskSupport === "forbidden") throw new Error(`Cannot register task-based tool '${name}' with taskSupport 'forbidden'. Use registerTool() instead.`);
|
|
335
|
-
return this._mcpServer._createRegisteredTool(name, config.title, config.description, config.inputSchema, config.outputSchema, config.annotations, execution, config._meta, handler);
|
|
336
|
-
}
|
|
337
|
-
};
|
|
338
|
-
|
|
339
|
-
//#endregion
|
|
340
|
-
//#region src/experimental/tasks/server.ts
|
|
341
|
-
/**
|
|
342
|
-
* Experimental task features for low-level MCP servers.
|
|
343
|
-
*
|
|
344
|
-
* Access via `server.experimental.tasks`:
|
|
345
|
-
* ```typescript
|
|
346
|
-
* const stream = server.experimental.tasks.requestStream(request, options);
|
|
347
|
-
* ```
|
|
348
|
-
*
|
|
349
|
-
* For high-level server usage with task-based tools, use {@linkcode index.McpServer | McpServer}.experimental.tasks instead.
|
|
350
|
-
*
|
|
351
|
-
* @experimental
|
|
352
|
-
*/
|
|
353
|
-
var ExperimentalServerTasks = class {
|
|
354
|
-
constructor(_server) {
|
|
355
|
-
this._server = _server;
|
|
356
|
-
}
|
|
357
|
-
get _module() {
|
|
358
|
-
return this._server.taskManager;
|
|
359
|
-
}
|
|
360
|
-
/**
|
|
361
|
-
* Sends a request and returns an AsyncGenerator that yields response messages.
|
|
362
|
-
* The generator is guaranteed to end with either a `'result'` or `'error'` message.
|
|
363
|
-
*
|
|
364
|
-
* This method provides streaming access to request processing, allowing you to
|
|
365
|
-
* observe intermediate task status updates for task-augmented requests.
|
|
366
|
-
*
|
|
367
|
-
* @param request - The request to send (method name determines the result schema)
|
|
368
|
-
* @param options - Optional request options (timeout, signal, task creation params, etc.)
|
|
369
|
-
* @returns AsyncGenerator that yields {@linkcode ResponseMessage} objects
|
|
370
|
-
*
|
|
371
|
-
* @experimental
|
|
372
|
-
*/
|
|
373
|
-
requestStream(request, options) {
|
|
374
|
-
const resultSchema = getResultSchema(request.method);
|
|
375
|
-
return this._module.requestStream(request, resultSchema, options);
|
|
376
|
-
}
|
|
377
|
-
/**
|
|
378
|
-
* Sends a sampling request and returns an AsyncGenerator that yields response messages.
|
|
379
|
-
* The generator is guaranteed to end with either a 'result' or 'error' message.
|
|
380
|
-
*
|
|
381
|
-
* For task-augmented requests, yields 'taskCreated' and 'taskStatus' messages
|
|
382
|
-
* before the final result.
|
|
383
|
-
*
|
|
384
|
-
* @example
|
|
385
|
-
* ```typescript
|
|
386
|
-
* const stream = server.experimental.tasks.createMessageStream({
|
|
387
|
-
* messages: [{ role: 'user', content: { type: 'text', text: 'Hello' } }],
|
|
388
|
-
* maxTokens: 100
|
|
389
|
-
* }, {
|
|
390
|
-
* onprogress: (progress) => {
|
|
391
|
-
* // Handle streaming tokens via progress notifications
|
|
392
|
-
* console.log('Progress:', progress.message);
|
|
393
|
-
* }
|
|
394
|
-
* });
|
|
395
|
-
*
|
|
396
|
-
* for await (const message of stream) {
|
|
397
|
-
* switch (message.type) {
|
|
398
|
-
* case 'taskCreated':
|
|
399
|
-
* console.log('Task created:', message.task.taskId);
|
|
400
|
-
* break;
|
|
401
|
-
* case 'taskStatus':
|
|
402
|
-
* console.log('Task status:', message.task.status);
|
|
403
|
-
* break;
|
|
404
|
-
* case 'result':
|
|
405
|
-
* console.log('Final result:', message.result);
|
|
406
|
-
* break;
|
|
407
|
-
* case 'error':
|
|
408
|
-
* console.error('Error:', message.error);
|
|
409
|
-
* break;
|
|
410
|
-
* }
|
|
411
|
-
* }
|
|
412
|
-
* ```
|
|
413
|
-
*
|
|
414
|
-
* @param params - The sampling request parameters
|
|
415
|
-
* @param options - Optional request options (timeout, signal, task creation params, onprogress, etc.)
|
|
416
|
-
* @returns AsyncGenerator that yields ResponseMessage objects
|
|
417
|
-
*
|
|
418
|
-
* @experimental
|
|
419
|
-
*/
|
|
420
|
-
createMessageStream(params, options) {
|
|
421
|
-
const clientCapabilities = this._server.getClientCapabilities();
|
|
422
|
-
if ((params.tools || params.toolChoice) && !clientCapabilities?.sampling?.tools) throw new SdkError(SdkErrorCode.CapabilityNotSupported, "Client does not support sampling tools capability.");
|
|
423
|
-
if (params.messages.length > 0) {
|
|
424
|
-
const lastMessage = params.messages.at(-1);
|
|
425
|
-
const lastContent = Array.isArray(lastMessage.content) ? lastMessage.content : [lastMessage.content];
|
|
426
|
-
const hasToolResults = lastContent.some((c) => c.type === "tool_result");
|
|
427
|
-
const previousMessage = params.messages.length > 1 ? params.messages.at(-2) : void 0;
|
|
428
|
-
const previousContent = previousMessage ? Array.isArray(previousMessage.content) ? previousMessage.content : [previousMessage.content] : [];
|
|
429
|
-
const hasPreviousToolUse = previousContent.some((c) => c.type === "tool_use");
|
|
430
|
-
if (hasToolResults) {
|
|
431
|
-
if (lastContent.some((c) => c.type !== "tool_result")) throw new Error("The last message must contain only tool_result content if any is present");
|
|
432
|
-
if (!hasPreviousToolUse) throw new Error("tool_result blocks are not matching any tool_use from the previous message");
|
|
433
|
-
}
|
|
434
|
-
if (hasPreviousToolUse) {
|
|
435
|
-
const toolUseIds = new Set(previousContent.filter((c) => c.type === "tool_use").map((c) => c.id));
|
|
436
|
-
const toolResultIds = new Set(lastContent.filter((c) => c.type === "tool_result").map((c) => c.toolUseId));
|
|
437
|
-
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");
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
return this.requestStream({
|
|
441
|
-
method: "sampling/createMessage",
|
|
442
|
-
params
|
|
443
|
-
}, options);
|
|
444
|
-
}
|
|
445
|
-
/**
|
|
446
|
-
* Sends an elicitation request and returns an AsyncGenerator that yields response messages.
|
|
447
|
-
* The generator is guaranteed to end with either a 'result' or 'error' message.
|
|
448
|
-
*
|
|
449
|
-
* For task-augmented requests (especially URL-based elicitation), yields 'taskCreated'
|
|
450
|
-
* and 'taskStatus' messages before the final result.
|
|
451
|
-
*
|
|
452
|
-
* @example
|
|
453
|
-
* ```typescript
|
|
454
|
-
* const stream = server.experimental.tasks.elicitInputStream({
|
|
455
|
-
* mode: 'url',
|
|
456
|
-
* message: 'Please authenticate',
|
|
457
|
-
* elicitationId: 'auth-123',
|
|
458
|
-
* url: 'https://example.com/auth'
|
|
459
|
-
* }, {
|
|
460
|
-
* task: { ttl: 300000 } // Task-augmented for long-running auth flow
|
|
461
|
-
* });
|
|
462
|
-
*
|
|
463
|
-
* for await (const message of stream) {
|
|
464
|
-
* switch (message.type) {
|
|
465
|
-
* case 'taskCreated':
|
|
466
|
-
* console.log('Task created:', message.task.taskId);
|
|
467
|
-
* break;
|
|
468
|
-
* case 'taskStatus':
|
|
469
|
-
* console.log('Task status:', message.task.status);
|
|
470
|
-
* break;
|
|
471
|
-
* case 'result':
|
|
472
|
-
* console.log('User action:', message.result.action);
|
|
473
|
-
* break;
|
|
474
|
-
* case 'error':
|
|
475
|
-
* console.error('Error:', message.error);
|
|
476
|
-
* break;
|
|
477
|
-
* }
|
|
478
|
-
* }
|
|
479
|
-
* ```
|
|
480
|
-
*
|
|
481
|
-
* @param params - The elicitation request parameters
|
|
482
|
-
* @param options - Optional request options (timeout, signal, task creation params, etc.)
|
|
483
|
-
* @returns AsyncGenerator that yields ResponseMessage objects
|
|
484
|
-
*
|
|
485
|
-
* @experimental
|
|
486
|
-
*/
|
|
487
|
-
elicitInputStream(params, options) {
|
|
488
|
-
const clientCapabilities = this._server.getClientCapabilities();
|
|
489
|
-
const mode = params.mode ?? "form";
|
|
490
|
-
switch (mode) {
|
|
491
|
-
case "url":
|
|
492
|
-
if (!clientCapabilities?.elicitation?.url) throw new SdkError(SdkErrorCode.CapabilityNotSupported, "Client does not support url elicitation.");
|
|
493
|
-
break;
|
|
494
|
-
case "form":
|
|
495
|
-
if (!clientCapabilities?.elicitation?.form) throw new SdkError(SdkErrorCode.CapabilityNotSupported, "Client does not support form elicitation.");
|
|
496
|
-
break;
|
|
497
|
-
}
|
|
498
|
-
const normalizedParams = mode === "form" && params.mode !== "form" ? {
|
|
499
|
-
...params,
|
|
500
|
-
mode: "form"
|
|
501
|
-
} : params;
|
|
502
|
-
return this.requestStream({
|
|
503
|
-
method: "elicitation/create",
|
|
504
|
-
params: normalizedParams
|
|
505
|
-
}, options);
|
|
506
|
-
}
|
|
507
|
-
/**
|
|
508
|
-
* Gets the current status of a task.
|
|
509
|
-
*
|
|
510
|
-
* @param taskId - The task identifier
|
|
511
|
-
* @param options - Optional request options
|
|
512
|
-
* @returns The task status
|
|
513
|
-
*
|
|
514
|
-
* @experimental
|
|
515
|
-
*/
|
|
516
|
-
async getTask(taskId, options) {
|
|
517
|
-
return this._module.getTask({ taskId }, options);
|
|
518
|
-
}
|
|
519
|
-
/**
|
|
520
|
-
* Retrieves the result of a completed task.
|
|
521
|
-
*
|
|
522
|
-
* @param taskId - The task identifier
|
|
523
|
-
* @param options - Optional request options
|
|
524
|
-
* @returns The task result. The payload structure matches the result type of the
|
|
525
|
-
* original request (e.g., a `tools/call` task returns a `CallToolResult`).
|
|
526
|
-
*
|
|
527
|
-
* @experimental
|
|
528
|
-
*/
|
|
529
|
-
async getTaskResult(taskId, options) {
|
|
530
|
-
return this._module.getTaskResult({ taskId }, GetTaskPayloadResultSchema, options);
|
|
531
|
-
}
|
|
532
|
-
/**
|
|
533
|
-
* Lists tasks with optional pagination.
|
|
534
|
-
*
|
|
535
|
-
* @param cursor - Optional pagination cursor
|
|
536
|
-
* @param options - Optional request options
|
|
537
|
-
* @returns List of tasks with optional next cursor
|
|
538
|
-
*
|
|
539
|
-
* @experimental
|
|
540
|
-
*/
|
|
541
|
-
async listTasks(cursor, options) {
|
|
542
|
-
return this._module.listTasks(cursor ? { cursor } : void 0, options);
|
|
543
|
-
}
|
|
544
|
-
/**
|
|
545
|
-
* Cancels a running task.
|
|
546
|
-
*
|
|
547
|
-
* @param taskId - The task identifier
|
|
548
|
-
* @param options - Optional request options
|
|
549
|
-
*
|
|
550
|
-
* @experimental
|
|
551
|
-
*/
|
|
552
|
-
async cancelTask(taskId, options) {
|
|
553
|
-
return this._module.cancelTask({ taskId }, options);
|
|
554
|
-
}
|
|
555
|
-
};
|
|
556
|
-
|
|
557
59
|
//#endregion
|
|
558
60
|
//#region src/server/server.ts
|
|
559
61
|
/**
|
|
@@ -566,10 +68,10 @@ var ExperimentalServerTasks = class {
|
|
|
566
68
|
var Server = class extends Protocol {
|
|
567
69
|
_clientCapabilities;
|
|
568
70
|
_clientVersion;
|
|
71
|
+
_negotiatedProtocolVersion;
|
|
569
72
|
_capabilities;
|
|
570
73
|
_instructions;
|
|
571
74
|
_jsonSchemaValidator;
|
|
572
|
-
_experimental;
|
|
573
75
|
/**
|
|
574
76
|
* Callback for when initialization has fully completed (i.e., the client has sent an `notifications/initialized` notification).
|
|
575
77
|
*/
|
|
@@ -578,22 +80,22 @@ var Server = class extends Protocol {
|
|
|
578
80
|
* Initializes this server with the given name and version information.
|
|
579
81
|
*/
|
|
580
82
|
constructor(_serverInfo, options) {
|
|
581
|
-
super(
|
|
582
|
-
...options,
|
|
583
|
-
tasks: extractTaskManagerOptions(options?.capabilities?.tasks)
|
|
584
|
-
});
|
|
83
|
+
super(options);
|
|
585
84
|
this._serverInfo = _serverInfo;
|
|
586
85
|
this._capabilities = options?.capabilities ? { ...options.capabilities } : {};
|
|
587
86
|
this._instructions = options?.instructions;
|
|
588
87
|
this._jsonSchemaValidator = options?.jsonSchemaValidator ?? new DefaultJsonSchemaValidator();
|
|
589
|
-
if (options?.capabilities?.tasks) {
|
|
590
|
-
const { taskStore, taskMessageQueue, defaultTaskPollInterval, maxTaskQueueSize, ...wireCapabilities } = options.capabilities.tasks;
|
|
591
|
-
this._capabilities.tasks = wireCapabilities;
|
|
592
|
-
}
|
|
593
88
|
this.setRequestHandler("initialize", (request) => this._oninitialize(request));
|
|
594
89
|
this.setNotificationHandler("notifications/initialized", () => this.oninitialized?.());
|
|
595
90
|
if (this._capabilities.logging) this._registerLoggingHandler();
|
|
596
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* Registers the built-in `logging/setLevel` request handler.
|
|
94
|
+
*
|
|
95
|
+
* @deprecated Deprecated as of protocol version 2026-07-28 (SEP-2577).
|
|
96
|
+
* Remains functional during the deprecation window (at least twelve months).
|
|
97
|
+
* Migrate to stderr logging (STDIO servers) or OpenTelemetry.
|
|
98
|
+
*/
|
|
597
99
|
_registerLoggingHandler() {
|
|
598
100
|
this.setRequestHandler("logging/setLevel", async (request, ctx) => {
|
|
599
101
|
const transportSessionId = ctx.sessionId || ctx.http?.req?.headers.get("mcp-session-id") || void 0;
|
|
@@ -625,17 +127,6 @@ var Server = class extends Protocol {
|
|
|
625
127
|
} : void 0
|
|
626
128
|
};
|
|
627
129
|
}
|
|
628
|
-
/**
|
|
629
|
-
* Access experimental features.
|
|
630
|
-
*
|
|
631
|
-
* WARNING: These APIs are experimental and may change without notice.
|
|
632
|
-
*
|
|
633
|
-
* @experimental
|
|
634
|
-
*/
|
|
635
|
-
get experimental() {
|
|
636
|
-
if (!this._experimental) this._experimental = { tasks: new ExperimentalServerTasks(this) };
|
|
637
|
-
return this._experimental;
|
|
638
|
-
}
|
|
639
130
|
_loggingLevels = /* @__PURE__ */ new Map();
|
|
640
131
|
LOG_LEVEL_SEVERITY = new Map(LoggingLevelSchema.options.map((level, index) => [level, index]));
|
|
641
132
|
isMessageIgnored = (level, sessionId) => {
|
|
@@ -654,36 +145,24 @@ var Server = class extends Protocol {
|
|
|
654
145
|
if (!hadLogging && this._capabilities.logging) this._registerLoggingHandler();
|
|
655
146
|
}
|
|
656
147
|
/**
|
|
657
|
-
*
|
|
148
|
+
* Enforces server-side validation for `tools/call` results regardless of how the
|
|
149
|
+
* handler was registered.
|
|
658
150
|
*/
|
|
659
|
-
|
|
660
|
-
if (method
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
}
|
|
675
|
-
return taskValidationResult.data;
|
|
676
|
-
}
|
|
677
|
-
const validationResult = parseSchema(CallToolResultSchema, result);
|
|
678
|
-
if (!validationResult.success) {
|
|
679
|
-
const errorMessage = validationResult.error instanceof Error ? validationResult.error.message : String(validationResult.error);
|
|
680
|
-
throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Invalid tools/call result: ${errorMessage}`);
|
|
681
|
-
}
|
|
682
|
-
return validationResult.data;
|
|
683
|
-
};
|
|
684
|
-
return super.setRequestHandler(method, wrappedHandler);
|
|
685
|
-
}
|
|
686
|
-
return super.setRequestHandler(method, handler);
|
|
151
|
+
_wrapHandler(method, handler) {
|
|
152
|
+
if (method !== "tools/call") return handler;
|
|
153
|
+
return async (request, ctx) => {
|
|
154
|
+
const validatedRequest = parseSchema(CallToolRequestSchema, request);
|
|
155
|
+
if (!validatedRequest.success) {
|
|
156
|
+
const errorMessage = validatedRequest.error instanceof Error ? validatedRequest.error.message : String(validatedRequest.error);
|
|
157
|
+
throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Invalid tools/call request: ${errorMessage}`);
|
|
158
|
+
}
|
|
159
|
+
const validationResult = parseSchema(CallToolResultSchema, await handler(request, ctx));
|
|
160
|
+
if (!validationResult.success) {
|
|
161
|
+
const errorMessage = validationResult.error instanceof Error ? validationResult.error.message : String(validationResult.error);
|
|
162
|
+
throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Invalid tools/call result: ${errorMessage}`);
|
|
163
|
+
}
|
|
164
|
+
return validationResult.data;
|
|
165
|
+
};
|
|
687
166
|
}
|
|
688
167
|
assertCapabilityForMethod(method) {
|
|
689
168
|
switch (method) {
|
|
@@ -746,17 +225,12 @@ var Server = class extends Protocol {
|
|
|
746
225
|
case "initialize": break;
|
|
747
226
|
}
|
|
748
227
|
}
|
|
749
|
-
assertTaskCapability(method) {
|
|
750
|
-
assertClientRequestTaskCapability(this._clientCapabilities?.tasks?.requests, method, "Client");
|
|
751
|
-
}
|
|
752
|
-
assertTaskHandlerCapability(method) {
|
|
753
|
-
assertToolsCallTaskCapability(this._capabilities?.tasks?.requests, method, "Server");
|
|
754
|
-
}
|
|
755
228
|
async _oninitialize(request) {
|
|
756
229
|
const requestedVersion = request.params.protocolVersion;
|
|
757
230
|
this._clientCapabilities = request.params.capabilities;
|
|
758
231
|
this._clientVersion = request.params.clientInfo;
|
|
759
232
|
const protocolVersion = this._supportedProtocolVersions.includes(requestedVersion) ? requestedVersion : this._supportedProtocolVersions[0] ?? LATEST_PROTOCOL_VERSION;
|
|
233
|
+
this._negotiatedProtocolVersion = protocolVersion;
|
|
760
234
|
this.transport?.setProtocolVersion?.(protocolVersion);
|
|
761
235
|
return {
|
|
762
236
|
protocolVersion,
|
|
@@ -778,6 +252,14 @@ var Server = class extends Protocol {
|
|
|
778
252
|
return this._clientVersion;
|
|
779
253
|
}
|
|
780
254
|
/**
|
|
255
|
+
* After initialization has completed, this will be populated with the protocol version negotiated
|
|
256
|
+
* with the client (the version the server responded with during the initialize handshake), or
|
|
257
|
+
* `undefined` before initialization.
|
|
258
|
+
*/
|
|
259
|
+
getNegotiatedProtocolVersion() {
|
|
260
|
+
return this._negotiatedProtocolVersion;
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
781
263
|
* Returns the current server capabilities.
|
|
782
264
|
*/
|
|
783
265
|
getCapabilities() {
|
|
@@ -867,6 +349,13 @@ var Server = class extends Protocol {
|
|
|
867
349
|
params: { elicitationId }
|
|
868
350
|
}, options);
|
|
869
351
|
}
|
|
352
|
+
/**
|
|
353
|
+
* Requests the list of roots from the client.
|
|
354
|
+
*
|
|
355
|
+
* @deprecated Deprecated as of protocol version 2026-07-28 (SEP-2577).
|
|
356
|
+
* Remains functional during the deprecation window (at least twelve months).
|
|
357
|
+
* Migrate to passing paths via tool parameters, resource URIs, or configuration.
|
|
358
|
+
*/
|
|
870
359
|
async listRoots(params, options) {
|
|
871
360
|
return this._requestWithSchema({
|
|
872
361
|
method: "roots/list",
|
|
@@ -879,6 +368,10 @@ var Server = class extends Protocol {
|
|
|
879
368
|
* @see {@linkcode LoggingMessageNotification}
|
|
880
369
|
* @param params
|
|
881
370
|
* @param sessionId Optional for stateless transports and backward compatibility.
|
|
371
|
+
*
|
|
372
|
+
* @deprecated Deprecated as of protocol version 2026-07-28 (SEP-2577).
|
|
373
|
+
* Remains functional during the deprecation window (at least twelve months).
|
|
374
|
+
* Migrate to stderr logging (STDIO servers) or OpenTelemetry.
|
|
882
375
|
*/
|
|
883
376
|
async sendLoggingMessage(params, sessionId) {
|
|
884
377
|
if (this._capabilities.logging && !this.isMessageIgnored(params.level, sessionId)) return this.notification({
|
|
@@ -927,20 +420,11 @@ var McpServer = class {
|
|
|
927
420
|
_registeredResourceTemplates = {};
|
|
928
421
|
_registeredTools = {};
|
|
929
422
|
_registeredPrompts = {};
|
|
930
|
-
_experimental;
|
|
931
423
|
constructor(serverInfo, options) {
|
|
932
424
|
this.server = new Server(serverInfo, options);
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
*
|
|
937
|
-
* WARNING: These APIs are experimental and may change without notice.
|
|
938
|
-
*
|
|
939
|
-
* @experimental
|
|
940
|
-
*/
|
|
941
|
-
get experimental() {
|
|
942
|
-
if (!this._experimental) this._experimental = { tasks: new ExperimentalMcpServerTasks(this) };
|
|
943
|
-
return this._experimental;
|
|
425
|
+
if (options?.capabilities?.tools) this.setToolRequestHandlers();
|
|
426
|
+
if (options?.capabilities?.resources) this.setResourceRequestHandlers();
|
|
427
|
+
if (options?.capabilities?.prompts) this.setPromptRequestHandlers();
|
|
944
428
|
}
|
|
945
429
|
/**
|
|
946
430
|
* Attaches to the given transport, starts it, and starts listening for messages.
|
|
@@ -976,6 +460,7 @@ var McpServer = class {
|
|
|
976
460
|
description: tool.description,
|
|
977
461
|
inputSchema: tool.inputSchema ? standardSchemaToJsonSchema(tool.inputSchema, "input") : EMPTY_OBJECT_JSON_SCHEMA,
|
|
978
462
|
annotations: tool.annotations,
|
|
463
|
+
icons: tool.icons,
|
|
979
464
|
execution: tool.execution,
|
|
980
465
|
_meta: tool._meta
|
|
981
466
|
};
|
|
@@ -987,15 +472,8 @@ var McpServer = class {
|
|
|
987
472
|
if (!tool) throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Tool ${request.params.name} not found`);
|
|
988
473
|
if (!tool.enabled) throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Tool ${request.params.name} disabled`);
|
|
989
474
|
try {
|
|
990
|
-
const isTaskRequest = !!request.params.task;
|
|
991
|
-
const taskSupport = tool.execution?.taskSupport;
|
|
992
|
-
const isTaskHandler = "createTask" in tool.handler;
|
|
993
|
-
if ((taskSupport === "required" || taskSupport === "optional") && !isTaskHandler) throw new ProtocolError(ProtocolErrorCode.InternalError, `Tool ${request.params.name} has taskSupport '${taskSupport}' but was not registered with registerToolTask`);
|
|
994
|
-
if (taskSupport === "required" && !isTaskRequest) throw new ProtocolError(ProtocolErrorCode.MethodNotFound, `Tool ${request.params.name} requires task augmentation (taskSupport: 'required')`);
|
|
995
|
-
if (taskSupport === "optional" && !isTaskRequest && isTaskHandler) return await this.handleAutomaticTaskPolling(tool, request, ctx);
|
|
996
475
|
const args = await this.validateToolInput(tool, request.params.arguments, request.params.name);
|
|
997
476
|
const result = await this.executeToolHandler(tool, args, ctx);
|
|
998
|
-
if (isTaskRequest) return result;
|
|
999
477
|
await this.validateToolOutput(tool, result, request.params.name);
|
|
1000
478
|
return result;
|
|
1001
479
|
} catch (error) {
|
|
@@ -1034,36 +512,17 @@ var McpServer = class {
|
|
|
1034
512
|
*/
|
|
1035
513
|
async validateToolOutput(tool, result, toolName) {
|
|
1036
514
|
if (!tool.outputSchema) return;
|
|
1037
|
-
if (!("content" in result)) return;
|
|
1038
515
|
if (result.isError) return;
|
|
1039
516
|
if (!result.structuredContent) throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Output validation error: Tool ${toolName} has an output schema but no structured content was provided`);
|
|
1040
517
|
const parseResult = await validateStandardSchema(tool.outputSchema, result.structuredContent);
|
|
1041
518
|
if (!parseResult.success) throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Output validation error: Invalid structured content for tool ${toolName}: ${parseResult.error}`);
|
|
1042
519
|
}
|
|
1043
520
|
/**
|
|
1044
|
-
* Executes a tool handler
|
|
521
|
+
* Executes a tool handler.
|
|
1045
522
|
*/
|
|
1046
523
|
async executeToolHandler(tool, args, ctx) {
|
|
1047
524
|
return tool.executor(args, ctx);
|
|
1048
525
|
}
|
|
1049
|
-
/**
|
|
1050
|
-
* Handles automatic task polling for tools with `taskSupport` `'optional'`.
|
|
1051
|
-
*/
|
|
1052
|
-
async handleAutomaticTaskPolling(tool, request, ctx) {
|
|
1053
|
-
if (!ctx.task?.store) throw new Error("No task store provided for task-capable tool.");
|
|
1054
|
-
const args = await this.validateToolInput(tool, request.params.arguments, request.params.name);
|
|
1055
|
-
const createTaskResult = await tool.executor(args, ctx);
|
|
1056
|
-
const taskId = createTaskResult.task.taskId;
|
|
1057
|
-
let task = createTaskResult.task;
|
|
1058
|
-
const pollInterval = task.pollInterval ?? 5e3;
|
|
1059
|
-
while (task.status !== "completed" && task.status !== "failed" && task.status !== "cancelled") {
|
|
1060
|
-
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
1061
|
-
const updatedTask = await ctx.task.store.getTask(taskId);
|
|
1062
|
-
if (!updatedTask) throw new ProtocolError(ProtocolErrorCode.InternalError, `Task ${taskId} not found during polling`);
|
|
1063
|
-
task = updatedTask;
|
|
1064
|
-
}
|
|
1065
|
-
return await ctx.task.store.getTaskResult(taskId);
|
|
1066
|
-
}
|
|
1067
526
|
_completionHandlerInitialized = false;
|
|
1068
527
|
setCompletionRequestHandler() {
|
|
1069
528
|
if (this._completionHandlerInitialized) return;
|
|
@@ -1161,6 +620,7 @@ var McpServer = class {
|
|
|
1161
620
|
title: prompt.title,
|
|
1162
621
|
description: prompt.description,
|
|
1163
622
|
arguments: prompt.argsSchema ? promptArgumentsFromStandardSchema(prompt.argsSchema) : void 0,
|
|
623
|
+
icons: prompt.icons,
|
|
1164
624
|
_meta: prompt._meta
|
|
1165
625
|
};
|
|
1166
626
|
}) }));
|
|
@@ -1241,13 +701,14 @@ var McpServer = class {
|
|
|
1241
701
|
if (Array.isArray(variableNames) && variableNames.some((v) => !!template.completeCallback(v))) this.setCompletionRequestHandler();
|
|
1242
702
|
return registeredResourceTemplate;
|
|
1243
703
|
}
|
|
1244
|
-
_createRegisteredPrompt(name, title, description, argsSchema, callback, _meta) {
|
|
704
|
+
_createRegisteredPrompt(name, title, description, argsSchema, callback, icons, _meta) {
|
|
1245
705
|
let currentArgsSchema = argsSchema;
|
|
1246
706
|
let currentCallback = callback;
|
|
1247
707
|
const registeredPrompt = {
|
|
1248
708
|
title,
|
|
1249
709
|
description,
|
|
1250
710
|
argsSchema,
|
|
711
|
+
icons,
|
|
1251
712
|
_meta,
|
|
1252
713
|
handler: createPromptHandler(name, argsSchema, callback),
|
|
1253
714
|
enabled: true,
|
|
@@ -1261,6 +722,7 @@ var McpServer = class {
|
|
|
1261
722
|
}
|
|
1262
723
|
if (updates.title !== void 0) registeredPrompt.title = updates.title;
|
|
1263
724
|
if (updates.description !== void 0) registeredPrompt.description = updates.description;
|
|
725
|
+
if (updates.icons !== void 0) registeredPrompt.icons = updates.icons;
|
|
1264
726
|
if (updates._meta !== void 0) registeredPrompt._meta = updates._meta;
|
|
1265
727
|
let needsHandlerRegen = false;
|
|
1266
728
|
if (updates.argsSchema !== void 0) {
|
|
@@ -1288,7 +750,7 @@ var McpServer = class {
|
|
|
1288
750
|
}
|
|
1289
751
|
return registeredPrompt;
|
|
1290
752
|
}
|
|
1291
|
-
_createRegisteredTool(name, title, description, inputSchema, outputSchema, annotations, execution, _meta, handler) {
|
|
753
|
+
_createRegisteredTool(name, title, description, inputSchema, outputSchema, annotations, icons, execution, _meta, handler) {
|
|
1292
754
|
validateAndWarnToolName(name);
|
|
1293
755
|
let currentHandler = handler;
|
|
1294
756
|
const registeredTool = {
|
|
@@ -1297,6 +759,7 @@ var McpServer = class {
|
|
|
1297
759
|
inputSchema,
|
|
1298
760
|
outputSchema,
|
|
1299
761
|
annotations,
|
|
762
|
+
icons,
|
|
1300
763
|
execution,
|
|
1301
764
|
_meta,
|
|
1302
765
|
handler,
|
|
@@ -1326,6 +789,7 @@ var McpServer = class {
|
|
|
1326
789
|
if (needsExecutorRegen) registeredTool.executor = createToolExecutor(registeredTool.inputSchema, currentHandler);
|
|
1327
790
|
if (updates.outputSchema !== void 0) registeredTool.outputSchema = updates.outputSchema;
|
|
1328
791
|
if (updates.annotations !== void 0) registeredTool.annotations = updates.annotations;
|
|
792
|
+
if (updates.icons !== void 0) registeredTool.icons = updates.icons;
|
|
1329
793
|
if (updates._meta !== void 0) registeredTool._meta = updates._meta;
|
|
1330
794
|
if (updates.enabled !== void 0) registeredTool.enabled = updates.enabled;
|
|
1331
795
|
this.sendToolListChanged();
|
|
@@ -1336,67 +800,15 @@ var McpServer = class {
|
|
|
1336
800
|
this.sendToolListChanged();
|
|
1337
801
|
return registeredTool;
|
|
1338
802
|
}
|
|
1339
|
-
/**
|
|
1340
|
-
* Registers a tool with a config object and callback.
|
|
1341
|
-
*
|
|
1342
|
-
* @example
|
|
1343
|
-
* ```ts source="./mcp.examples.ts#McpServer_registerTool_basic"
|
|
1344
|
-
* server.registerTool(
|
|
1345
|
-
* 'calculate-bmi',
|
|
1346
|
-
* {
|
|
1347
|
-
* title: 'BMI Calculator',
|
|
1348
|
-
* description: 'Calculate Body Mass Index',
|
|
1349
|
-
* inputSchema: z.object({
|
|
1350
|
-
* weightKg: z.number(),
|
|
1351
|
-
* heightM: z.number()
|
|
1352
|
-
* }),
|
|
1353
|
-
* outputSchema: z.object({ bmi: z.number() })
|
|
1354
|
-
* },
|
|
1355
|
-
* async ({ weightKg, heightM }) => {
|
|
1356
|
-
* const output = { bmi: weightKg / (heightM * heightM) };
|
|
1357
|
-
* return {
|
|
1358
|
-
* content: [{ type: 'text', text: JSON.stringify(output) }],
|
|
1359
|
-
* structuredContent: output
|
|
1360
|
-
* };
|
|
1361
|
-
* }
|
|
1362
|
-
* );
|
|
1363
|
-
* ```
|
|
1364
|
-
*/
|
|
1365
803
|
registerTool(name, config, cb) {
|
|
1366
804
|
if (this._registeredTools[name]) throw new Error(`Tool ${name} is already registered`);
|
|
1367
|
-
const { title, description, inputSchema, outputSchema, annotations, _meta } = config;
|
|
1368
|
-
return this._createRegisteredTool(name, title, description, inputSchema, outputSchema, annotations,
|
|
805
|
+
const { title, description, inputSchema, outputSchema, annotations, icons, _meta } = config;
|
|
806
|
+
return this._createRegisteredTool(name, title, description, normalizeRawShapeSchema(inputSchema), normalizeRawShapeSchema(outputSchema), annotations, icons, void 0, _meta, cb);
|
|
1369
807
|
}
|
|
1370
|
-
/**
|
|
1371
|
-
* Registers a prompt with a config object and callback.
|
|
1372
|
-
*
|
|
1373
|
-
* @example
|
|
1374
|
-
* ```ts source="./mcp.examples.ts#McpServer_registerPrompt_basic"
|
|
1375
|
-
* server.registerPrompt(
|
|
1376
|
-
* 'review-code',
|
|
1377
|
-
* {
|
|
1378
|
-
* title: 'Code Review',
|
|
1379
|
-
* description: 'Review code for best practices',
|
|
1380
|
-
* argsSchema: z.object({ code: z.string() })
|
|
1381
|
-
* },
|
|
1382
|
-
* ({ code }) => ({
|
|
1383
|
-
* messages: [
|
|
1384
|
-
* {
|
|
1385
|
-
* role: 'user' as const,
|
|
1386
|
-
* content: {
|
|
1387
|
-
* type: 'text' as const,
|
|
1388
|
-
* text: `Please review this code:\n\n${code}`
|
|
1389
|
-
* }
|
|
1390
|
-
* }
|
|
1391
|
-
* ]
|
|
1392
|
-
* })
|
|
1393
|
-
* );
|
|
1394
|
-
* ```
|
|
1395
|
-
*/
|
|
1396
808
|
registerPrompt(name, config, cb) {
|
|
1397
809
|
if (this._registeredPrompts[name]) throw new Error(`Prompt ${name} is already registered`);
|
|
1398
|
-
const { title, description, argsSchema, _meta } = config;
|
|
1399
|
-
const registeredPrompt = this._createRegisteredPrompt(name, title, description, argsSchema, cb, _meta);
|
|
810
|
+
const { title, description, argsSchema, icons, _meta } = config;
|
|
811
|
+
const registeredPrompt = this._createRegisteredPrompt(name, title, description, normalizeRawShapeSchema(argsSchema), cb, icons, _meta);
|
|
1400
812
|
this.setPromptRequestHandlers();
|
|
1401
813
|
this.sendPromptListChanged();
|
|
1402
814
|
return registeredPrompt;
|
|
@@ -1422,6 +834,10 @@ var McpServer = class {
|
|
|
1422
834
|
* data: 'Processing complete'
|
|
1423
835
|
* });
|
|
1424
836
|
* ```
|
|
837
|
+
*
|
|
838
|
+
* @deprecated Deprecated as of protocol version 2026-07-28 (SEP-2577).
|
|
839
|
+
* Remains functional during the deprecation window (at least twelve months).
|
|
840
|
+
* Migrate to stderr logging (STDIO servers) or OpenTelemetry.
|
|
1425
841
|
*/
|
|
1426
842
|
async sendLoggingMessage(params, sessionId) {
|
|
1427
843
|
return this.server.sendLoggingMessage(params, sessionId);
|
|
@@ -1480,21 +896,6 @@ var ResourceTemplate = class {
|
|
|
1480
896
|
* When `inputSchema` is undefined, the handler is called with just `(ctx)`.
|
|
1481
897
|
*/
|
|
1482
898
|
function createToolExecutor(inputSchema, handler) {
|
|
1483
|
-
if ("createTask" in handler) {
|
|
1484
|
-
const taskHandler = handler;
|
|
1485
|
-
return async (args, ctx) => {
|
|
1486
|
-
if (!ctx.task?.store) throw new Error("No task store provided.");
|
|
1487
|
-
const taskCtx = {
|
|
1488
|
-
...ctx,
|
|
1489
|
-
task: {
|
|
1490
|
-
store: ctx.task.store,
|
|
1491
|
-
requestedTtl: ctx.task?.requestedTtl
|
|
1492
|
-
}
|
|
1493
|
-
};
|
|
1494
|
-
if (inputSchema) return taskHandler.createTask(args, taskCtx);
|
|
1495
|
-
return taskHandler.createTask(taskCtx);
|
|
1496
|
-
};
|
|
1497
|
-
}
|
|
1498
899
|
if (inputSchema) {
|
|
1499
900
|
const callback$1 = handler;
|
|
1500
901
|
return async (args, ctx) => callback$1(args, ctx);
|
|
@@ -1621,101 +1022,6 @@ function hostHeaderValidationResponse(req, allowedHostnames) {
|
|
|
1621
1022
|
});
|
|
1622
1023
|
}
|
|
1623
1024
|
|
|
1624
|
-
//#endregion
|
|
1625
|
-
//#region src/server/stdio.ts
|
|
1626
|
-
/**
|
|
1627
|
-
* Server transport for stdio: this communicates with an MCP client by reading from the current process' `stdin` and writing to `stdout`.
|
|
1628
|
-
*
|
|
1629
|
-
* This transport is only available in Node.js environments.
|
|
1630
|
-
*
|
|
1631
|
-
* @example
|
|
1632
|
-
* ```ts source="./stdio.examples.ts#StdioServerTransport_basicUsage"
|
|
1633
|
-
* const server = new McpServer({ name: 'my-server', version: '1.0.0' });
|
|
1634
|
-
* const transport = new StdioServerTransport();
|
|
1635
|
-
* await server.connect(transport);
|
|
1636
|
-
* ```
|
|
1637
|
-
*/
|
|
1638
|
-
var StdioServerTransport = class {
|
|
1639
|
-
_readBuffer = new ReadBuffer();
|
|
1640
|
-
_started = false;
|
|
1641
|
-
_closed = false;
|
|
1642
|
-
constructor(_stdin = process.stdin, _stdout = process.stdout) {
|
|
1643
|
-
this._stdin = _stdin;
|
|
1644
|
-
this._stdout = _stdout;
|
|
1645
|
-
}
|
|
1646
|
-
onclose;
|
|
1647
|
-
onerror;
|
|
1648
|
-
onmessage;
|
|
1649
|
-
_ondata = (chunk) => {
|
|
1650
|
-
this._readBuffer.append(chunk);
|
|
1651
|
-
this.processReadBuffer();
|
|
1652
|
-
};
|
|
1653
|
-
_onerror = (error) => {
|
|
1654
|
-
this.onerror?.(error);
|
|
1655
|
-
};
|
|
1656
|
-
_onstdouterror = (error) => {
|
|
1657
|
-
this.onerror?.(error);
|
|
1658
|
-
this.close().catch(() => {});
|
|
1659
|
-
};
|
|
1660
|
-
/**
|
|
1661
|
-
* Starts listening for messages on `stdin`.
|
|
1662
|
-
*/
|
|
1663
|
-
async start() {
|
|
1664
|
-
if (this._started) throw new Error("StdioServerTransport already started! If using Server class, note that connect() calls start() automatically.");
|
|
1665
|
-
this._started = true;
|
|
1666
|
-
this._stdin.on("data", this._ondata);
|
|
1667
|
-
this._stdin.on("error", this._onerror);
|
|
1668
|
-
this._stdout.on("error", this._onstdouterror);
|
|
1669
|
-
}
|
|
1670
|
-
processReadBuffer() {
|
|
1671
|
-
while (true) try {
|
|
1672
|
-
const message = this._readBuffer.readMessage();
|
|
1673
|
-
if (message === null) break;
|
|
1674
|
-
this.onmessage?.(message);
|
|
1675
|
-
} catch (error) {
|
|
1676
|
-
this.onerror?.(error);
|
|
1677
|
-
}
|
|
1678
|
-
}
|
|
1679
|
-
async close() {
|
|
1680
|
-
if (this._closed) return;
|
|
1681
|
-
this._closed = true;
|
|
1682
|
-
this._stdin.off("data", this._ondata);
|
|
1683
|
-
this._stdin.off("error", this._onerror);
|
|
1684
|
-
this._stdout.off("error", this._onstdouterror);
|
|
1685
|
-
if (this._stdin.listenerCount("data") === 0) this._stdin.pause();
|
|
1686
|
-
this._readBuffer.clear();
|
|
1687
|
-
this.onclose?.();
|
|
1688
|
-
}
|
|
1689
|
-
send(message) {
|
|
1690
|
-
if (this._closed) return Promise.reject(/* @__PURE__ */ new Error("StdioServerTransport is closed"));
|
|
1691
|
-
return new Promise((resolve, reject) => {
|
|
1692
|
-
const json = serializeMessage(message);
|
|
1693
|
-
let settled = false;
|
|
1694
|
-
const onError = (error) => {
|
|
1695
|
-
if (settled) return;
|
|
1696
|
-
settled = true;
|
|
1697
|
-
this._stdout.off("error", onError);
|
|
1698
|
-
this._stdout.off("drain", onDrain);
|
|
1699
|
-
reject(error);
|
|
1700
|
-
};
|
|
1701
|
-
const onDrain = () => {
|
|
1702
|
-
if (settled) return;
|
|
1703
|
-
settled = true;
|
|
1704
|
-
this._stdout.off("error", onError);
|
|
1705
|
-
this._stdout.off("drain", onDrain);
|
|
1706
|
-
resolve();
|
|
1707
|
-
};
|
|
1708
|
-
this._stdout.once("error", onError);
|
|
1709
|
-
if (this._stdout.write(json)) {
|
|
1710
|
-
if (settled) return;
|
|
1711
|
-
settled = true;
|
|
1712
|
-
this._stdout.off("error", onError);
|
|
1713
|
-
resolve();
|
|
1714
|
-
} else if (!settled) this._stdout.once("drain", onDrain);
|
|
1715
|
-
});
|
|
1716
|
-
}
|
|
1717
|
-
};
|
|
1718
|
-
|
|
1719
1025
|
//#endregion
|
|
1720
1026
|
//#region src/server/streamableHttp.ts
|
|
1721
1027
|
/**
|
|
@@ -1772,6 +1078,7 @@ var StdioServerTransport = class {
|
|
|
1772
1078
|
var WebStandardStreamableHTTPServerTransport = class {
|
|
1773
1079
|
sessionIdGenerator;
|
|
1774
1080
|
_started = false;
|
|
1081
|
+
_closed = false;
|
|
1775
1082
|
_streamMapping = /* @__PURE__ */ new Map();
|
|
1776
1083
|
_requestToStreamMapping = /* @__PURE__ */ new Map();
|
|
1777
1084
|
_requestResponseMap = /* @__PURE__ */ new Map();
|
|
@@ -1876,13 +1183,29 @@ var WebStandardStreamableHTTPServerTransport = class {
|
|
|
1876
1183
|
}
|
|
1877
1184
|
}
|
|
1878
1185
|
/**
|
|
1186
|
+
* Returns true if the client's protocol version supports empty SSE data in
|
|
1187
|
+
* priming events (the fix shipped with protocol version `2025-11-25`).
|
|
1188
|
+
*
|
|
1189
|
+
* The version is checked for membership in this transport instance's
|
|
1190
|
+
* supported protocol versions rather than with an open-ended
|
|
1191
|
+
* `>= '2025-11-25'` comparison: the value may come from an `initialize`
|
|
1192
|
+
* request body, which (unlike the `MCP-Protocol-Version` header) is not
|
|
1193
|
+
* validated against `supportedProtocolVersions` before reaching this
|
|
1194
|
+
* check. An unknown future version string must not silently enable
|
|
1195
|
+
* behavior reserved for versions this transport actually supports.
|
|
1196
|
+
*/
|
|
1197
|
+
supportsEmptySSEData(protocolVersion) {
|
|
1198
|
+
return this._supportedProtocolVersions.includes(protocolVersion) && protocolVersion >= "2025-11-25";
|
|
1199
|
+
}
|
|
1200
|
+
/**
|
|
1879
1201
|
* Writes a priming event to establish resumption capability.
|
|
1880
1202
|
* Only sends if `eventStore` is configured (opt-in for resumability) and
|
|
1881
|
-
* the client's protocol version supports empty SSE data (
|
|
1203
|
+
* the client's protocol version supports empty SSE data (a supported
|
|
1204
|
+
* version that is >= `2025-11-25`).
|
|
1882
1205
|
*/
|
|
1883
1206
|
async writePrimingEvent(controller, encoder, streamId, protocolVersion) {
|
|
1884
1207
|
if (!this._eventStore) return;
|
|
1885
|
-
if (protocolVersion
|
|
1208
|
+
if (!this.supportsEmptySSEData(protocolVersion)) return;
|
|
1886
1209
|
const primingEventId = await this._eventStore.storeEvent(streamId, {});
|
|
1887
1210
|
let primingEvent = `id: ${primingEventId}\ndata: \n\n`;
|
|
1888
1211
|
if (this._retryInterval !== void 0) primingEvent = `id: ${primingEventId}\nretry: ${this._retryInterval}\ndata: \n\n`;
|
|
@@ -2135,7 +1458,7 @@ var WebStandardStreamableHTTPServerTransport = class {
|
|
|
2135
1458
|
for (const message of messages) {
|
|
2136
1459
|
let closeSSEStream;
|
|
2137
1460
|
let closeStandaloneSSEStream;
|
|
2138
|
-
if (isJSONRPCRequest(message) && this._eventStore && clientProtocolVersion
|
|
1461
|
+
if (isJSONRPCRequest(message) && this._eventStore && this.supportsEmptySSEData(clientProtocolVersion)) {
|
|
2139
1462
|
closeSSEStream = () => {
|
|
2140
1463
|
this.closeSSEStream(message.id);
|
|
2141
1464
|
};
|
|
@@ -2213,6 +1536,8 @@ var WebStandardStreamableHTTPServerTransport = class {
|
|
|
2213
1536
|
}
|
|
2214
1537
|
}
|
|
2215
1538
|
async close() {
|
|
1539
|
+
if (this._closed) return;
|
|
1540
|
+
this._closed = true;
|
|
2216
1541
|
for (const { cleanup } of this._streamMapping.values()) cleanup();
|
|
2217
1542
|
this._streamMapping.clear();
|
|
2218
1543
|
this._requestResponseMap.clear();
|
|
@@ -2292,5 +1617,5 @@ function fromJsonSchema(schema, validator) {
|
|
|
2292
1617
|
}
|
|
2293
1618
|
|
|
2294
1619
|
//#endregion
|
|
2295
|
-
export {
|
|
1620
|
+
export { BAGGAGE_META_KEY, CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, DEFAULT_NEGOTIATED_PROTOCOL_VERSION, DEFAULT_REQUEST_TIMEOUT_MSEC, INTERNAL_ERROR, INVALID_PARAMS, INVALID_REQUEST, InMemoryTransport, JSONRPC_VERSION, LATEST_PROTOCOL_VERSION, LOG_LEVEL_META_KEY, METHOD_NOT_FOUND, McpServer, OAuthError, OAuthErrorCode, PARSE_ERROR, PROTOCOL_VERSION_META_KEY, ProtocolError, ProtocolErrorCode, RELATED_TASK_META_KEY, ReadBuffer, ResourceTemplate, STDIO_DEFAULT_MAX_BUFFER_SIZE, SUPPORTED_PROTOCOL_VERSIONS, SdkError, SdkErrorCode, SdkHttpError, Server, TRACEPARENT_META_KEY, TRACESTATE_META_KEY, UnsupportedProtocolVersionError, UriTemplate, UrlElicitationRequiredError, WebStandardStreamableHTTPServerTransport, assertCompleteRequestPrompt, assertCompleteRequestResourceTemplate, checkResourceAllowed, completable, createFetchWithInit, deserializeMessage, fromJsonSchema, getDisplayName, hostHeaderValidationResponse, isCallToolResult, isCompletable, isInitializeRequest, isInitializedNotification, isJSONRPCErrorResponse, isJSONRPCNotification, isJSONRPCRequest, isJSONRPCResponse, isJSONRPCResultResponse, isSpecType, isTaskAugmentedRequestParams, localhostAllowedHostnames, parseJSONRPCMessage, resourceUrlFromServerUrl, serializeMessage, specTypeSchemas, validateHostHeader };
|
|
2296
1621
|
//# sourceMappingURL=index.mjs.map
|