| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250 |
- "use strict";
- /**
- * Experimental server task features for MCP SDK.
- * WARNING: These APIs are experimental and may change without notice.
- *
- * @experimental
- */
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.ExperimentalServerTasks = void 0;
- const types_js_1 = require("../../types.js");
- /**
- * Experimental task features for low-level MCP servers.
- *
- * Access via `server.experimental.tasks`:
- * ```typescript
- * const stream = server.experimental.tasks.requestStream(request, schema, options);
- * ```
- *
- * For high-level server usage with task-based tools, use `McpServer.experimental.tasks` instead.
- *
- * @experimental
- */
- class ExperimentalServerTasks {
- constructor(_server) {
- this._server = _server;
- }
- /**
- * Sends a request and returns an AsyncGenerator that yields response messages.
- * The generator is guaranteed to end with either a 'result' or 'error' message.
- *
- * This method provides streaming access to request processing, allowing you to
- * observe intermediate task status updates for task-augmented requests.
- *
- * @param request - The request to send
- * @param resultSchema - Zod schema for validating the result
- * @param options - Optional request options (timeout, signal, task creation params, etc.)
- * @returns AsyncGenerator that yields ResponseMessage objects
- *
- * @experimental
- */
- requestStream(request, resultSchema, options) {
- return this._server.requestStream(request, resultSchema, options);
- }
- /**
- * Sends a sampling request and returns an AsyncGenerator that yields response messages.
- * The generator is guaranteed to end with either a 'result' or 'error' message.
- *
- * For task-augmented requests, yields 'taskCreated' and 'taskStatus' messages
- * before the final result.
- *
- * @example
- * ```typescript
- * const stream = server.experimental.tasks.createMessageStream({
- * messages: [{ role: 'user', content: { type: 'text', text: 'Hello' } }],
- * maxTokens: 100
- * }, {
- * onprogress: (progress) => {
- * // Handle streaming tokens via progress notifications
- * console.log('Progress:', progress.message);
- * }
- * });
- *
- * for await (const message of stream) {
- * switch (message.type) {
- * case 'taskCreated':
- * console.log('Task created:', message.task.taskId);
- * break;
- * case 'taskStatus':
- * console.log('Task status:', message.task.status);
- * break;
- * case 'result':
- * console.log('Final result:', message.result);
- * break;
- * case 'error':
- * console.error('Error:', message.error);
- * break;
- * }
- * }
- * ```
- *
- * @param params - The sampling request parameters
- * @param options - Optional request options (timeout, signal, task creation params, onprogress, etc.)
- * @returns AsyncGenerator that yields ResponseMessage objects
- *
- * @experimental
- */
- createMessageStream(params, options) {
- // Access client capabilities via the server
- const clientCapabilities = this._server.getClientCapabilities();
- // Capability check - only required when tools/toolChoice are provided
- if ((params.tools || params.toolChoice) && !clientCapabilities?.sampling?.tools) {
- throw new Error('Client does not support sampling tools capability.');
- }
- // Message structure validation - always validate tool_use/tool_result pairs.
- // These may appear even without tools/toolChoice in the current request when
- // a previous sampling request returned tool_use and this is a follow-up with results.
- if (params.messages.length > 0) {
- const lastMessage = params.messages[params.messages.length - 1];
- const lastContent = Array.isArray(lastMessage.content) ? lastMessage.content : [lastMessage.content];
- const hasToolResults = lastContent.some(c => c.type === 'tool_result');
- const previousMessage = params.messages.length > 1 ? params.messages[params.messages.length - 2] : undefined;
- const previousContent = previousMessage
- ? Array.isArray(previousMessage.content)
- ? previousMessage.content
- : [previousMessage.content]
- : [];
- const hasPreviousToolUse = previousContent.some(c => c.type === 'tool_use');
- if (hasToolResults) {
- if (lastContent.some(c => c.type !== 'tool_result')) {
- throw new Error('The last message must contain only tool_result content if any is present');
- }
- if (!hasPreviousToolUse) {
- throw new Error('tool_result blocks are not matching any tool_use from the previous message');
- }
- }
- if (hasPreviousToolUse) {
- // Extract tool_use IDs from previous message and tool_result IDs from current message
- const toolUseIds = new Set(previousContent.filter(c => c.type === 'tool_use').map(c => c.id));
- const toolResultIds = new Set(lastContent.filter(c => c.type === 'tool_result').map(c => c.toolUseId));
- 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');
- }
- }
- }
- return this.requestStream({
- method: 'sampling/createMessage',
- params
- }, types_js_1.CreateMessageResultSchema, options);
- }
- /**
- * Sends an elicitation request and returns an AsyncGenerator that yields response messages.
- * The generator is guaranteed to end with either a 'result' or 'error' message.
- *
- * For task-augmented requests (especially URL-based elicitation), yields 'taskCreated'
- * and 'taskStatus' messages before the final result.
- *
- * @example
- * ```typescript
- * const stream = server.experimental.tasks.elicitInputStream({
- * mode: 'url',
- * message: 'Please authenticate',
- * elicitationId: 'auth-123',
- * url: 'https://example.com/auth'
- * }, {
- * task: { ttl: 300000 } // Task-augmented for long-running auth flow
- * });
- *
- * for await (const message of stream) {
- * switch (message.type) {
- * case 'taskCreated':
- * console.log('Task created:', message.task.taskId);
- * break;
- * case 'taskStatus':
- * console.log('Task status:', message.task.status);
- * break;
- * case 'result':
- * console.log('User action:', message.result.action);
- * break;
- * case 'error':
- * console.error('Error:', message.error);
- * break;
- * }
- * }
- * ```
- *
- * @param params - The elicitation request parameters
- * @param options - Optional request options (timeout, signal, task creation params, etc.)
- * @returns AsyncGenerator that yields ResponseMessage objects
- *
- * @experimental
- */
- elicitInputStream(params, options) {
- // Access client capabilities via the server
- const clientCapabilities = this._server.getClientCapabilities();
- const mode = params.mode ?? 'form';
- // Capability check based on mode
- switch (mode) {
- case 'url': {
- if (!clientCapabilities?.elicitation?.url) {
- throw new Error('Client does not support url elicitation.');
- }
- break;
- }
- case 'form': {
- if (!clientCapabilities?.elicitation?.form) {
- throw new Error('Client does not support form elicitation.');
- }
- break;
- }
- }
- // Normalize params to ensure mode is set for form mode (defaults to 'form' per spec)
- const normalizedParams = mode === 'form' && params.mode === undefined ? { ...params, mode: 'form' } : params;
- // Cast to ServerRequest needed because TypeScript can't narrow the union type
- // based on the discriminated 'method' field when constructing the object literal
- return this.requestStream({
- method: 'elicitation/create',
- params: normalizedParams
- }, types_js_1.ElicitResultSchema, options);
- }
- /**
- * Gets the current status of a task.
- *
- * @param taskId - The task identifier
- * @param options - Optional request options
- * @returns The task status
- *
- * @experimental
- */
- async getTask(taskId, options) {
- return this._server.getTask({ taskId }, options);
- }
- /**
- * Retrieves the result of a completed task.
- *
- * @param taskId - The task identifier
- * @param resultSchema - Zod schema for validating the result
- * @param options - Optional request options
- * @returns The task result
- *
- * @experimental
- */
- async getTaskResult(taskId, resultSchema, options) {
- return this._server.getTaskResult({ taskId }, resultSchema, options);
- }
- /**
- * Lists tasks with optional pagination.
- *
- * @param cursor - Optional pagination cursor
- * @param options - Optional request options
- * @returns List of tasks with optional next cursor
- *
- * @experimental
- */
- async listTasks(cursor, options) {
- return this._server.listTasks(cursor ? { cursor } : undefined, options);
- }
- /**
- * Cancels a running task.
- *
- * @param taskId - The task identifier
- * @param options - Optional request options
- *
- * @experimental
- */
- async cancelTask(taskId, options) {
- return this._server.cancelTask({ taskId }, options);
- }
- }
- exports.ExperimentalServerTasks = ExperimentalServerTasks;
- //# sourceMappingURL=server.js.map
|