client.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. "use strict";
  2. /**
  3. * Experimental client task features for MCP SDK.
  4. * WARNING: These APIs are experimental and may change without notice.
  5. *
  6. * @experimental
  7. */
  8. Object.defineProperty(exports, "__esModule", { value: true });
  9. exports.ExperimentalClientTasks = void 0;
  10. const types_js_1 = require("../../types.js");
  11. /**
  12. * Experimental task features for MCP clients.
  13. *
  14. * Access via `client.experimental.tasks`:
  15. * ```typescript
  16. * const stream = client.experimental.tasks.callToolStream({ name: 'tool', arguments: {} });
  17. * const task = await client.experimental.tasks.getTask(taskId);
  18. * ```
  19. *
  20. * @experimental
  21. */
  22. class ExperimentalClientTasks {
  23. constructor(_client) {
  24. this._client = _client;
  25. }
  26. /**
  27. * Calls a tool and returns an AsyncGenerator that yields response messages.
  28. * The generator is guaranteed to end with either a 'result' or 'error' message.
  29. *
  30. * This method provides streaming access to tool execution, allowing you to
  31. * observe intermediate task status updates for long-running tool calls.
  32. * Automatically validates structured output if the tool has an outputSchema.
  33. *
  34. * @example
  35. * ```typescript
  36. * const stream = client.experimental.tasks.callToolStream({ name: 'myTool', arguments: {} });
  37. * for await (const message of stream) {
  38. * switch (message.type) {
  39. * case 'taskCreated':
  40. * console.log('Tool execution started:', message.task.taskId);
  41. * break;
  42. * case 'taskStatus':
  43. * console.log('Tool status:', message.task.status);
  44. * break;
  45. * case 'result':
  46. * console.log('Tool result:', message.result);
  47. * break;
  48. * case 'error':
  49. * console.error('Tool error:', message.error);
  50. * break;
  51. * }
  52. * }
  53. * ```
  54. *
  55. * @param params - Tool call parameters (name and arguments)
  56. * @param resultSchema - Zod schema for validating the result (defaults to CallToolResultSchema)
  57. * @param options - Optional request options (timeout, signal, task creation params, etc.)
  58. * @returns AsyncGenerator that yields ResponseMessage objects
  59. *
  60. * @experimental
  61. */
  62. async *callToolStream(params, resultSchema = types_js_1.CallToolResultSchema, options) {
  63. // Access Client's internal methods
  64. const clientInternal = this._client;
  65. // Add task creation parameters if server supports it and not explicitly provided
  66. const optionsWithTask = {
  67. ...options,
  68. // We check if the tool is known to be a task during auto-configuration, but assume
  69. // the caller knows what they're doing if they pass this explicitly
  70. task: options?.task ?? (clientInternal.isToolTask(params.name) ? {} : undefined)
  71. };
  72. const stream = clientInternal.requestStream({ method: 'tools/call', params }, resultSchema, optionsWithTask);
  73. // Get the validator for this tool (if it has an output schema)
  74. const validator = clientInternal.getToolOutputValidator(params.name);
  75. // Iterate through the stream and validate the final result if needed
  76. for await (const message of stream) {
  77. // If this is a result message and the tool has an output schema, validate it
  78. if (message.type === 'result' && validator) {
  79. const result = message.result;
  80. // If tool has outputSchema, it MUST return structuredContent (unless it's an error)
  81. if (!result.structuredContent && !result.isError) {
  82. yield {
  83. type: 'error',
  84. error: new types_js_1.McpError(types_js_1.ErrorCode.InvalidRequest, `Tool ${params.name} has an output schema but did not return structured content`)
  85. };
  86. return;
  87. }
  88. // Only validate structured content if present (not when there's an error)
  89. if (result.structuredContent) {
  90. try {
  91. // Validate the structured content against the schema
  92. const validationResult = validator(result.structuredContent);
  93. if (!validationResult.valid) {
  94. yield {
  95. type: 'error',
  96. error: new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams, `Structured content does not match the tool's output schema: ${validationResult.errorMessage}`)
  97. };
  98. return;
  99. }
  100. }
  101. catch (error) {
  102. if (error instanceof types_js_1.McpError) {
  103. yield { type: 'error', error };
  104. return;
  105. }
  106. yield {
  107. type: 'error',
  108. error: new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams, `Failed to validate structured content: ${error instanceof Error ? error.message : String(error)}`)
  109. };
  110. return;
  111. }
  112. }
  113. }
  114. // Yield the message (either validated result or any other message type)
  115. yield message;
  116. }
  117. }
  118. /**
  119. * Gets the current status of a task.
  120. *
  121. * @param taskId - The task identifier
  122. * @param options - Optional request options
  123. * @returns The task status
  124. *
  125. * @experimental
  126. */
  127. async getTask(taskId, options) {
  128. return this._client.getTask({ taskId }, options);
  129. }
  130. /**
  131. * Retrieves the result of a completed task.
  132. *
  133. * @param taskId - The task identifier
  134. * @param resultSchema - Zod schema for validating the result
  135. * @param options - Optional request options
  136. * @returns The task result
  137. *
  138. * @experimental
  139. */
  140. async getTaskResult(taskId, resultSchema, options) {
  141. // Delegate to the client's underlying Protocol method
  142. return this._client.getTaskResult({ taskId }, resultSchema, options);
  143. }
  144. /**
  145. * Lists tasks with optional pagination.
  146. *
  147. * @param cursor - Optional pagination cursor
  148. * @param options - Optional request options
  149. * @returns List of tasks with optional next cursor
  150. *
  151. * @experimental
  152. */
  153. async listTasks(cursor, options) {
  154. // Delegate to the client's underlying Protocol method
  155. return this._client.listTasks(cursor ? { cursor } : undefined, options);
  156. }
  157. /**
  158. * Cancels a running task.
  159. *
  160. * @param taskId - The task identifier
  161. * @param options - Optional request options
  162. *
  163. * @experimental
  164. */
  165. async cancelTask(taskId, options) {
  166. // Delegate to the client's underlying Protocol method
  167. return this._client.cancelTask({ taskId }, options);
  168. }
  169. /**
  170. * Sends a request and returns an AsyncGenerator that yields response messages.
  171. * The generator is guaranteed to end with either a 'result' or 'error' message.
  172. *
  173. * This method provides streaming access to request processing, allowing you to
  174. * observe intermediate task status updates for task-augmented requests.
  175. *
  176. * @param request - The request to send
  177. * @param resultSchema - Zod schema for validating the result
  178. * @param options - Optional request options (timeout, signal, task creation params, etc.)
  179. * @returns AsyncGenerator that yields ResponseMessage objects
  180. *
  181. * @experimental
  182. */
  183. requestStream(request, resultSchema, options) {
  184. return this._client.requestStream(request, resultSchema, options);
  185. }
  186. }
  187. exports.ExperimentalClientTasks = ExperimentalClientTasks;
  188. //# sourceMappingURL=client.js.map