@@ -53876,6 +53876,147 @@ var ExperimentalServerTasks = class {
5387653876 requestStream(request, resultSchema, options) {
5387753877 return this._server.requestStream(request, resultSchema, options);
5387853878 }
53879+ /**
53880+ * Sends a sampling request and returns an AsyncGenerator that yields response messages.
53881+ * The generator is guaranteed to end with either a 'result' or 'error' message.
53882+ *
53883+ * For task-augmented requests, yields 'taskCreated' and 'taskStatus' messages
53884+ * before the final result.
53885+ *
53886+ * @example
53887+ * ```typescript
53888+ * const stream = server.experimental.tasks.createMessageStream({
53889+ * messages: [{ role: 'user', content: { type: 'text', text: 'Hello' } }],
53890+ * maxTokens: 100
53891+ * }, {
53892+ * onprogress: (progress) => {
53893+ * // Handle streaming tokens via progress notifications
53894+ * console.log('Progress:', progress.message);
53895+ * }
53896+ * });
53897+ *
53898+ * for await (const message of stream) {
53899+ * switch (message.type) {
53900+ * case 'taskCreated':
53901+ * console.log('Task created:', message.task.taskId);
53902+ * break;
53903+ * case 'taskStatus':
53904+ * console.log('Task status:', message.task.status);
53905+ * break;
53906+ * case 'result':
53907+ * console.log('Final result:', message.result);
53908+ * break;
53909+ * case 'error':
53910+ * console.error('Error:', message.error);
53911+ * break;
53912+ * }
53913+ * }
53914+ * ```
53915+ *
53916+ * @param params - The sampling request parameters
53917+ * @param options - Optional request options (timeout, signal, task creation params, onprogress, etc.)
53918+ * @returns AsyncGenerator that yields ResponseMessage objects
53919+ *
53920+ * @experimental
53921+ */
53922+ createMessageStream(params, options) {
53923+ const clientCapabilities = this._server.getClientCapabilities();
53924+ if ((params.tools || params.toolChoice) && !clientCapabilities?.sampling?.tools) {
53925+ throw new Error("Client does not support sampling tools capability.");
53926+ }
53927+ if (params.messages.length > 0) {
53928+ const lastMessage = params.messages[params.messages.length - 1];
53929+ const lastContent = Array.isArray(lastMessage.content) ? lastMessage.content : [lastMessage.content];
53930+ const hasToolResults = lastContent.some((c) => c.type === "tool_result");
53931+ const previousMessage = params.messages.length > 1 ? params.messages[params.messages.length - 2] : void 0;
53932+ const previousContent = previousMessage ? Array.isArray(previousMessage.content) ? previousMessage.content : [previousMessage.content] : [];
53933+ const hasPreviousToolUse = previousContent.some((c) => c.type === "tool_use");
53934+ if (hasToolResults) {
53935+ if (lastContent.some((c) => c.type !== "tool_result")) {
53936+ throw new Error("The last message must contain only tool_result content if any is present");
53937+ }
53938+ if (!hasPreviousToolUse) {
53939+ throw new Error("tool_result blocks are not matching any tool_use from the previous message");
53940+ }
53941+ }
53942+ if (hasPreviousToolUse) {
53943+ const toolUseIds = new Set(previousContent.filter((c) => c.type === "tool_use").map((c) => c.id));
53944+ const toolResultIds = new Set(lastContent.filter((c) => c.type === "tool_result").map((c) => c.toolUseId));
53945+ if (toolUseIds.size !== toolResultIds.size || ![...toolUseIds].every((id) => toolResultIds.has(id))) {
53946+ throw new Error("ids of tool_result blocks and tool_use blocks from previous message do not match");
53947+ }
53948+ }
53949+ }
53950+ return this.requestStream({
53951+ method: "sampling/createMessage",
53952+ params
53953+ }, CreateMessageResultSchema, options);
53954+ }
53955+ /**
53956+ * Sends an elicitation request and returns an AsyncGenerator that yields response messages.
53957+ * The generator is guaranteed to end with either a 'result' or 'error' message.
53958+ *
53959+ * For task-augmented requests (especially URL-based elicitation), yields 'taskCreated'
53960+ * and 'taskStatus' messages before the final result.
53961+ *
53962+ * @example
53963+ * ```typescript
53964+ * const stream = server.experimental.tasks.elicitInputStream({
53965+ * mode: 'url',
53966+ * message: 'Please authenticate',
53967+ * elicitationId: 'auth-123',
53968+ * url: 'https://example.com/auth'
53969+ * }, {
53970+ * task: { ttl: 300000 } // Task-augmented for long-running auth flow
53971+ * });
53972+ *
53973+ * for await (const message of stream) {
53974+ * switch (message.type) {
53975+ * case 'taskCreated':
53976+ * console.log('Task created:', message.task.taskId);
53977+ * break;
53978+ * case 'taskStatus':
53979+ * console.log('Task status:', message.task.status);
53980+ * break;
53981+ * case 'result':
53982+ * console.log('User action:', message.result.action);
53983+ * break;
53984+ * case 'error':
53985+ * console.error('Error:', message.error);
53986+ * break;
53987+ * }
53988+ * }
53989+ * ```
53990+ *
53991+ * @param params - The elicitation request parameters
53992+ * @param options - Optional request options (timeout, signal, task creation params, etc.)
53993+ * @returns AsyncGenerator that yields ResponseMessage objects
53994+ *
53995+ * @experimental
53996+ */
53997+ elicitInputStream(params, options) {
53998+ const clientCapabilities = this._server.getClientCapabilities();
53999+ const mode = params.mode ?? "form";
54000+ switch (mode) {
54001+ case "url": {
54002+ if (!clientCapabilities?.elicitation?.url) {
54003+ throw new Error("Client does not support url elicitation.");
54004+ }
54005+ break;
54006+ }
54007+ case "form": {
54008+ if (!clientCapabilities?.elicitation?.form) {
54009+ throw new Error("Client does not support form elicitation.");
54010+ }
54011+ break;
54012+ }
54013+ }
54014+ const normalizedParams = mode === "form" && params.mode === void 0 ? { ...params, mode: "form" } : params;
54015+ return this.requestStream({
54016+ method: "elicitation/create",
54017+ params: normalizedParams
54018+ }, ElicitResultSchema, options);
54019+ }
5387954020 /**
5388054021 * Gets the current status of a task.
5388154022 *
@@ -55971,6 +56112,7 @@ data:
5597156112 async handleGetRequest(req) {
5597256113 const acceptHeader = req.headers.get("accept");
5597356114 if (!acceptHeader?.includes("text/event-stream")) {
56115+ this.onerror?.(new Error("Not Acceptable: Client must accept text/event-stream"));
5597456116 return this.createJsonErrorResponse(406, -32e3, "Not Acceptable: Client must accept text/event-stream");
5597556117 }
5597656118 const sessionError = this.validateSession(req);
@@ -55988,6 +56130,7 @@ data:
5598856130 }
5598956131 }
5599056132 if (this._streamMapping.get(this._standaloneSseStreamId) !== void 0) {
56133+ this.onerror?.(new Error("Conflict: Only one SSE stream is allowed per session"));
5599156134 return this.createJsonErrorResponse(409, -32e3, "Conflict: Only one SSE stream is allowed per session");
5599256135 }
5599356136 const encoder = new TextEncoder();
@@ -56027,16 +56170,19 @@ data:
5602756170 */
5602856171 async replayEvents(lastEventId) {
5602956172 if (!this._eventStore) {
56173+ this.onerror?.(new Error("Event store not configured"));
5603056174 return this.createJsonErrorResponse(400, -32e3, "Event store not configured");
5603156175 }
5603256176 try {
5603356177 let streamId;
5603456178 if (this._eventStore.getStreamIdForEventId) {
5603556179 streamId = await this._eventStore.getStreamIdForEventId(lastEventId);
5603656180 if (!streamId) {
56181+ this.onerror?.(new Error("Invalid event ID format"));
5603756182 return this.createJsonErrorResponse(400, -32e3, "Invalid event ID format");
5603856183 }
5603956184 if (this._streamMapping.get(streamId) !== void 0) {
56185+ this.onerror?.(new Error("Conflict: Stream already has an active connection"));
5604056186 return this.createJsonErrorResponse(409, -32e3, "Conflict: Stream already has an active connection");
5604156187 }
5604256188 }
@@ -56102,14 +56248,16 @@ data:
5610256248`;
5610356249 controller.enqueue(encoder.encode(eventData));
5610456250 return true;
56105- } catch {
56251+ } catch (error2) {
56252+ this.onerror?.(error2);
5610656253 return false;
5610756254 }
5610856255 }
5610956256 /**
5611056257 * Handles unsupported requests (PUT, PATCH, etc.)
5611156258 */
5611256259 handleUnsupportedRequest() {
56260+ this.onerror?.(new Error("Method not allowed."));
5611356261 return new Response(JSON.stringify({
5611456262 jsonrpc: "2.0",
5611556263 error: {
@@ -56132,14 +56280,17 @@ data:
5613256280 try {
5613356281 const acceptHeader = req.headers.get("accept");
5613456282 if (!acceptHeader?.includes("application/json") || !acceptHeader.includes("text/event-stream")) {
56283+ this.onerror?.(new Error("Not Acceptable: Client must accept both application/json and text/event-stream"));
5613556284 return this.createJsonErrorResponse(406, -32e3, "Not Acceptable: Client must accept both application/json and text/event-stream");
5613656285 }
5613756286 const ct = req.headers.get("content-type");
5613856287 if (!ct || !ct.includes("application/json")) {
56288+ this.onerror?.(new Error("Unsupported Media Type: Content-Type must be application/json"));
5613956289 return this.createJsonErrorResponse(415, -32e3, "Unsupported Media Type: Content-Type must be application/json");
5614056290 }
5614156291 const requestInfo = {
56142- headers: Object.fromEntries(req.headers.entries())
56292+ headers: Object.fromEntries(req.headers.entries()),
56293+ url: new URL(req.url)
5614356294 };
5614456295 let rawMessage;
5614556296 if (options?.parsedBody !== void 0) {
@@ -56148,6 +56299,7 @@ data:
5614856299 try {
5614956300 rawMessage = await req.json();
5615056301 } catch {
56302+ this.onerror?.(new Error("Parse error: Invalid JSON"));
5615156303 return this.createJsonErrorResponse(400, -32700, "Parse error: Invalid JSON");
5615256304 }
5615356305 }
@@ -56159,14 +56311,17 @@ data:
5615956311 messages = [JSONRPCMessageSchema.parse(rawMessage)];
5616056312 }
5616156313 } catch {
56314+ this.onerror?.(new Error("Parse error: Invalid JSON-RPC message"));
5616256315 return this.createJsonErrorResponse(400, -32700, "Parse error: Invalid JSON-RPC message");
5616356316 }
5616456317 const isInitializationRequest = messages.some(isInitializeRequest);
5616556318 if (isInitializationRequest) {
5616656319 if (this._initialized && this.sessionId !== void 0) {
56320+ this.onerror?.(new Error("Invalid Request: Server already initialized"));
5616756321 return this.createJsonErrorResponse(400, -32600, "Invalid Request: Server already initialized");
5616856322 }
5616956323 if (messages.length > 1) {
56324+ this.onerror?.(new Error("Invalid Request: Only one initialization request is allowed"));
5617056325 return this.createJsonErrorResponse(400, -32600, "Invalid Request: Only one initialization request is allowed");
5617156326 }
5617256327 this.sessionId = this.sessionIdGenerator?.();
@@ -56292,13 +56447,16 @@ data:
5629256447 return void 0;
5629356448 }
5629456449 if (!this._initialized) {
56450+ this.onerror?.(new Error("Bad Request: Server not initialized"));
5629556451 return this.createJsonErrorResponse(400, -32e3, "Bad Request: Server not initialized");
5629656452 }
5629756453 const sessionId = req.headers.get("mcp-session-id");
5629856454 if (!sessionId) {
56455+ this.onerror?.(new Error("Bad Request: Mcp-Session-Id header is required"));
5629956456 return this.createJsonErrorResponse(400, -32e3, "Bad Request: Mcp-Session-Id header is required");
5630056457 }
5630156458 if (sessionId !== this.sessionId) {
56459+ this.onerror?.(new Error("Session not found"));
5630256460 return this.createJsonErrorResponse(404, -32001, "Session not found");
5630356461 }
5630456462 return void 0;
@@ -56319,6 +56477,7 @@ data:
5631956477 validateProtocolVersion(req) {
5632056478 const protocolVersion = req.headers.get("mcp-protocol-version");
5632156479 if (protocolVersion !== null && !SUPPORTED_PROTOCOL_VERSIONS.includes(protocolVersion)) {
56480+ this.onerror?.(new Error(`Bad Request: Unsupported protocol version: ${protocolVersion} (supported versions: ${SUPPORTED_PROTOCOL_VERSIONS.join(", ")})`));
5632256481 return this.createJsonErrorResponse(400, -32e3, `Bad Request: Unsupported protocol version: ${protocolVersion} (supported versions: ${SUPPORTED_PROTOCOL_VERSIONS.join(", ")})`);
5632356482 }
5632456483 return void 0;
0 commit comments