@j0hanz/fetch-url-mcp 1.3.0 → 1.4.0
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 +24 -21
- package/dist/cli.d.ts +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +18 -12
- package/dist/cli.js.map +1 -1
- package/dist/http/auth.d.ts +15 -1
- package/dist/http/auth.d.ts.map +1 -1
- package/dist/http/auth.js +84 -17
- package/dist/http/auth.js.map +1 -1
- package/dist/http/health.d.ts +1 -1
- package/dist/http/health.d.ts.map +1 -1
- package/dist/http/health.js +5 -15
- package/dist/http/health.js.map +1 -1
- package/dist/http/helpers.d.ts +1 -8
- package/dist/http/helpers.d.ts.map +1 -1
- package/dist/http/helpers.js +13 -13
- package/dist/http/helpers.js.map +1 -1
- package/dist/http/native.d.ts.map +1 -1
- package/dist/http/native.js +126 -23
- package/dist/http/native.js.map +1 -1
- package/dist/http/rate-limit.d.ts +2 -1
- package/dist/http/rate-limit.d.ts.map +1 -1
- package/dist/http/rate-limit.js +33 -26
- package/dist/http/rate-limit.js.map +1 -1
- package/dist/index.js +22 -19
- package/dist/index.js.map +1 -1
- package/dist/lib/cache.d.ts.map +1 -0
- package/dist/{cache.js → lib/cache.js} +15 -11
- package/dist/lib/cache.js.map +1 -0
- package/dist/{config.d.ts → lib/config.d.ts} +2 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/{config.js → lib/config.js} +4 -2
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/crypto.d.ts.map +1 -0
- package/dist/{crypto.js → lib/crypto.js} +6 -3
- package/dist/lib/crypto.js.map +1 -0
- package/dist/lib/dom-noise-removal.d.ts.map +1 -0
- package/dist/{dom-noise-removal.js → lib/dom-noise-removal.js} +1 -2
- package/dist/lib/dom-noise-removal.js.map +1 -0
- package/dist/lib/download.d.ts.map +1 -0
- package/dist/{download.js → lib/download.js} +7 -7
- package/dist/lib/download.js.map +1 -0
- package/dist/{errors.d.ts → lib/errors.d.ts} +3 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/{errors.js → lib/errors.js} +8 -1
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/fetch-content.d.ts.map +1 -0
- package/dist/{fetch-content.js → lib/fetch-content.js} +3 -2
- package/dist/lib/fetch-content.js.map +1 -0
- package/dist/lib/fetch-stream.d.ts.map +1 -0
- package/dist/{fetch-stream.js → lib/fetch-stream.js} +3 -5
- package/dist/lib/fetch-stream.js.map +1 -0
- package/dist/lib/fetch.d.ts.map +1 -0
- package/dist/{fetch.js → lib/fetch.js} +100 -145
- package/dist/lib/fetch.js.map +1 -0
- package/dist/lib/host-normalization.d.ts.map +1 -0
- package/dist/{host-normalization.js → lib/host-normalization.js} +9 -9
- package/dist/lib/host-normalization.js.map +1 -0
- package/dist/lib/ip-blocklist.d.ts.map +1 -0
- package/dist/{ip-blocklist.js → lib/ip-blocklist.js} +11 -8
- package/dist/lib/ip-blocklist.js.map +1 -0
- package/dist/lib/json.d.ts.map +1 -0
- package/dist/{json.js → lib/json.js} +2 -5
- package/dist/lib/json.js.map +1 -0
- package/dist/lib/language-detection.d.ts.map +1 -0
- package/dist/{language-detection.js → lib/language-detection.js} +1 -7
- package/dist/lib/language-detection.js.map +1 -0
- package/dist/{markdown-cleanup.d.ts → lib/markdown-cleanup.d.ts} +1 -1
- package/dist/lib/markdown-cleanup.d.ts.map +1 -0
- package/dist/{markdown-cleanup.js → lib/markdown-cleanup.js} +2 -5
- package/dist/lib/markdown-cleanup.js.map +1 -0
- package/dist/lib/mcp-lifecycle.d.ts +5 -0
- package/dist/lib/mcp-lifecycle.d.ts.map +1 -0
- package/dist/lib/mcp-lifecycle.js +51 -0
- package/dist/lib/mcp-lifecycle.js.map +1 -0
- package/dist/lib/mcp-validator.d.ts.map +1 -0
- package/dist/{mcp-validator.js → lib/mcp-validator.js} +6 -12
- package/dist/lib/mcp-validator.js.map +1 -0
- package/dist/{mcp.d.ts → lib/mcp.d.ts} +1 -1
- package/dist/lib/mcp.d.ts.map +1 -0
- package/dist/{mcp.js → lib/mcp.js} +64 -37
- package/dist/lib/mcp.js.map +1 -0
- package/dist/lib/observability.d.ts.map +1 -0
- package/dist/{observability.js → lib/observability.js} +2 -1
- package/dist/lib/observability.js.map +1 -0
- package/dist/lib/server-tuning.d.ts.map +1 -0
- package/dist/{server-tuning.js → lib/server-tuning.js} +3 -2
- package/dist/lib/server-tuning.js.map +1 -0
- package/dist/{session.d.ts → lib/session.d.ts} +5 -1
- package/dist/lib/session.d.ts.map +1 -0
- package/dist/{session.js → lib/session.js} +46 -36
- package/dist/lib/session.js.map +1 -0
- package/dist/lib/timer-utils.d.ts +13 -0
- package/dist/lib/timer-utils.d.ts.map +1 -0
- package/dist/lib/timer-utils.js +44 -0
- package/dist/lib/timer-utils.js.map +1 -0
- package/dist/lib/tool-errors.d.ts.map +1 -0
- package/dist/{tool-errors.js → lib/tool-errors.js} +8 -5
- package/dist/lib/tool-errors.js.map +1 -0
- package/dist/{tool-pipeline.d.ts → lib/tool-pipeline.d.ts} +1 -2
- package/dist/lib/tool-pipeline.d.ts.map +1 -0
- package/dist/{tool-pipeline.js → lib/tool-pipeline.js} +11 -27
- package/dist/lib/tool-pipeline.js.map +1 -0
- package/dist/{tool-progress.d.ts → lib/tool-progress.d.ts} +1 -2
- package/dist/lib/tool-progress.d.ts.map +1 -0
- package/dist/{tool-progress.js → lib/tool-progress.js} +27 -21
- package/dist/lib/tool-progress.js.map +1 -0
- package/dist/lib/type-guards.d.ts.map +1 -0
- package/dist/{type-guards.js → lib/type-guards.js} +3 -4
- package/dist/lib/type-guards.js.map +1 -0
- package/dist/{prompts.d.ts → prompts/index.d.ts} +1 -1
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/{prompts.js → prompts/index.js} +13 -13
- package/dist/prompts/index.js.map +1 -0
- package/dist/{resources.d.ts → resources/index.d.ts} +1 -1
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/{resources.js → resources/index.js} +30 -34
- package/dist/resources/index.js.map +1 -0
- package/dist/resources/instructions.d.ts.map +1 -0
- package/dist/resources/instructions.js +43 -0
- package/dist/resources/instructions.js.map +1 -0
- package/dist/schemas/inputs.d.ts +8 -0
- package/dist/schemas/inputs.d.ts.map +1 -0
- package/dist/schemas/inputs.js +25 -0
- package/dist/schemas/inputs.js.map +1 -0
- package/dist/schemas/outputs.d.ts +24 -0
- package/dist/schemas/outputs.d.ts.map +1 -0
- package/dist/schemas/outputs.js +78 -0
- package/dist/schemas/outputs.js.map +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +31 -26
- package/dist/server.js.map +1 -1
- package/dist/tasks/execution.d.ts.map +1 -1
- package/dist/tasks/execution.js +105 -63
- package/dist/tasks/execution.js.map +1 -1
- package/dist/tasks/manager.d.ts +10 -0
- package/dist/tasks/manager.d.ts.map +1 -1
- package/dist/tasks/manager.js +62 -54
- package/dist/tasks/manager.js.map +1 -1
- package/dist/tasks/owner.d.ts +4 -4
- package/dist/tasks/owner.d.ts.map +1 -1
- package/dist/tasks/owner.js +9 -15
- package/dist/tasks/owner.js.map +1 -1
- package/dist/tasks/tool-registry.d.ts +12 -0
- package/dist/tasks/tool-registry.d.ts.map +1 -0
- package/dist/tasks/tool-registry.js +14 -0
- package/dist/tasks/tool-registry.js.map +1 -0
- package/dist/tools/fetch-url.d.ts +29 -0
- package/dist/tools/fetch-url.d.ts.map +1 -0
- package/dist/{tools.js → tools/fetch-url.js} +120 -167
- package/dist/tools/fetch-url.js.map +1 -0
- package/dist/tools/index.d.ts +3 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +5 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/transform/transform.d.ts.map +1 -1
- package/dist/transform/transform.js +164 -176
- package/dist/transform/transform.js.map +1 -1
- package/dist/transform/worker-pool.d.ts.map +1 -1
- package/dist/transform/worker-pool.js +9 -11
- package/dist/transform/worker-pool.js.map +1 -1
- package/dist/transform/workers/shared.d.ts +8 -0
- package/dist/transform/workers/shared.d.ts.map +1 -0
- package/dist/transform/workers/shared.js +131 -0
- package/dist/transform/workers/shared.js.map +1 -0
- package/dist/transform/workers/transform-child.js +5 -132
- package/dist/transform/workers/transform-child.js.map +1 -1
- package/dist/transform/workers/transform-worker.js +7 -125
- package/dist/transform/workers/transform-worker.js.map +1 -1
- package/package.json +8 -7
- package/dist/cache.d.ts.map +0 -1
- package/dist/cache.js.map +0 -1
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/crypto.d.ts.map +0 -1
- package/dist/crypto.js.map +0 -1
- package/dist/dom-noise-removal.d.ts.map +0 -1
- package/dist/dom-noise-removal.js.map +0 -1
- package/dist/download.d.ts.map +0 -1
- package/dist/download.js.map +0 -1
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js.map +0 -1
- package/dist/examples/mcp-fetch-url-client.js +0 -329
- package/dist/examples/mcp-fetch-url-client.js.map +0 -1
- package/dist/fetch-content.d.ts.map +0 -1
- package/dist/fetch-content.js.map +0 -1
- package/dist/fetch-stream.d.ts.map +0 -1
- package/dist/fetch-stream.js.map +0 -1
- package/dist/fetch.d.ts.map +0 -1
- package/dist/fetch.js.map +0 -1
- package/dist/host-normalization.d.ts.map +0 -1
- package/dist/host-normalization.js.map +0 -1
- package/dist/instructions.d.ts.map +0 -1
- package/dist/instructions.js +0 -108
- package/dist/instructions.js.map +0 -1
- package/dist/ip-blocklist.d.ts.map +0 -1
- package/dist/ip-blocklist.js.map +0 -1
- package/dist/json.d.ts.map +0 -1
- package/dist/json.js.map +0 -1
- package/dist/language-detection.d.ts.map +0 -1
- package/dist/language-detection.js.map +0 -1
- package/dist/markdown-cleanup.d.ts.map +0 -1
- package/dist/markdown-cleanup.js.map +0 -1
- package/dist/mcp-validator.d.ts.map +0 -1
- package/dist/mcp-validator.js.map +0 -1
- package/dist/mcp.d.ts.map +0 -1
- package/dist/mcp.js.map +0 -1
- package/dist/observability.d.ts.map +0 -1
- package/dist/observability.js.map +0 -1
- package/dist/prompts.d.ts.map +0 -1
- package/dist/prompts.js.map +0 -1
- package/dist/resources.d.ts.map +0 -1
- package/dist/resources.js.map +0 -1
- package/dist/server-tuning.d.ts.map +0 -1
- package/dist/server-tuning.js.map +0 -1
- package/dist/session.d.ts.map +0 -1
- package/dist/session.js.map +0 -1
- package/dist/timer-utils.d.ts +0 -6
- package/dist/timer-utils.d.ts.map +0 -1
- package/dist/timer-utils.js +0 -30
- package/dist/timer-utils.js.map +0 -1
- package/dist/tool-errors.d.ts.map +0 -1
- package/dist/tool-errors.js.map +0 -1
- package/dist/tool-pipeline.d.ts.map +0 -1
- package/dist/tool-pipeline.js.map +0 -1
- package/dist/tool-progress.d.ts.map +0 -1
- package/dist/tool-progress.js.map +0 -1
- package/dist/tools.d.ts +0 -54
- package/dist/tools.d.ts.map +0 -1
- package/dist/tools.js.map +0 -1
- package/dist/type-guards.d.ts.map +0 -1
- package/dist/type-guards.js.map +0 -1
- /package/dist/{cache.d.ts → lib/cache.d.ts} +0 -0
- /package/dist/{crypto.d.ts → lib/crypto.d.ts} +0 -0
- /package/dist/{dom-noise-removal.d.ts → lib/dom-noise-removal.d.ts} +0 -0
- /package/dist/{download.d.ts → lib/download.d.ts} +0 -0
- /package/dist/{fetch-content.d.ts → lib/fetch-content.d.ts} +0 -0
- /package/dist/{fetch-stream.d.ts → lib/fetch-stream.d.ts} +0 -0
- /package/dist/{fetch.d.ts → lib/fetch.d.ts} +0 -0
- /package/dist/{host-normalization.d.ts → lib/host-normalization.d.ts} +0 -0
- /package/dist/{ip-blocklist.d.ts → lib/ip-blocklist.d.ts} +0 -0
- /package/dist/{json.d.ts → lib/json.d.ts} +0 -0
- /package/dist/{language-detection.d.ts → lib/language-detection.d.ts} +0 -0
- /package/dist/{mcp-validator.d.ts → lib/mcp-validator.d.ts} +0 -0
- /package/dist/{observability.d.ts → lib/observability.d.ts} +0 -0
- /package/dist/{server-tuning.d.ts → lib/server-tuning.d.ts} +0 -0
- /package/dist/{tool-errors.d.ts → lib/tool-errors.d.ts} +0 -0
- /package/dist/{type-guards.d.ts → lib/type-guards.d.ts} +0 -0
- /package/dist/{instructions.d.ts → resources/instructions.d.ts} +0 -0
package/dist/tasks/execution.js
CHANGED
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
import { ErrorCode, McpError, } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { config } from '../lib/config.js';
|
|
3
|
+
import { getErrorMessage, RESOURCE_NOT_FOUND_ERROR_CODE, } from '../lib/errors.js';
|
|
4
|
+
import { logWarn, runWithRequestContext } from '../lib/observability.js';
|
|
5
|
+
import { isObject } from '../lib/type-guards.js';
|
|
4
6
|
import { taskManager, } from './manager.js';
|
|
5
|
-
import { compact,
|
|
7
|
+
import { compact, tryReadToolStructuredError, } from './owner.js';
|
|
8
|
+
import { getTaskCapableTool, hasTaskCapableTool, } from './tool-registry.js';
|
|
6
9
|
/* -------------------------------------------------------------------------------------------------
|
|
7
10
|
* Abort-controller management for in-flight task executions
|
|
8
11
|
* ------------------------------------------------------------------------------------------------- */
|
|
12
|
+
// Intentionally process-global (not session-scoped): abortAllTaskExecutions() is called
|
|
13
|
+
// during SIGTERM/SIGINT shutdown to cancel every in-flight task across all sessions.
|
|
14
|
+
// Keep this process-global so shutdown can cancel all in-flight tasks across sessions.
|
|
15
|
+
// Per-session isolation would require a different cancellation fan-out strategy.
|
|
9
16
|
const taskAbortControllers = new Map();
|
|
10
17
|
function attachAbortController(taskId) {
|
|
11
18
|
const existing = taskAbortControllers.get(taskId);
|
|
12
19
|
if (existing) {
|
|
20
|
+
// Abort the previous controller before replacing it — avoids stranding
|
|
21
|
+
// a running fetch that can no longer be cancelled via abortTaskExecution().
|
|
22
|
+
existing.abort();
|
|
13
23
|
taskAbortControllers.delete(taskId);
|
|
14
24
|
}
|
|
15
25
|
const controller = new AbortController();
|
|
@@ -48,6 +58,11 @@ export function toTaskSummary(task) {
|
|
|
48
58
|
lastUpdatedAt: task.lastUpdatedAt,
|
|
49
59
|
ttl: task.ttl,
|
|
50
60
|
pollInterval: task.pollInterval,
|
|
61
|
+
_meta: {
|
|
62
|
+
'io.modelcontextprotocol/related-task': {
|
|
63
|
+
taskId: task.taskId,
|
|
64
|
+
},
|
|
65
|
+
},
|
|
51
66
|
};
|
|
52
67
|
}
|
|
53
68
|
export function withRelatedTaskMeta(result, taskId) {
|
|
@@ -63,39 +78,55 @@ export function withRelatedTaskMeta(result, taskId) {
|
|
|
63
78
|
};
|
|
64
79
|
}
|
|
65
80
|
export function emitTaskStatusNotification(server, task) {
|
|
81
|
+
if (!config.tasks.emitStatusNotifications)
|
|
82
|
+
return;
|
|
66
83
|
if (!server.isConnected())
|
|
67
84
|
return;
|
|
85
|
+
// NOTE: 'notifications/tasks/status' is not part of the MCP v2025-11-25 specification.
|
|
86
|
+
// This relies on the experimental task infrastructure in the SDK and may change.
|
|
68
87
|
void server.server
|
|
69
88
|
.notification({
|
|
70
89
|
method: 'notifications/tasks/status',
|
|
71
|
-
params:
|
|
90
|
+
params: buildTaskStatusNotificationParams(task),
|
|
72
91
|
})
|
|
73
92
|
.catch((error) => {
|
|
74
93
|
logWarn('Failed to send task status notification', {
|
|
75
94
|
taskId: task.taskId,
|
|
76
95
|
status: task.status,
|
|
77
|
-
error,
|
|
96
|
+
error: getErrorMessage(error),
|
|
78
97
|
});
|
|
79
98
|
});
|
|
80
99
|
}
|
|
100
|
+
function buildTaskStatusNotificationParams(task) {
|
|
101
|
+
return {
|
|
102
|
+
taskId: task.taskId,
|
|
103
|
+
status: task.status,
|
|
104
|
+
...(task.statusMessage ? { statusMessage: task.statusMessage } : {}),
|
|
105
|
+
createdAt: task.createdAt,
|
|
106
|
+
lastUpdatedAt: task.lastUpdatedAt,
|
|
107
|
+
ttl: task.ttl,
|
|
108
|
+
pollInterval: task.pollInterval,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
81
111
|
/* -------------------------------------------------------------------------------------------------
|
|
82
112
|
* Validation helpers
|
|
83
113
|
* ------------------------------------------------------------------------------------------------- */
|
|
84
|
-
function requireFetchUrlArgs(args) {
|
|
85
|
-
const parsed = fetchUrlInputSchema.safeParse(args);
|
|
86
|
-
if (!parsed.success) {
|
|
87
|
-
throw new McpError(ErrorCode.InvalidParams, 'Invalid arguments for fetch-url');
|
|
88
|
-
}
|
|
89
|
-
return parsed.data;
|
|
90
|
-
}
|
|
91
114
|
export function throwTaskNotFound() {
|
|
92
|
-
throw new McpError(
|
|
115
|
+
throw new McpError(RESOURCE_NOT_FOUND_ERROR_CODE, 'Task not found');
|
|
93
116
|
}
|
|
94
|
-
function
|
|
95
|
-
|
|
96
|
-
|
|
117
|
+
function resolveTaskCapableTool(name) {
|
|
118
|
+
const descriptor = getTaskCapableTool(name);
|
|
119
|
+
if (descriptor)
|
|
120
|
+
return descriptor;
|
|
97
121
|
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: '${name}'`);
|
|
98
122
|
}
|
|
123
|
+
// Validates that the tool name is recognized before we attempt to execute it.
|
|
124
|
+
// This ensures that an unknown tool produces a MethodNotFound error, rather than potentially executing and failing with an internal error if the tool handler does not properly validate its input.
|
|
125
|
+
function assertKnownTool(name) {
|
|
126
|
+
if (!hasTaskCapableTool(name)) {
|
|
127
|
+
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: '${name}'`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
99
130
|
/* -------------------------------------------------------------------------------------------------
|
|
100
131
|
* Task result builders
|
|
101
132
|
* ------------------------------------------------------------------------------------------------- */
|
|
@@ -135,13 +166,43 @@ function updateWorkingTaskStatus(server, taskId, statusMessage) {
|
|
|
135
166
|
if (updated)
|
|
136
167
|
emitTaskStatusNotification(server, updated);
|
|
137
168
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
169
|
+
function updateTaskAndEmitStatus(server, taskId, update) {
|
|
170
|
+
taskManager.updateTask(taskId, update);
|
|
171
|
+
const task = taskManager.getTask(taskId);
|
|
172
|
+
if (task)
|
|
173
|
+
emitTaskStatusNotification(server, task);
|
|
174
|
+
}
|
|
175
|
+
function buildTaskFailureState(error) {
|
|
176
|
+
const statusMessage = getErrorMessage(error);
|
|
177
|
+
if (error instanceof McpError) {
|
|
178
|
+
return {
|
|
179
|
+
statusMessage,
|
|
180
|
+
error: {
|
|
181
|
+
code: error.code,
|
|
182
|
+
message: statusMessage,
|
|
183
|
+
data: error.data,
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
return {
|
|
188
|
+
statusMessage,
|
|
189
|
+
error: {
|
|
190
|
+
code: ErrorCode.InternalError,
|
|
191
|
+
message: statusMessage,
|
|
192
|
+
},
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
async function runTaskToolExecution(params) {
|
|
196
|
+
const { server, taskId, args, tool, meta, sessionId, sendNotification } = params;
|
|
197
|
+
return runWithRequestContext({
|
|
198
|
+
requestId: taskId,
|
|
199
|
+
operationId: taskId,
|
|
200
|
+
...(sessionId ? { sessionId } : {}),
|
|
201
|
+
}, async () => {
|
|
141
202
|
const controller = attachAbortController(taskId);
|
|
142
203
|
try {
|
|
143
204
|
const relatedMeta = buildRelatedTaskMeta(taskId, meta);
|
|
144
|
-
const result = await
|
|
205
|
+
const result = await tool.execute(args, {
|
|
145
206
|
signal: controller.signal,
|
|
146
207
|
requestId: taskId,
|
|
147
208
|
_meta: relatedMeta,
|
|
@@ -150,40 +211,22 @@ async function runFetchTaskExecution(params) {
|
|
|
150
211
|
updateWorkingTaskStatus(server, taskId, message);
|
|
151
212
|
},
|
|
152
213
|
});
|
|
153
|
-
const isToolError =
|
|
154
|
-
|
|
155
|
-
result['isError'];
|
|
156
|
-
taskManager.updateTask(taskId, {
|
|
214
|
+
const isToolError = isObject(result) && 'isError' in result && result.isError === true;
|
|
215
|
+
updateTaskAndEmitStatus(server, taskId, {
|
|
157
216
|
status: isToolError ? 'failed' : 'completed',
|
|
158
217
|
statusMessage: isToolError
|
|
159
218
|
? (tryReadToolStructuredError(result) ?? 'Tool execution failed')
|
|
160
219
|
: 'Task completed successfully.',
|
|
161
220
|
result,
|
|
162
221
|
});
|
|
163
|
-
const task = taskManager.getTask(taskId);
|
|
164
|
-
if (task)
|
|
165
|
-
emitTaskStatusNotification(server, task);
|
|
166
222
|
}
|
|
167
223
|
catch (error) {
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
? {
|
|
171
|
-
code: error.code,
|
|
172
|
-
message: errorMessage,
|
|
173
|
-
data: error.data,
|
|
174
|
-
}
|
|
175
|
-
: {
|
|
176
|
-
code: ErrorCode.InternalError,
|
|
177
|
-
message: errorMessage,
|
|
178
|
-
};
|
|
179
|
-
taskManager.updateTask(taskId, {
|
|
224
|
+
const failure = buildTaskFailureState(error);
|
|
225
|
+
updateTaskAndEmitStatus(server, taskId, {
|
|
180
226
|
status: 'failed',
|
|
181
|
-
statusMessage:
|
|
182
|
-
error:
|
|
227
|
+
statusMessage: failure.statusMessage,
|
|
228
|
+
error: failure.error,
|
|
183
229
|
});
|
|
184
|
-
const task = taskManager.getTask(taskId);
|
|
185
|
-
if (task)
|
|
186
|
-
emitTaskStatusNotification(server, task);
|
|
187
230
|
}
|
|
188
231
|
finally {
|
|
189
232
|
clearTaskExecution(taskId);
|
|
@@ -191,42 +234,41 @@ async function runFetchTaskExecution(params) {
|
|
|
191
234
|
});
|
|
192
235
|
}
|
|
193
236
|
function handleTaskToolCall(server, params, context) {
|
|
194
|
-
|
|
195
|
-
const validArgs =
|
|
237
|
+
const tool = resolveTaskCapableTool(params.name);
|
|
238
|
+
const validArgs = tool.parseArguments(params.arguments);
|
|
196
239
|
const task = taskManager.createTask(params.task?.ttl !== undefined ? { ttl: params.task.ttl } : undefined, 'Task started', context.ownerKey);
|
|
197
|
-
void
|
|
240
|
+
void runTaskToolExecution({
|
|
198
241
|
server,
|
|
199
242
|
taskId: task.taskId,
|
|
200
243
|
args: validArgs,
|
|
244
|
+
tool,
|
|
201
245
|
...compact({
|
|
202
246
|
meta: params._meta,
|
|
247
|
+
sessionId: context.sessionId,
|
|
203
248
|
sendNotification: context.sendNotification,
|
|
204
249
|
}),
|
|
205
250
|
});
|
|
206
251
|
return buildCreateTaskResult(toTaskSummary(task));
|
|
207
252
|
}
|
|
208
253
|
async function handleDirectToolCall(params, context) {
|
|
209
|
-
const
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
...(params._meta ? { _meta: params._meta } : {}),
|
|
219
|
-
};
|
|
220
|
-
return fetchUrlToolHandler(args, extra);
|
|
254
|
+
const tool = resolveTaskCapableTool(params.name);
|
|
255
|
+
const args = tool.parseArguments(params.arguments);
|
|
256
|
+
const extra = compact({
|
|
257
|
+
signal: context.signal,
|
|
258
|
+
requestId: context.requestId,
|
|
259
|
+
sendNotification: context.sendNotification,
|
|
260
|
+
_meta: params._meta,
|
|
261
|
+
});
|
|
262
|
+
return tool.execute(args, extra);
|
|
221
263
|
}
|
|
222
264
|
export async function handleToolCallRequest(server, request, context) {
|
|
223
265
|
const { params } = request;
|
|
266
|
+
// Validate the tool name first so an unknown tool always produces MethodNotFound,
|
|
267
|
+
// regardless of whether a task:{} param was supplied (H-4).
|
|
268
|
+
assertKnownTool(params.name);
|
|
224
269
|
if (params.task) {
|
|
225
270
|
return handleTaskToolCall(server, params, context);
|
|
226
271
|
}
|
|
227
|
-
|
|
228
|
-
return handleDirectToolCall(params, context);
|
|
229
|
-
}
|
|
230
|
-
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${params.name}`);
|
|
272
|
+
return handleDirectToolCall(params, context);
|
|
231
273
|
}
|
|
232
274
|
//# sourceMappingURL=execution.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execution.js","sourceRoot":"","sources":["../../src/tasks/execution.ts"],"names":[],"mappings":"AACA,OAAO,EACL,SAAS,EACT,QAAQ,GAET,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"execution.js","sourceRoot":"","sources":["../../src/tasks/execution.ts"],"names":[],"mappings":"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"}
|
package/dist/tasks/manager.d.ts
CHANGED
|
@@ -28,6 +28,11 @@ export interface CreateTaskResult {
|
|
|
28
28
|
lastUpdatedAt: string;
|
|
29
29
|
ttl: number;
|
|
30
30
|
pollInterval: number;
|
|
31
|
+
_meta?: {
|
|
32
|
+
'io.modelcontextprotocol/related-task': {
|
|
33
|
+
taskId: string;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
31
36
|
};
|
|
32
37
|
_meta?: Record<string, unknown>;
|
|
33
38
|
}
|
|
@@ -39,11 +44,13 @@ declare class TaskManager {
|
|
|
39
44
|
private startCleanupLoop;
|
|
40
45
|
private removeExpiredTasks;
|
|
41
46
|
private removeTask;
|
|
47
|
+
private releaseOwnerCount;
|
|
42
48
|
private countTasksForOwner;
|
|
43
49
|
private incrementOwnerCount;
|
|
44
50
|
private decrementOwnerCount;
|
|
45
51
|
private assertTaskCapacity;
|
|
46
52
|
createTask(options?: CreateTaskOptions, statusMessage?: string, ownerKey?: string): TaskState;
|
|
53
|
+
private lookupActiveTask;
|
|
47
54
|
getTask(taskId: string, ownerKey?: string): TaskState | undefined;
|
|
48
55
|
updateTask(taskId: string, updates: Partial<Omit<TaskState, 'taskId' | 'createdAt'>>): void;
|
|
49
56
|
cancelTask(taskId: string, ownerKey?: string): TaskState | undefined;
|
|
@@ -57,12 +64,15 @@ declare class TaskManager {
|
|
|
57
64
|
tasks: TaskState[];
|
|
58
65
|
nextCursor?: string;
|
|
59
66
|
};
|
|
67
|
+
private addWaiter;
|
|
68
|
+
private removeWaiter;
|
|
60
69
|
waitForTerminalTask(taskId: string, ownerKey: string, signal?: AbortSignal): Promise<TaskState | undefined>;
|
|
61
70
|
private notifyWaiters;
|
|
62
71
|
private isExpired;
|
|
63
72
|
shrinkTtlAfterDelivery(taskId: string): void;
|
|
64
73
|
private encodeCursor;
|
|
65
74
|
private decodeCursor;
|
|
75
|
+
private resolveNextCursor;
|
|
66
76
|
}
|
|
67
77
|
export declare const taskManager: TaskManager;
|
|
68
78
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/tasks/manager.ts"],"names":[],"mappings":"
|
|
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
|
@@ -3,8 +3,9 @@ import { AsyncLocalStorage } from 'node:async_hooks';
|
|
|
3
3
|
import { Buffer } from 'node:buffer';
|
|
4
4
|
import { randomUUID } from 'node:crypto';
|
|
5
5
|
import { setInterval } from 'node:timers';
|
|
6
|
-
import { config } from '../config.js';
|
|
7
|
-
import {
|
|
6
|
+
import { config } from '../lib/config.js';
|
|
7
|
+
import { toError } from '../lib/errors.js';
|
|
8
|
+
import { createUnrefTimeout, } from '../lib/timer-utils.js';
|
|
8
9
|
const DEFAULT_TTL_MS = 60_000;
|
|
9
10
|
const MIN_TTL_MS = 1_000;
|
|
10
11
|
const MAX_TTL_MS = 86_400_000;
|
|
@@ -20,7 +21,7 @@ function isTerminalStatus(status) {
|
|
|
20
21
|
function normalizeTaskTtl(ttl) {
|
|
21
22
|
if (!Number.isFinite(ttl))
|
|
22
23
|
return DEFAULT_TTL_MS;
|
|
23
|
-
const rounded = Math.trunc(ttl
|
|
24
|
+
const rounded = Math.trunc(Number(ttl));
|
|
24
25
|
if (rounded < MIN_TTL_MS)
|
|
25
26
|
return MIN_TTL_MS;
|
|
26
27
|
if (rounded > MAX_TTL_MS)
|
|
@@ -42,24 +43,29 @@ class TaskManager {
|
|
|
42
43
|
}
|
|
43
44
|
removeExpiredTasks() {
|
|
44
45
|
const now = Date.now();
|
|
45
|
-
const expired = [];
|
|
46
46
|
for (const [id, task] of this.tasks) {
|
|
47
47
|
if (this.isExpired(task, now)) {
|
|
48
|
-
|
|
48
|
+
this.removeTask(id);
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
-
for (const id of expired) {
|
|
52
|
-
this.removeTask(id);
|
|
53
|
-
}
|
|
54
51
|
}
|
|
55
52
|
removeTask(taskId) {
|
|
56
53
|
const task = this.tasks.get(taskId);
|
|
57
54
|
if (!task)
|
|
58
55
|
return false;
|
|
59
56
|
this.tasks.delete(taskId);
|
|
60
|
-
this.
|
|
57
|
+
this.releaseOwnerCount(task);
|
|
61
58
|
return true;
|
|
62
59
|
}
|
|
60
|
+
releaseOwnerCount(task) {
|
|
61
|
+
const internal = task;
|
|
62
|
+
if (internal._ownerCounted === false)
|
|
63
|
+
return;
|
|
64
|
+
if ('_ownerCounted' in internal) {
|
|
65
|
+
internal._ownerCounted = false;
|
|
66
|
+
}
|
|
67
|
+
this.decrementOwnerCount(task.ownerKey);
|
|
68
|
+
}
|
|
63
69
|
countTasksForOwner(ownerKey) {
|
|
64
70
|
return this.ownerCounts.get(ownerKey) ?? 0;
|
|
65
71
|
}
|
|
@@ -99,12 +105,13 @@ class TaskManager {
|
|
|
99
105
|
ttl: normalizeTaskTtl(options?.ttl),
|
|
100
106
|
pollInterval: DEFAULT_POLL_INTERVAL_MS,
|
|
101
107
|
_createdAtMs: now.getTime(),
|
|
108
|
+
_ownerCounted: true,
|
|
102
109
|
};
|
|
103
110
|
this.tasks.set(task.taskId, task);
|
|
104
111
|
this.incrementOwnerCount(ownerKey);
|
|
105
112
|
return task;
|
|
106
113
|
}
|
|
107
|
-
|
|
114
|
+
lookupActiveTask(taskId, ownerKey) {
|
|
108
115
|
const task = this.tasks.get(taskId);
|
|
109
116
|
if (!task)
|
|
110
117
|
return undefined;
|
|
@@ -116,16 +123,17 @@ class TaskManager {
|
|
|
116
123
|
}
|
|
117
124
|
return task;
|
|
118
125
|
}
|
|
126
|
+
getTask(taskId, ownerKey) {
|
|
127
|
+
return this.lookupActiveTask(taskId, ownerKey);
|
|
128
|
+
}
|
|
119
129
|
updateTask(taskId, updates) {
|
|
120
130
|
const task = this.tasks.get(taskId);
|
|
121
131
|
if (!task)
|
|
122
132
|
return;
|
|
123
133
|
if (isTerminalStatus(task.status))
|
|
124
134
|
return;
|
|
125
|
-
Object.assign(task,
|
|
126
|
-
|
|
127
|
-
lastUpdatedAt: new Date().toISOString(),
|
|
128
|
-
});
|
|
135
|
+
Object.assign(task, updates);
|
|
136
|
+
task.lastUpdatedAt = new Date().toISOString();
|
|
129
137
|
this.notifyWaiters(task);
|
|
130
138
|
}
|
|
131
139
|
cancelTask(taskId, ownerKey) {
|
|
@@ -139,6 +147,7 @@ class TaskManager {
|
|
|
139
147
|
status: 'cancelled',
|
|
140
148
|
statusMessage: 'The task was cancelled by request.',
|
|
141
149
|
});
|
|
150
|
+
this.releaseOwnerCount(task);
|
|
142
151
|
return this.tasks.get(taskId);
|
|
143
152
|
}
|
|
144
153
|
cancelTasksByOwner(ownerKey, statusMessage = 'The task was cancelled because its owner is no longer active.') {
|
|
@@ -154,6 +163,7 @@ class TaskManager {
|
|
|
154
163
|
status: 'cancelled',
|
|
155
164
|
statusMessage,
|
|
156
165
|
});
|
|
166
|
+
this.releaseOwnerCount(task);
|
|
157
167
|
cancelled.push(task);
|
|
158
168
|
}
|
|
159
169
|
return cancelled;
|
|
@@ -163,12 +173,11 @@ class TaskManager {
|
|
|
163
173
|
let collecting = anchorTaskId === null;
|
|
164
174
|
let anchorFound = anchorTaskId === null;
|
|
165
175
|
const now = Date.now();
|
|
166
|
-
const expired = [];
|
|
167
176
|
for (const task of this.tasks.values()) {
|
|
168
177
|
if (task.ownerKey !== ownerKey)
|
|
169
178
|
continue;
|
|
170
179
|
if (this.isExpired(task, now)) {
|
|
171
|
-
|
|
180
|
+
this.removeTask(task.taskId);
|
|
172
181
|
continue;
|
|
173
182
|
}
|
|
174
183
|
if (!collecting) {
|
|
@@ -182,9 +191,6 @@ class TaskManager {
|
|
|
182
191
|
if (page.length > pageSize)
|
|
183
192
|
break;
|
|
184
193
|
}
|
|
185
|
-
for (const id of expired) {
|
|
186
|
-
this.removeTask(id);
|
|
187
|
-
}
|
|
188
194
|
// Anchor task expired between pages; return empty list so callers stop
|
|
189
195
|
// pagination cleanly. Silently falling back to page 0 risks infinite loops
|
|
190
196
|
// for automated clients that always follow nextCursor.
|
|
@@ -209,36 +215,44 @@ class TaskManager {
|
|
|
209
215
|
if (hasMore) {
|
|
210
216
|
page.pop();
|
|
211
217
|
}
|
|
212
|
-
const
|
|
213
|
-
const nextCursor = hasMore && lastTask !== undefined
|
|
214
|
-
? this.encodeCursor(lastTask.taskId)
|
|
215
|
-
: undefined;
|
|
218
|
+
const nextCursor = this.resolveNextCursor(page, hasMore);
|
|
216
219
|
return nextCursor ? { tasks: page, nextCursor } : { tasks: page };
|
|
217
220
|
}
|
|
221
|
+
addWaiter(taskId, waiter) {
|
|
222
|
+
let set = this.waiters.get(taskId);
|
|
223
|
+
if (!set) {
|
|
224
|
+
set = new Set();
|
|
225
|
+
this.waiters.set(taskId, set);
|
|
226
|
+
}
|
|
227
|
+
set.add(waiter);
|
|
228
|
+
}
|
|
229
|
+
removeWaiter(taskId, waiter) {
|
|
230
|
+
if (!waiter)
|
|
231
|
+
return;
|
|
232
|
+
const set = this.waiters.get(taskId);
|
|
233
|
+
if (!set)
|
|
234
|
+
return;
|
|
235
|
+
set.delete(waiter);
|
|
236
|
+
if (set.size === 0) {
|
|
237
|
+
this.waiters.delete(taskId);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
218
240
|
async waitForTerminalTask(taskId, ownerKey, signal) {
|
|
219
|
-
const task = this.
|
|
241
|
+
const task = this.lookupActiveTask(taskId, ownerKey);
|
|
220
242
|
if (!task)
|
|
221
243
|
return undefined;
|
|
222
|
-
if (ownerKey && task.ownerKey !== ownerKey)
|
|
223
|
-
return undefined;
|
|
224
|
-
if (this.isExpired(task)) {
|
|
225
|
-
this.removeTask(taskId);
|
|
226
|
-
return undefined;
|
|
227
|
-
}
|
|
228
244
|
if (isTerminalStatus(task.status))
|
|
229
245
|
return task;
|
|
246
|
+
// isExpired() above guarantees task.ttl has not elapsed; compute deadlineMs
|
|
247
|
+
// for the promise-based timeout below.
|
|
230
248
|
const deadlineMs = task._createdAtMs + task.ttl;
|
|
231
|
-
const now = Date.now();
|
|
232
|
-
if (deadlineMs <= now) {
|
|
233
|
-
this.removeTask(taskId);
|
|
234
|
-
return undefined;
|
|
235
|
-
}
|
|
236
249
|
return new Promise((resolve, reject) => {
|
|
250
|
+
// Bind resolve/reject to the AsyncLocalStorage context of the caller, so that any context values (e.g. requestId) are preserved when we later call them from a different tick.
|
|
237
251
|
const resolveInContext = AsyncLocalStorage.bind((value) => {
|
|
238
252
|
resolve(value);
|
|
239
253
|
});
|
|
240
254
|
const rejectInContext = AsyncLocalStorage.bind((error) => {
|
|
241
|
-
reject(
|
|
255
|
+
reject(toError(error));
|
|
242
256
|
});
|
|
243
257
|
let settled = false;
|
|
244
258
|
let waiter = null;
|
|
@@ -252,16 +266,6 @@ class TaskManager {
|
|
|
252
266
|
signal.removeEventListener('abort', onAbort);
|
|
253
267
|
}
|
|
254
268
|
};
|
|
255
|
-
const removeWaiter = () => {
|
|
256
|
-
if (waiter) {
|
|
257
|
-
const set = this.waiters.get(taskId);
|
|
258
|
-
if (set) {
|
|
259
|
-
set.delete(waiter);
|
|
260
|
-
if (set.size === 0)
|
|
261
|
-
this.waiters.delete(taskId);
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
};
|
|
265
269
|
const settleOnce = (fn) => {
|
|
266
270
|
if (settled)
|
|
267
271
|
return;
|
|
@@ -271,7 +275,7 @@ class TaskManager {
|
|
|
271
275
|
const onAbort = () => {
|
|
272
276
|
settleOnce(() => {
|
|
273
277
|
cleanup();
|
|
274
|
-
removeWaiter();
|
|
278
|
+
this.removeWaiter(taskId, waiter);
|
|
275
279
|
rejectInContext(new McpError(ErrorCode.ConnectionClosed, 'Request was cancelled'));
|
|
276
280
|
});
|
|
277
281
|
};
|
|
@@ -289,12 +293,7 @@ class TaskManager {
|
|
|
289
293
|
onAbort();
|
|
290
294
|
return;
|
|
291
295
|
}
|
|
292
|
-
|
|
293
|
-
if (!set) {
|
|
294
|
-
set = new Set();
|
|
295
|
-
this.waiters.set(taskId, set);
|
|
296
|
-
}
|
|
297
|
-
set.add(waiter);
|
|
296
|
+
this.addWaiter(taskId, waiter);
|
|
298
297
|
if (signal) {
|
|
299
298
|
signal.addEventListener('abort', onAbort, { once: true });
|
|
300
299
|
}
|
|
@@ -304,7 +303,7 @@ class TaskManager {
|
|
|
304
303
|
.then(() => {
|
|
305
304
|
settleOnce(() => {
|
|
306
305
|
cleanup();
|
|
307
|
-
removeWaiter();
|
|
306
|
+
this.removeWaiter(taskId, waiter);
|
|
308
307
|
this.removeTask(taskId);
|
|
309
308
|
resolveInContext(undefined);
|
|
310
309
|
});
|
|
@@ -335,9 +334,12 @@ class TaskManager {
|
|
|
335
334
|
const newTtl = elapsed + RESULT_DELIVERY_GRACE_MS;
|
|
336
335
|
if (newTtl < task.ttl) {
|
|
337
336
|
task.ttl = newTtl;
|
|
337
|
+
task.lastUpdatedAt = new Date().toISOString();
|
|
338
338
|
}
|
|
339
339
|
}
|
|
340
340
|
encodeCursor(taskId) {
|
|
341
|
+
// Base64url-encode the taskId to produce a compact opaque cursor string.
|
|
342
|
+
// The taskId is a UUID, which is 36 ASCII chars, so the resulting cursor will be 48 chars (36 * 4/3) plus padding if any.
|
|
341
343
|
return Buffer.from(taskId, 'utf8').toString('base64url');
|
|
342
344
|
}
|
|
343
345
|
decodeCursor(cursor) {
|
|
@@ -354,6 +356,12 @@ class TaskManager {
|
|
|
354
356
|
return null;
|
|
355
357
|
}
|
|
356
358
|
}
|
|
359
|
+
resolveNextCursor(page, hasMore) {
|
|
360
|
+
if (!hasMore)
|
|
361
|
+
return undefined;
|
|
362
|
+
const lastTask = page.at(-1);
|
|
363
|
+
return lastTask ? this.encodeCursor(lastTask.taskId) : undefined;
|
|
364
|
+
}
|
|
357
365
|
}
|
|
358
366
|
function isValidBase64UrlCursor(cursor) {
|
|
359
367
|
if (!cursor)
|