(private _options?: ProtocolOptions)
| 364 | fallbackNotificationHandler?: (notification: Notification) => Promise<void>; |
| 365 | |
| 366 | constructor(private _options?: ProtocolOptions) { |
| 367 | this.setNotificationHandler(CancelledNotificationSchema, notification => { |
| 368 | this._oncancel(notification); |
| 369 | }); |
| 370 | |
| 371 | this.setNotificationHandler(ProgressNotificationSchema, notification => { |
| 372 | this._onprogress(notification as unknown as ProgressNotification); |
| 373 | }); |
| 374 | |
| 375 | this.setRequestHandler( |
| 376 | PingRequestSchema, |
| 377 | // Automatic pong by default. |
| 378 | _request => ({}) as SendResultT |
| 379 | ); |
| 380 | |
| 381 | // Install task handlers if TaskStore is provided |
| 382 | this._taskStore = _options?.taskStore; |
| 383 | this._taskMessageQueue = _options?.taskMessageQueue; |
| 384 | if (this._taskStore) { |
| 385 | this.setRequestHandler(GetTaskRequestSchema, async (request, extra) => { |
| 386 | const task = await this._taskStore!.getTask(request.params.taskId, extra.sessionId); |
| 387 | if (!task) { |
| 388 | throw new McpError(ErrorCode.InvalidParams, 'Failed to retrieve task: Task not found'); |
| 389 | } |
| 390 | |
| 391 | // Per spec: tasks/get responses SHALL NOT include related-task metadata |
| 392 | // as the taskId parameter is the source of truth |
| 393 | // @ts-expect-error SendResultT cannot contain GetTaskResult, but we include it in our derived types everywhere else |
| 394 | return { |
| 395 | ...task |
| 396 | } as SendResultT; |
| 397 | }); |
| 398 | |
| 399 | this.setRequestHandler(GetTaskPayloadRequestSchema, async (request, extra) => { |
| 400 | const handleTaskResult = async (): Promise<SendResultT> => { |
| 401 | const taskId = request.params.taskId; |
| 402 | |
| 403 | // Deliver queued messages |
| 404 | if (this._taskMessageQueue) { |
| 405 | let queuedMessage: QueuedMessage | undefined; |
| 406 | while ((queuedMessage = await this._taskMessageQueue.dequeue(taskId, extra.sessionId))) { |
| 407 | // Handle response and error messages by routing them to the appropriate resolver |
| 408 | if (queuedMessage.type === 'response' || queuedMessage.type === 'error') { |
| 409 | const message = queuedMessage.message; |
| 410 | const requestId = message.id; |
| 411 | |
| 412 | // Lookup resolver in _requestResolvers map |
| 413 | const resolver = this._requestResolvers.get(requestId as RequestId); |
| 414 | |
| 415 | if (resolver) { |
| 416 | // Remove resolver from map after invocation |
| 417 | this._requestResolvers.delete(requestId as RequestId); |
| 418 | |
| 419 | // Invoke resolver with response or error |
| 420 | if (queuedMessage.type === 'response') { |
| 421 | resolver(message as JSONRPCResultResponse); |
| 422 | } else { |
| 423 | // Convert JSONRPCError to McpError |
nothing calls this directly
no test coverage detected
searching dependent graphs…