@j0hanz/fetch-url-mcp 1.12.0 → 1.12.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -17
- package/dist/http/auth.d.ts.map +1 -1
- package/dist/http/auth.js +61 -20
- package/dist/http/helpers.d.ts +1 -1
- package/dist/http/helpers.d.ts.map +1 -1
- package/dist/http/helpers.js +7 -9
- package/dist/http/native.d.ts.map +1 -1
- package/dist/http/native.js +271 -54
- package/dist/http/rate-limit.d.ts.map +1 -1
- package/dist/http/rate-limit.js +2 -1
- package/dist/index.js +5 -4
- package/dist/lib/config.d.ts +1 -1
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +8 -1
- package/dist/lib/core.d.ts +8 -4
- package/dist/lib/core.d.ts.map +1 -1
- package/dist/lib/core.js +240 -73
- package/dist/lib/fetch-pipeline.d.ts.map +1 -1
- package/dist/lib/fetch-pipeline.js +15 -2
- package/dist/lib/http.d.ts.map +1 -1
- package/dist/lib/http.js +1 -1
- package/dist/lib/mcp-interop.d.ts +15 -3
- package/dist/lib/mcp-interop.d.ts.map +1 -1
- package/dist/lib/mcp-interop.js +92 -23
- package/dist/lib/url.d.ts.map +1 -1
- package/dist/lib/url.js +1 -1
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +2 -2
- package/dist/resources/index.d.ts +4 -0
- package/dist/resources/index.d.ts.map +1 -1
- package/dist/resources/index.js +39 -4
- package/dist/schemas.d.ts +5 -5
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +7 -9
- package/dist/server.d.ts +3 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +20 -11
- package/dist/tasks/execution.d.ts +1 -1
- package/dist/tasks/execution.d.ts.map +1 -1
- package/dist/tasks/execution.js +72 -25
- package/dist/tasks/handlers.d.ts.map +1 -1
- package/dist/tasks/handlers.js +31 -24
- package/dist/tasks/manager.d.ts +5 -2
- package/dist/tasks/manager.d.ts.map +1 -1
- package/dist/tasks/manager.js +58 -19
- package/dist/tasks/owner.d.ts +5 -0
- package/dist/tasks/owner.d.ts.map +1 -1
- package/dist/tasks/owner.js +15 -7
- package/dist/tasks/registry.d.ts +10 -8
- package/dist/tasks/registry.d.ts.map +1 -1
- package/dist/tasks/registry.js +27 -15
- package/dist/tools/fetch-url.d.ts +2 -0
- package/dist/tools/fetch-url.d.ts.map +1 -1
- package/dist/tools/fetch-url.js +76 -21
- package/dist/transform/dom-prep.d.ts.map +1 -1
- package/dist/transform/dom-prep.js +6 -6
- package/dist/transform/transform.d.ts.map +1 -1
- package/dist/transform/transform.js +17 -14
- package/dist/transform/worker-pool.d.ts.map +1 -1
- package/dist/transform/worker-pool.js +43 -3
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execution.d.ts","sourceRoot":"","sources":["../../src/tasks/execution.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAGL,KAAK,YAAY,EAClB,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"execution.d.ts","sourceRoot":"","sources":["../../src/tasks/execution.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAGL,KAAK,YAAY,EAClB,MAAM,oCAAoC,CAAC;AAc5C,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,KAAK,gBAAgB,EAErB,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AACtB,OAAO,EAGL,KAAK,eAAe,EAErB,MAAM,YAAY,CAAC;AAkCpB,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAGvD;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,aAAa,SAA4D,GACxE,MAAM,CAOR;AAED,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C;AAMD,KAAK,WAAW,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;AAC5C,KAAK,uBAAuB,GAAG,IAAI,CACjC,SAAS,EACP,QAAQ,GACR,QAAQ,GACR,eAAe,GACf,UAAU,GACV,OAAO,GACP,WAAW,GACX,eAAe,GACf,KAAK,GACL,cAAc,CACjB,CAAC;AAEF,wBAAgB,aAAa,CAAC,IAAI,EAAE,uBAAuB,GAAG,WAAW,CAYxE;AAED,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,SAAS,GACd,IAAI,CAmBN;AAED,wBAAgB,iBAAiB,IAAI,KAAK,CAEzC;AA2JD,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,uBAAuB,EAChC,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,YAAY,CAAC,CAwFvB"}
|
package/dist/tasks/execution.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { ErrorCode, McpError, } from '@modelcontextprotocol/sdk/types.js';
|
|
2
2
|
import { config } from '../lib/core.js';
|
|
3
|
-
import { logWarn, runWithRequestContext } from '../lib/core.js';
|
|
3
|
+
import { logDebug, logError, logInfo, logWarn, runWithRequestContext, } from '../lib/core.js';
|
|
4
|
+
import {} from '../lib/mcp-interop.js';
|
|
4
5
|
import { getErrorMessage } from '../lib/utils.js';
|
|
5
6
|
import { isObject } from '../lib/utils.js';
|
|
6
7
|
import { buildRelatedTaskMeta, } from './call-contract.js';
|
|
7
8
|
import { taskManager, } from './manager.js';
|
|
8
9
|
import { buildToolHandlerExtra, compact, tryReadToolStructuredError, } from './owner.js';
|
|
9
10
|
import { getTaskCapableTool, getTaskCapableToolSupport, } from './registry.js';
|
|
10
|
-
const TASK_NOT_FOUND_ERROR_CODE = -32002;
|
|
11
11
|
/* -------------------------------------------------------------------------------------------------
|
|
12
12
|
* Abort-controller management for in-flight task executions
|
|
13
13
|
* ------------------------------------------------------------------------------------------------- */
|
|
@@ -20,7 +20,7 @@ function attachAbortController(taskId) {
|
|
|
20
20
|
logWarn('Abort controller map reached task capacity — possible leak', {
|
|
21
21
|
size: taskAbortControllers.size,
|
|
22
22
|
maxTotal: config.tasks.maxTotal,
|
|
23
|
-
});
|
|
23
|
+
}, 'tasks');
|
|
24
24
|
}
|
|
25
25
|
const controller = new AbortController();
|
|
26
26
|
taskAbortControllers.set(taskId, controller);
|
|
@@ -48,6 +48,8 @@ export function toTaskSummary(task) {
|
|
|
48
48
|
taskId: task.taskId,
|
|
49
49
|
status: task.status,
|
|
50
50
|
...(task.statusMessage ? { statusMessage: task.statusMessage } : {}),
|
|
51
|
+
...(task.progress !== undefined ? { progress: task.progress } : {}),
|
|
52
|
+
...(task.total !== undefined ? { total: task.total } : {}),
|
|
51
53
|
createdAt: task.createdAt,
|
|
52
54
|
lastUpdatedAt: task.lastUpdatedAt,
|
|
53
55
|
ttl: task.ttl,
|
|
@@ -63,15 +65,15 @@ export function emitTaskStatusNotification(server, task) {
|
|
|
63
65
|
params: { ...toTaskSummary(task) },
|
|
64
66
|
})
|
|
65
67
|
.catch((error) => {
|
|
66
|
-
|
|
68
|
+
logError('Failed to send task status notification', {
|
|
67
69
|
taskId: task.taskId,
|
|
68
70
|
status: task.status,
|
|
69
71
|
error: getErrorMessage(error),
|
|
70
|
-
});
|
|
72
|
+
}, 'tasks');
|
|
71
73
|
});
|
|
72
74
|
}
|
|
73
75
|
export function throwTaskNotFound() {
|
|
74
|
-
throw new McpError(
|
|
76
|
+
throw new McpError(ErrorCode.InvalidParams, 'Task not found');
|
|
75
77
|
}
|
|
76
78
|
/* -------------------------------------------------------------------------------------------------
|
|
77
79
|
* Execution pipeline
|
|
@@ -87,28 +89,23 @@ function buildTaskFailureState(error) {
|
|
|
87
89
|
? (/^MCP error -?\d+:\s*(.*)$/s.exec(error.message)?.[1] ?? error.message)
|
|
88
90
|
: undefined;
|
|
89
91
|
const statusMessage = mcpErrorMessage ?? getErrorMessage(error);
|
|
90
|
-
const payload = { error: statusMessage };
|
|
91
92
|
if (error instanceof McpError) {
|
|
92
|
-
payload['code'] = error.code;
|
|
93
|
-
if (error.data !== undefined) {
|
|
94
|
-
payload['data'] = error.data;
|
|
95
|
-
}
|
|
96
93
|
return {
|
|
97
94
|
status: 'failed',
|
|
98
95
|
statusMessage,
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
96
|
+
error: {
|
|
97
|
+
code: error.code,
|
|
98
|
+
...(error.data !== undefined ? { data: error.data } : {}),
|
|
99
|
+
message: statusMessage,
|
|
102
100
|
},
|
|
103
101
|
};
|
|
104
102
|
}
|
|
105
|
-
payload['code'] = ErrorCode.InternalError;
|
|
106
103
|
return {
|
|
107
104
|
status: 'failed',
|
|
108
105
|
statusMessage,
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
106
|
+
error: {
|
|
107
|
+
code: ErrorCode.InternalError,
|
|
108
|
+
message: statusMessage,
|
|
112
109
|
},
|
|
113
110
|
};
|
|
114
111
|
}
|
|
@@ -131,30 +128,50 @@ async function runTaskToolExecution(params) {
|
|
|
131
128
|
...(sessionId ? { sessionId } : {}),
|
|
132
129
|
}, async () => {
|
|
133
130
|
const controller = attachAbortController(taskId);
|
|
131
|
+
const progressState = { closed: false };
|
|
134
132
|
try {
|
|
133
|
+
logInfo('Task execution started', { taskId, tool: tool.name }, 'tasks');
|
|
135
134
|
const relatedMeta = buildRelatedTaskMeta(taskId, meta);
|
|
136
135
|
const result = await tool.execute(args, {
|
|
137
136
|
signal: controller.signal,
|
|
138
137
|
requestId: taskId,
|
|
139
138
|
_meta: relatedMeta,
|
|
139
|
+
progressState,
|
|
140
140
|
canReportProgress: () => taskManager.getTask(taskId)?.status === 'working',
|
|
141
141
|
...compact({ sendNotification }),
|
|
142
|
-
onProgress: (
|
|
142
|
+
onProgress: (progress, message, total) => {
|
|
143
143
|
const current = taskManager.getTask(taskId);
|
|
144
144
|
if (current?.status === 'working' &&
|
|
145
|
-
current.statusMessage !== message
|
|
145
|
+
(current.statusMessage !== message ||
|
|
146
|
+
current.progress !== progress ||
|
|
147
|
+
(total !== undefined && current.total !== total))) {
|
|
146
148
|
updateTaskAndEmitStatus(server, taskId, {
|
|
147
149
|
statusMessage: message,
|
|
150
|
+
progress,
|
|
151
|
+
...(total !== undefined ? { total } : {}),
|
|
148
152
|
});
|
|
149
153
|
}
|
|
150
154
|
},
|
|
151
155
|
});
|
|
152
|
-
|
|
156
|
+
const completionUpdate = buildTaskCompletionUpdate(result, tool);
|
|
157
|
+
updateTaskAndEmitStatus(server, taskId, completionUpdate);
|
|
158
|
+
if (completionUpdate.status === 'completed') {
|
|
159
|
+
logInfo('Task execution completed', { taskId, tool: tool.name }, 'tasks');
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
logWarn('Task execution completed with tool error result', { taskId, tool: tool.name }, 'tasks');
|
|
163
|
+
}
|
|
153
164
|
}
|
|
154
165
|
catch (error) {
|
|
166
|
+
logError('Task execution failed', {
|
|
167
|
+
taskId,
|
|
168
|
+
tool: tool.name,
|
|
169
|
+
error: getErrorMessage(error),
|
|
170
|
+
}, 'tasks');
|
|
155
171
|
updateTaskAndEmitStatus(server, taskId, buildTaskFailureState(error));
|
|
156
172
|
}
|
|
157
173
|
finally {
|
|
174
|
+
progressState.closed = true;
|
|
158
175
|
taskAbortControllers.delete(taskId);
|
|
159
176
|
}
|
|
160
177
|
});
|
|
@@ -162,16 +179,21 @@ async function runTaskToolExecution(params) {
|
|
|
162
179
|
export async function handleToolCallRequest(server, request, context) {
|
|
163
180
|
const { params } = request;
|
|
164
181
|
// Validate the tool name first so an unknown tool always produces MethodNotFound
|
|
165
|
-
const tool = getTaskCapableTool(params.name);
|
|
182
|
+
const tool = getTaskCapableTool(server, params.name);
|
|
166
183
|
if (!tool) {
|
|
167
184
|
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: '${params.name}'`);
|
|
168
185
|
}
|
|
169
186
|
if (params.task) {
|
|
170
|
-
if (getTaskCapableToolSupport(params.name) === 'forbidden') {
|
|
187
|
+
if (getTaskCapableToolSupport(server, params.name) === 'forbidden') {
|
|
171
188
|
throw new McpError(ErrorCode.MethodNotFound, `Task augmentation is forbidden for tool '${params.name}'`);
|
|
172
189
|
}
|
|
173
190
|
const args = tool.parseArguments(params.arguments);
|
|
174
191
|
const task = taskManager.createTask(params.task.ttl !== undefined ? { ttl: params.task.ttl } : undefined, 'Task started', context.ownerKey);
|
|
192
|
+
logInfo('Task execution queued', {
|
|
193
|
+
taskId: task.taskId,
|
|
194
|
+
tool: params.name,
|
|
195
|
+
...(params.task.ttl !== undefined ? { ttl: params.task.ttl } : {}),
|
|
196
|
+
}, 'tasks');
|
|
175
197
|
void runTaskToolExecution({
|
|
176
198
|
server,
|
|
177
199
|
taskId: task.taskId,
|
|
@@ -183,8 +205,33 @@ export async function handleToolCallRequest(server, request, context) {
|
|
|
183
205
|
sendNotification: context.sendNotification,
|
|
184
206
|
}),
|
|
185
207
|
});
|
|
186
|
-
return {
|
|
208
|
+
return {
|
|
209
|
+
task: toTaskSummary(task),
|
|
210
|
+
...(tool.immediateResponse
|
|
211
|
+
? {
|
|
212
|
+
_meta: {
|
|
213
|
+
'io.modelcontextprotocol/model-immediate-response': tool.immediateResponse,
|
|
214
|
+
},
|
|
215
|
+
}
|
|
216
|
+
: {}),
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
if (getTaskCapableToolSupport(server, params.name) === 'required') {
|
|
220
|
+
throw new McpError(ErrorCode.MethodNotFound, `Task augmentation is required for tool '${params.name}'`);
|
|
187
221
|
}
|
|
188
222
|
const args = tool.parseArguments(params.arguments);
|
|
189
|
-
|
|
223
|
+
const progressState = { closed: false };
|
|
224
|
+
logDebug('Executing task-capable tool inline', {
|
|
225
|
+
tool: params.name,
|
|
226
|
+
hasProgressToken: params._meta?.progressToken !== undefined,
|
|
227
|
+
}, 'tasks');
|
|
228
|
+
try {
|
|
229
|
+
return await tool.execute(args, {
|
|
230
|
+
...buildToolHandlerExtra(context, params._meta),
|
|
231
|
+
progressState,
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
finally {
|
|
235
|
+
progressState.closed = true;
|
|
236
|
+
}
|
|
190
237
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../src/tasks/handlers.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAmCzE,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AA4D7E,UAAU,8BAA8B;IACtC,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,UAAU,6BAA6B;IACrC,oBAAoB,EAAE,OAAO,CAAC;IAC9B,0BAA0B,EAAE,OAAO,CAAC;CACrC;
|
|
1
|
+
{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../src/tasks/handlers.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAmCzE,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AA4D7E,UAAU,8BAA8B;IACtC,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,UAAU,6BAA6B;IACrC,oBAAoB,EAAE,OAAO,CAAC;IAC9B,0BAA0B,EAAE,OAAO,CAAC;CACrC;AAkBD,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,SAAS,EACjB,OAAO,CAAC,EAAE,8BAA8B,GACvC,6BAA6B,CAoK/B"}
|
package/dist/tasks/handlers.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
2
|
import {} from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
-
import { CallToolRequestSchema, ErrorCode,
|
|
3
|
+
import { CallToolRequestSchema, ErrorCode, } from '@modelcontextprotocol/sdk/types.js';
|
|
4
|
+
import { McpError } from '@modelcontextprotocol/sdk/types.js';
|
|
4
5
|
import { z } from 'zod';
|
|
5
|
-
import { logWarn, runWithRequestContext } from '../lib/core.js';
|
|
6
|
+
import { logDebug, logWarn, runWithRequestContext } from '../lib/core.js';
|
|
6
7
|
import { getSdkCallToolHandler } from '../lib/mcp-interop.js';
|
|
7
8
|
import { parseExtendedCallToolRequest, withRelatedTaskMeta, } from './call-contract.js';
|
|
8
9
|
import { abortTaskExecution, emitTaskStatusNotification, handleToolCallRequest, throwTaskNotFound, toTaskSummary, } from './execution.js';
|
|
@@ -40,15 +41,21 @@ function resolveOwnerScopedExtra(extra) {
|
|
|
40
41
|
ownerKey: resolveTaskOwnerKey(parsedExtra),
|
|
41
42
|
};
|
|
42
43
|
}
|
|
44
|
+
function throwStoredTaskError(task) {
|
|
45
|
+
if (task.error) {
|
|
46
|
+
throw new McpError(task.error.code, task.error.message, task.error.data);
|
|
47
|
+
}
|
|
48
|
+
throw new McpError(ErrorCode.InternalError, task.statusMessage ?? 'Task execution failed', { taskId: task.taskId });
|
|
49
|
+
}
|
|
43
50
|
export function registerTaskHandlers(server, options) {
|
|
44
51
|
const sdkCallToolHandler = getSdkCallToolHandler(server);
|
|
45
|
-
const taskCapableToolsRegistered = hasRegisteredTaskCapableTools();
|
|
52
|
+
const taskCapableToolsRegistered = hasRegisteredTaskCapableTools(server);
|
|
46
53
|
const requireInterception = options?.requireInterception ?? true;
|
|
47
54
|
if (!sdkCallToolHandler) {
|
|
48
55
|
if (taskCapableToolsRegistered && requireInterception) {
|
|
49
56
|
throw new Error('Task-capable tools are registered but SDK tools/call interception is unavailable. Upgrade compatibility or disable strict interception with TASKS_REQUIRE_INTERCEPTION=false.');
|
|
50
57
|
}
|
|
51
|
-
logWarn('Task call interception disabled: SDK tools/call handler unavailable; task-capable tools require MCP SDK compatibility update', { sdkVersion: 'unknown' });
|
|
58
|
+
logWarn('Task call interception disabled: SDK tools/call handler unavailable; task-capable tools require MCP SDK compatibility update', { sdkVersion: 'unknown' }, 'tasks');
|
|
52
59
|
}
|
|
53
60
|
if (sdkCallToolHandler) {
|
|
54
61
|
server.server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
|
|
@@ -66,11 +73,16 @@ export function registerTaskHandlers(server, options) {
|
|
|
66
73
|
const toolName = request.params.name;
|
|
67
74
|
// Only intercept task-capable tools managed by the local task registry.
|
|
68
75
|
// Delegate all other tools to the SDK handler to avoid shadowing future tools.
|
|
69
|
-
if (!hasTaskCapableTool(toolName)) {
|
|
76
|
+
if (!hasTaskCapableTool(server, toolName)) {
|
|
70
77
|
return sdkCallToolHandler(request, extra);
|
|
71
78
|
}
|
|
72
79
|
const parsed = parseExtendedCallToolRequest(request);
|
|
73
80
|
const context = resolveToolCallContext(parsedExtra, parsed.params._meta);
|
|
81
|
+
logDebug('Intercepted task-capable tool call', {
|
|
82
|
+
tool: toolName,
|
|
83
|
+
taskRequested: parsed.params.task !== undefined,
|
|
84
|
+
hasProgressToken: parsed.params._meta?.progressToken !== undefined,
|
|
85
|
+
}, 'tasks');
|
|
74
86
|
return handleToolCallRequest(server, parsed, context);
|
|
75
87
|
});
|
|
76
88
|
});
|
|
@@ -78,6 +90,7 @@ export function registerTaskHandlers(server, options) {
|
|
|
78
90
|
server.server.setRequestHandler(TaskGetSchema, (request, extra) => {
|
|
79
91
|
const { taskId } = request.params;
|
|
80
92
|
const { ownerKey } = resolveOwnerScopedExtra(extra);
|
|
93
|
+
logDebug('tasks/get requested', { taskId }, 'tasks');
|
|
81
94
|
const task = taskManager.getTask(taskId, ownerKey);
|
|
82
95
|
if (!task)
|
|
83
96
|
throwTaskNotFound();
|
|
@@ -86,31 +99,23 @@ export function registerTaskHandlers(server, options) {
|
|
|
86
99
|
server.server.setRequestHandler(TaskResultSchema, async (request, extra) => {
|
|
87
100
|
const { taskId } = request.params;
|
|
88
101
|
const { parsedExtra, ownerKey } = resolveOwnerScopedExtra(extra);
|
|
102
|
+
logDebug('tasks/result requested', { taskId }, 'tasks');
|
|
89
103
|
const task = await taskManager.waitForTerminalTask(taskId, ownerKey, parsedExtra?.signal);
|
|
90
104
|
if (!task)
|
|
91
105
|
throwTaskNotFound();
|
|
92
106
|
try {
|
|
107
|
+
if (task.status === 'cancelled') {
|
|
108
|
+
throwStoredTaskError(task);
|
|
109
|
+
}
|
|
93
110
|
if (task.status === 'failed') {
|
|
111
|
+
if (task.error) {
|
|
112
|
+
throwStoredTaskError(task);
|
|
113
|
+
}
|
|
94
114
|
const failedResult = (task.result ?? null);
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
text: JSON.stringify({
|
|
100
|
-
error: task.statusMessage ?? 'Task execution failed',
|
|
101
|
-
}),
|
|
102
|
-
},
|
|
103
|
-
],
|
|
104
|
-
isError: true,
|
|
105
|
-
};
|
|
106
|
-
return withRelatedTaskMeta(fallback, task.taskId);
|
|
107
|
-
}
|
|
108
|
-
if (task.status === 'cancelled') {
|
|
109
|
-
throw new McpError(ErrorCode.InvalidRequest, 'Task was cancelled', {
|
|
110
|
-
taskId: task.taskId,
|
|
111
|
-
status: 'cancelled',
|
|
112
|
-
...(task.statusMessage ? { statusMessage: task.statusMessage } : {}),
|
|
113
|
-
});
|
|
115
|
+
if (failedResult) {
|
|
116
|
+
return withRelatedTaskMeta(failedResult, task.taskId);
|
|
117
|
+
}
|
|
118
|
+
throwStoredTaskError(task);
|
|
114
119
|
}
|
|
115
120
|
const result = isServerResult(task.result)
|
|
116
121
|
? task.result
|
|
@@ -127,6 +132,7 @@ export function registerTaskHandlers(server, options) {
|
|
|
127
132
|
server.server.setRequestHandler(TaskListSchema, (request, extra) => {
|
|
128
133
|
const { ownerKey } = resolveOwnerScopedExtra(extra);
|
|
129
134
|
const cursor = request.params?.cursor;
|
|
135
|
+
logDebug('tasks/list requested', { hasCursor: cursor !== undefined }, 'tasks');
|
|
130
136
|
const { tasks, nextCursor } = taskManager.listTasks(cursor === undefined ? { ownerKey } : { ownerKey, cursor });
|
|
131
137
|
return {
|
|
132
138
|
tasks: tasks.map((task) => toTaskSummary(task)),
|
|
@@ -136,6 +142,7 @@ export function registerTaskHandlers(server, options) {
|
|
|
136
142
|
server.server.setRequestHandler(TaskCancelSchema, (request, extra) => {
|
|
137
143
|
const { taskId } = request.params;
|
|
138
144
|
const { ownerKey } = resolveOwnerScopedExtra(extra);
|
|
145
|
+
logDebug('tasks/cancel requested', { taskId }, 'tasks');
|
|
139
146
|
const task = taskManager.cancelTask(taskId, ownerKey);
|
|
140
147
|
if (!task)
|
|
141
148
|
throwTaskNotFound();
|
package/dist/tasks/manager.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type TaskStatus = 'working' | 'completed' | 'failed' | 'cancelled';
|
|
1
|
+
export type TaskStatus = 'working' | 'input_required' | 'completed' | 'failed' | 'cancelled';
|
|
2
2
|
export interface TaskError {
|
|
3
3
|
code: number;
|
|
4
4
|
message: string;
|
|
@@ -9,6 +9,8 @@ export interface TaskState {
|
|
|
9
9
|
ownerKey: string;
|
|
10
10
|
status: TaskStatus;
|
|
11
11
|
statusMessage?: string;
|
|
12
|
+
progress?: number;
|
|
13
|
+
total?: number;
|
|
12
14
|
createdAt: string;
|
|
13
15
|
lastUpdatedAt: string;
|
|
14
16
|
ttl: number;
|
|
@@ -25,6 +27,8 @@ export interface CreateTaskResult {
|
|
|
25
27
|
taskId: string;
|
|
26
28
|
status: TaskStatus;
|
|
27
29
|
statusMessage?: string;
|
|
30
|
+
progress?: number;
|
|
31
|
+
total?: number;
|
|
28
32
|
createdAt: string;
|
|
29
33
|
lastUpdatedAt: string;
|
|
30
34
|
ttl: number;
|
|
@@ -33,7 +37,6 @@ export interface CreateTaskResult {
|
|
|
33
37
|
}
|
|
34
38
|
declare class TaskManager {
|
|
35
39
|
private tasks;
|
|
36
|
-
private activeTaskCount;
|
|
37
40
|
private ownerCounts;
|
|
38
41
|
private readonly waiters;
|
|
39
42
|
private cleanupInterval;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/tasks/manager.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,UAAU,
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/tasks/manager.ts"],"names":[],"mappings":"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"}
|
package/dist/tasks/manager.js
CHANGED
|
@@ -2,7 +2,7 @@ import { randomUUID } from 'node:crypto';
|
|
|
2
2
|
import { createHmac, randomBytes } from 'node:crypto';
|
|
3
3
|
import { setInterval } from 'node:timers';
|
|
4
4
|
import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
|
|
5
|
-
import { config, logWarn } from '../lib/core.js';
|
|
5
|
+
import { config, logInfo, logWarn } from '../lib/core.js';
|
|
6
6
|
import { isObject, timingSafeEqualUtf8 } from '../lib/utils.js';
|
|
7
7
|
import { TaskWaiterRegistry, waitForTerminalTask as waitForTerminalTaskWithDeadline, } from './waiters.js';
|
|
8
8
|
const DEFAULT_TTL_MS = 60_000;
|
|
@@ -15,12 +15,18 @@ const CLEANUP_INTERVAL_MS = 60_000;
|
|
|
15
15
|
const RESULT_DELIVERY_GRACE_MS = 10_000;
|
|
16
16
|
const TASK_STATUS_VALUES = new Set([
|
|
17
17
|
'working',
|
|
18
|
+
'input_required',
|
|
19
|
+
'completed',
|
|
20
|
+
'failed',
|
|
21
|
+
'cancelled',
|
|
22
|
+
]);
|
|
23
|
+
const TERMINAL_STATUSES = new Set([
|
|
18
24
|
'completed',
|
|
19
25
|
'failed',
|
|
20
26
|
'cancelled',
|
|
21
27
|
]);
|
|
22
28
|
function isTerminalStatus(status) {
|
|
23
|
-
return status
|
|
29
|
+
return TERMINAL_STATUSES.has(status);
|
|
24
30
|
}
|
|
25
31
|
function resolveNextTaskStatus(task, updates) {
|
|
26
32
|
const nextStatus = updates.status;
|
|
@@ -39,9 +45,24 @@ function normalizeTaskTtl(ttl) {
|
|
|
39
45
|
return DEFAULT_TTL_MS;
|
|
40
46
|
return Math.max(MIN_TTL_MS, Math.min(Math.trunc(ttl), MAX_TTL_MS));
|
|
41
47
|
}
|
|
48
|
+
function logTaskStatusTransition(task, previousStatus, nextStatus) {
|
|
49
|
+
if (previousStatus === nextStatus)
|
|
50
|
+
return;
|
|
51
|
+
const meta = {
|
|
52
|
+
taskId: task.taskId,
|
|
53
|
+
ownerKey: task.ownerKey,
|
|
54
|
+
previousStatus,
|
|
55
|
+
nextStatus,
|
|
56
|
+
...(task.statusMessage ? { statusMessage: task.statusMessage } : {}),
|
|
57
|
+
};
|
|
58
|
+
if (nextStatus === 'failed') {
|
|
59
|
+
logWarn('Task status changed to failed', meta, 'tasks');
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
logInfo('Task status changed', meta, 'tasks');
|
|
63
|
+
}
|
|
42
64
|
class TaskManager {
|
|
43
65
|
tasks = new Map();
|
|
44
|
-
activeTaskCount = 0;
|
|
45
66
|
ownerCounts = new Map();
|
|
46
67
|
waiters = new TaskWaiterRegistry(isTerminalStatus);
|
|
47
68
|
cleanupInterval = null;
|
|
@@ -67,6 +88,11 @@ class TaskManager {
|
|
|
67
88
|
const now = Date.now();
|
|
68
89
|
for (const task of this.tasks.values()) {
|
|
69
90
|
if (this.isTaskExpired(task, now)) {
|
|
91
|
+
logWarn('Task expired', {
|
|
92
|
+
taskId: task.taskId,
|
|
93
|
+
ownerKey: task.ownerKey,
|
|
94
|
+
status: task.status,
|
|
95
|
+
}, 'tasks');
|
|
70
96
|
this.removeTask(task.taskId);
|
|
71
97
|
}
|
|
72
98
|
}
|
|
@@ -90,15 +116,18 @@ class TaskManager {
|
|
|
90
116
|
task.lastUpdatedAt = new Date().toISOString();
|
|
91
117
|
}
|
|
92
118
|
cancelActiveTask(task, statusMessage) {
|
|
93
|
-
this.applyTaskUpdate(task, {
|
|
119
|
+
this.applyTaskUpdate(task, {
|
|
120
|
+
status: 'cancelled',
|
|
121
|
+
statusMessage,
|
|
122
|
+
error: {
|
|
123
|
+
code: ErrorCode.ConnectionClosed,
|
|
124
|
+
message: statusMessage,
|
|
125
|
+
data: { code: 'ABORTED' },
|
|
126
|
+
},
|
|
127
|
+
});
|
|
94
128
|
this.waiters.notify(task);
|
|
95
|
-
this.releaseTaskCapacity(task);
|
|
96
129
|
}
|
|
97
130
|
releaseTaskCapacity(task) {
|
|
98
|
-
const internal = task;
|
|
99
|
-
if (!internal._capacityCounted)
|
|
100
|
-
return;
|
|
101
|
-
internal._capacityCounted = false;
|
|
102
131
|
const { ownerKey } = task;
|
|
103
132
|
const nextCount = (this.ownerCounts.get(ownerKey) ?? 0) - 1;
|
|
104
133
|
if (nextCount > 0) {
|
|
@@ -107,19 +136,16 @@ class TaskManager {
|
|
|
107
136
|
else {
|
|
108
137
|
this.ownerCounts.delete(ownerKey);
|
|
109
138
|
}
|
|
110
|
-
if (this.activeTaskCount > 0)
|
|
111
|
-
this.activeTaskCount--;
|
|
112
139
|
}
|
|
113
140
|
reserveTaskCapacity(ownerKey) {
|
|
114
141
|
const { maxPerOwner, maxTotal } = config.tasks;
|
|
115
|
-
if (this.
|
|
142
|
+
if (this.tasks.size >= maxTotal) {
|
|
116
143
|
throw new McpError(ErrorCode.InvalidRequest, `Task capacity reached (${maxTotal} total tasks)`);
|
|
117
144
|
}
|
|
118
145
|
if ((this.ownerCounts.get(ownerKey) ?? 0) >= maxPerOwner) {
|
|
119
146
|
throw new McpError(ErrorCode.InvalidRequest, `Task capacity reached for owner (${maxPerOwner} tasks)`);
|
|
120
147
|
}
|
|
121
148
|
this.ownerCounts.set(ownerKey, (this.ownerCounts.get(ownerKey) ?? 0) + 1);
|
|
122
|
-
this.activeTaskCount += 1;
|
|
123
149
|
}
|
|
124
150
|
createTask(options, statusMessage = 'Task started', ownerKey = DEFAULT_OWNER_KEY) {
|
|
125
151
|
this.removeExpiredTasks();
|
|
@@ -136,10 +162,14 @@ class TaskManager {
|
|
|
136
162
|
ttl: normalizeTaskTtl(options?.ttl),
|
|
137
163
|
pollInterval: DEFAULT_POLL_INTERVAL_MS,
|
|
138
164
|
_createdAtMs: now.getTime(),
|
|
139
|
-
_capacityCounted: true,
|
|
140
165
|
};
|
|
141
166
|
this.tasks.set(task.taskId, task);
|
|
142
167
|
this.ensureCleanupLoop();
|
|
168
|
+
logInfo('Task created', {
|
|
169
|
+
taskId: task.taskId,
|
|
170
|
+
ownerKey,
|
|
171
|
+
ttl: task.ttl,
|
|
172
|
+
}, 'tasks');
|
|
143
173
|
return task;
|
|
144
174
|
}
|
|
145
175
|
lookupActiveTask(taskId, ownerKey) {
|
|
@@ -160,25 +190,24 @@ class TaskManager {
|
|
|
160
190
|
updateTask(taskId, updates) {
|
|
161
191
|
const task = this.tasks.get(taskId);
|
|
162
192
|
if (!task) {
|
|
163
|
-
logWarn('updateTask called for unknown task', { taskId });
|
|
193
|
+
logWarn('updateTask called for unknown task', { taskId }, 'tasks');
|
|
164
194
|
return;
|
|
165
195
|
}
|
|
166
196
|
if (isTerminalStatus(task.status)) {
|
|
167
197
|
logWarn('updateTask called for terminal task', {
|
|
168
198
|
taskId,
|
|
169
199
|
currentStatus: task.status,
|
|
170
|
-
});
|
|
200
|
+
}, 'tasks');
|
|
171
201
|
return;
|
|
172
202
|
}
|
|
173
203
|
const nextStatus = resolveNextTaskStatus(task, updates);
|
|
204
|
+
const previousStatus = task.status;
|
|
174
205
|
this.applyTaskUpdate(task, {
|
|
175
206
|
...updates,
|
|
176
207
|
...(updates.status === undefined ? {} : { status: nextStatus }),
|
|
177
208
|
});
|
|
209
|
+
logTaskStatusTransition(task, previousStatus, task.status);
|
|
178
210
|
this.waiters.notify(task);
|
|
179
|
-
if (isTerminalStatus(nextStatus)) {
|
|
180
|
-
this.releaseTaskCapacity(task);
|
|
181
|
-
}
|
|
182
211
|
}
|
|
183
212
|
cancelTask(taskId, ownerKey) {
|
|
184
213
|
const task = this.lookupActiveTask(taskId, ownerKey);
|
|
@@ -188,6 +217,10 @@ class TaskManager {
|
|
|
188
217
|
throw new McpError(ErrorCode.InvalidParams, `Cannot cancel task: already in terminal status '${task.status}'`);
|
|
189
218
|
}
|
|
190
219
|
this.cancelActiveTask(task, 'The task was cancelled by request.');
|
|
220
|
+
logInfo('Task cancelled by request', {
|
|
221
|
+
taskId: task.taskId,
|
|
222
|
+
ownerKey: task.ownerKey,
|
|
223
|
+
}, 'tasks');
|
|
191
224
|
return task;
|
|
192
225
|
}
|
|
193
226
|
cancelTasksByOwner(ownerKey, statusMessage = 'The task was cancelled because its owner is no longer active.') {
|
|
@@ -200,6 +233,12 @@ class TaskManager {
|
|
|
200
233
|
cancelled.push(task);
|
|
201
234
|
}
|
|
202
235
|
}
|
|
236
|
+
if (cancelled.length > 0) {
|
|
237
|
+
logInfo('Tasks cancelled for owner', {
|
|
238
|
+
ownerKey,
|
|
239
|
+
count: cancelled.length,
|
|
240
|
+
}, 'tasks');
|
|
241
|
+
}
|
|
203
242
|
return cancelled;
|
|
204
243
|
}
|
|
205
244
|
collectPage(ownerKey, anchorTaskId, pageSize) {
|
package/dist/tasks/owner.d.ts
CHANGED
|
@@ -21,6 +21,10 @@ export interface ToolExecutionContext {
|
|
|
21
21
|
requestMeta?: ToolCallRequestMeta;
|
|
22
22
|
}
|
|
23
23
|
export type ToolCallContext = ToolExecutionContext;
|
|
24
|
+
interface AuthIdentity {
|
|
25
|
+
clientId?: string;
|
|
26
|
+
token?: string;
|
|
27
|
+
}
|
|
24
28
|
/** Strip keys whose value is `undefined`, returning an object with only the
|
|
25
29
|
* present keys. Return type correctly omits the `undefined` union so the result
|
|
26
30
|
* is compatible with `exactOptionalPropertyTypes`. */
|
|
@@ -29,6 +33,7 @@ type Compacted<T extends object> = {
|
|
|
29
33
|
};
|
|
30
34
|
export declare function compact<T extends object>(obj: T): Compacted<T>;
|
|
31
35
|
export declare function parseHandlerExtra(extra: unknown): HandlerExtra | undefined;
|
|
36
|
+
export declare function buildAuthenticatedOwnerKey(authInfo?: AuthIdentity): string | undefined;
|
|
32
37
|
export declare function resolveTaskOwnerKey(extra?: HandlerExtra): string;
|
|
33
38
|
export declare function resolveToolCallContext(extra?: HandlerExtra, requestMeta?: ToolCallRequestMeta): ToolCallContext;
|
|
34
39
|
export declare function buildToolHandlerExtra(context: ToolExecutionContext, requestMeta?: ToolCallRequestMeta): ToolHandlerExtra;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"owner.d.ts","sourceRoot":"","sources":["../../src/tasks/owner.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"owner.d.ts","sourceRoot":"","sources":["../../src/tasks/owner.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAQvE,OAAO,KAAK,EACV,oBAAoB,EACpB,gBAAgB,EACjB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,oBAAoB,CAAC;AAM5B,UAAU,YAAY;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACjD,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,gBAAgB,CAAC,EAAE,CAAC,YAAY,EAAE,oBAAoB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzE,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,gBAAgB,CAAC,EAAE,CAAC,YAAY,EAAE,oBAAoB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzE,WAAW,CAAC,EAAE,mBAAmB,CAAC;CACnC;AAED,MAAM,MAAM,eAAe,GAAG,oBAAoB,CAAC;AAEnD,UAAU,YAAY;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;sDAEsD;AACtD,KAAK,SAAS,CAAC,CAAC,SAAS,MAAM,IAAI;KAChC,CAAC,IAAI,MAAM,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,SAAS,KAAK,GACnD,KAAK,GACL,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC;CAClC,CAAC;AAEF,wBAAgB,OAAO,CAAC,CAAC,SAAS,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAQ9D;AA2BD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY,GAAG,SAAS,CA0B1E;AAED,wBAAgB,0BAA0B,CACxC,QAAQ,CAAC,EAAE,YAAY,GACtB,MAAM,GAAG,SAAS,CAUpB;AAED,wBAAgB,mBAAmB,CAAC,KAAK,CAAC,EAAE,YAAY,GAAG,MAAM,CAWhE;AAuDD,wBAAgB,sBAAsB,CACpC,KAAK,CAAC,EAAE,YAAY,EACpB,WAAW,CAAC,EAAE,mBAAmB,GAChC,eAAe,CAEjB;AAED,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,oBAAoB,EAC7B,WAAW,CAAC,EAAE,mBAAmB,GAChC,gBAAgB,CAOlB;AAED,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,EAC5E,OAAO,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,GAC7D,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAmBvD;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,YAAY,CAEpE;AAWD,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAe7E"}
|
package/dist/tasks/owner.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { hash, randomUUID } from 'node:crypto';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { getRequestId, runWithRequestContext } from '../lib/core.js';
|
|
3
|
+
import { getRequestId, resolveMcpSessionOwnerKey, runWithRequestContext, } from '../lib/core.js';
|
|
4
4
|
import { isObject } from '../lib/utils.js';
|
|
5
5
|
import { sanitizeToolCallMeta, } from './call-contract.js';
|
|
6
6
|
export function compact(obj) {
|
|
@@ -54,13 +54,21 @@ export function parseHandlerExtra(extra) {
|
|
|
54
54
|
}
|
|
55
55
|
return parsed;
|
|
56
56
|
}
|
|
57
|
+
export function buildAuthenticatedOwnerKey(authInfo) {
|
|
58
|
+
const authClientId = typeof authInfo?.clientId === 'string' ? authInfo.clientId : '';
|
|
59
|
+
const authToken = typeof authInfo?.token === 'string' ? authInfo.token : '';
|
|
60
|
+
if (authClientId || authToken) {
|
|
61
|
+
return `auth:${hash('sha256', `${authClientId}:${authToken}`, 'hex')}`;
|
|
62
|
+
}
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
57
65
|
export function resolveTaskOwnerKey(extra) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
66
|
+
const authenticatedOwnerKey = buildAuthenticatedOwnerKey(extra?.authInfo);
|
|
67
|
+
if (authenticatedOwnerKey)
|
|
68
|
+
return authenticatedOwnerKey;
|
|
69
|
+
if (extra?.sessionId) {
|
|
70
|
+
return (resolveMcpSessionOwnerKey(extra.sessionId) ?? `session:${extra.sessionId}`);
|
|
71
|
+
}
|
|
64
72
|
return 'default';
|
|
65
73
|
}
|
|
66
74
|
function resolveRequestIdFromExtra(extra) {
|
package/dist/tasks/registry.d.ts
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
1
2
|
import type { ServerResult } from '@modelcontextprotocol/sdk/types.js';
|
|
2
3
|
import type { ToolHandlerExtra } from '../lib/mcp-interop.js';
|
|
3
|
-
export type TaskCapableToolSupport = 'optional' | 'forbidden';
|
|
4
|
+
export type TaskCapableToolSupport = 'required' | 'optional' | 'forbidden';
|
|
4
5
|
export interface TaskCapableToolDescriptor<TArgs = unknown> {
|
|
5
6
|
name: string;
|
|
6
7
|
parseArguments: (args: unknown) => TArgs;
|
|
7
8
|
execute: (args: TArgs, extra?: ToolHandlerExtra) => Promise<ServerResult>;
|
|
8
9
|
getCompletionStatusMessage?: (result: ServerResult) => string | undefined;
|
|
9
10
|
taskSupport?: TaskCapableToolSupport;
|
|
11
|
+
immediateResponse?: string;
|
|
10
12
|
}
|
|
11
|
-
export declare function registerTaskCapableTool<TArgs>(descriptor: TaskCapableToolDescriptor<TArgs>): void;
|
|
12
|
-
export declare function unregisterTaskCapableTool(name: string): void;
|
|
13
|
-
export declare function getTaskCapableTool(name: string): TaskCapableToolDescriptor | undefined;
|
|
14
|
-
export declare function getTaskCapableToolSupport(name: string): TaskCapableToolSupport | undefined;
|
|
15
|
-
export declare function hasTaskCapableTool(name: string): boolean;
|
|
16
|
-
export declare function hasRegisteredTaskCapableTools(): boolean;
|
|
17
|
-
export declare function setTaskCapableToolSupport(name: string, support: TaskCapableToolSupport): void;
|
|
13
|
+
export declare function registerTaskCapableTool<TArgs>(server: McpServer, descriptor: TaskCapableToolDescriptor<TArgs>): void;
|
|
14
|
+
export declare function unregisterTaskCapableTool(server: McpServer, name: string): void;
|
|
15
|
+
export declare function getTaskCapableTool(server: McpServer, name: string): TaskCapableToolDescriptor | undefined;
|
|
16
|
+
export declare function getTaskCapableToolSupport(server: McpServer, name: string): TaskCapableToolSupport | undefined;
|
|
17
|
+
export declare function hasTaskCapableTool(server: McpServer, name: string): boolean;
|
|
18
|
+
export declare function hasRegisteredTaskCapableTools(server: McpServer): boolean;
|
|
19
|
+
export declare function setTaskCapableToolSupport(server: McpServer, name: string, support: TaskCapableToolSupport): void;
|
|
18
20
|
//# sourceMappingURL=registry.d.ts.map
|