Skip to content

Commit d044ace

Browse files
Only delete _taskToolMap entry on success; switch test to fake timers; fix JSDoc
1 parent a4e24fb commit d044ace

4 files changed

Lines changed: 18 additions & 12 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@modelcontextprotocol/sdk': patch
3+
---
4+
5+
Fix registerToolTask custom getTask/getTaskResult handlers not being invoked

src/server/mcp.ts

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -98,16 +98,15 @@ export class McpServer {
9898
getTaskResult: async (taskId: string, extra: RequestHandlerExtra<ServerRequest, ServerNotification>) => {
9999
const taskStore = extra.taskStore!;
100100
const handler = this._getTaskHandler(taskId);
101-
try {
102-
if (handler) {
103-
return await handler.getTaskResult({ ...extra, taskId, taskStore });
104-
}
105-
return await taskStore.getTaskResult(taskId);
106-
} finally {
107-
// Once the result has been retrieved the task is complete;
108-
// drop the taskId → toolName mapping to avoid unbounded growth.
109-
this._taskToolMap.delete(taskId);
110-
}
101+
const result = handler
102+
? await handler.getTaskResult({ ...extra, taskId, taskStore })
103+
: await taskStore.getTaskResult(taskId);
104+
// Once the result has been retrieved the task is complete;
105+
// drop the taskId → toolName mapping to avoid unbounded growth.
106+
// Cleanup on tasks/cancel would require a protocol-level hook and is
107+
// intentionally left out here.
108+
this._taskToolMap.delete(taskId);
109+
return result;
111110
}
112111
};
113112
this.server = new Server(serverInfo, { ...options, taskHandlerHooks });

src/shared/protocol.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ export type ProtocolOptions = {
108108
*/
109109
getTask?: (taskId: string, extra: RequestHandlerExtra<Request, Notification>) => Promise<GetTaskResult>;
110110
/**
111-
* Called when tasks/payload needs to retrieve the final result. If provided, must return the result.
111+
* Called when tasks/result needs to retrieve the final result. If provided, must return the result.
112112
*/
113113
getTaskResult?: (taskId: string, extra: RequestHandlerExtra<Request, Notification>) => Promise<Result>;
114114
};

test/server/mcp.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6818,6 +6818,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
68186818
});
68196819

68206820
test('should call custom getTask and getTaskResult handlers when client polls task directly', async () => {
6821+
vi.useFakeTimers();
68216822
const taskStore = new InMemoryTaskStore();
68226823

68236824
const getTaskSpy = vi.fn();
@@ -6910,7 +6911,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
69106911
const taskId = createResult.task.taskId;
69116912

69126913
// Wait for task to be ready to complete
6913-
await new Promise(resolve => setTimeout(resolve, 60));
6914+
vi.advanceTimersByTime(60);
69146915

69156916
// Client directly calls tasks/get - should invoke custom handler which completes the task
69166917
const getResult = await client.request({ method: 'tasks/get', params: { taskId } }, GetTaskResultSchema);
@@ -6922,6 +6923,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
69226923
expect(payloadResult.content).toBeDefined();
69236924
expect(getTaskResultSpy).toHaveBeenCalledWith(taskId);
69246925

6926+
vi.useRealTimers();
69256927
taskStore.cleanup();
69266928
});
69276929
});

0 commit comments

Comments
 (0)