@j0hanz/fetch-url-mcp 1.3.1 → 1.5.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 +3 -3
- package/dist/cli.js +15 -8
- package/dist/http/auth.d.ts +6 -6
- package/dist/http/auth.js +78 -23
- package/dist/http/health.d.ts +1 -2
- package/dist/http/health.js +7 -18
- package/dist/http/helpers.d.ts +3 -11
- package/dist/http/helpers.js +28 -26
- package/dist/http/native.d.ts +0 -1
- package/dist/http/native.js +63 -41
- package/dist/http/rate-limit.d.ts +2 -2
- package/dist/http/rate-limit.js +11 -16
- package/dist/index.d.ts +0 -1
- package/dist/index.js +17 -20
- package/dist/{markdown-cleanup.d.ts → lib/content.d.ts} +4 -2
- package/dist/lib/content.js +1356 -0
- package/dist/lib/core.d.ts +253 -0
- package/dist/lib/core.js +1228 -0
- package/dist/{tool-pipeline.d.ts → lib/fetch-pipeline.d.ts} +1 -3
- package/dist/{tool-pipeline.js → lib/fetch-pipeline.js} +18 -44
- package/dist/{fetch.d.ts → lib/http.d.ts} +7 -9
- package/dist/{fetch.js → lib/http.js} +721 -1004
- package/dist/lib/mcp-tools.d.ts +28 -0
- package/dist/lib/mcp-tools.js +107 -0
- package/dist/{tool-progress.d.ts → lib/progress.d.ts} +0 -2
- package/dist/{tool-progress.js → lib/progress.js} +9 -14
- package/dist/lib/task-handlers.d.ts +5 -0
- package/dist/{mcp.js → lib/task-handlers.js} +95 -31
- package/dist/lib/url.d.ts +70 -0
- package/dist/lib/url.js +686 -0
- package/dist/lib/utils.d.ts +58 -0
- package/dist/lib/utils.js +304 -0
- package/dist/{prompts.d.ts → prompts/index.d.ts} +0 -1
- package/dist/{prompts.js → prompts/index.js} +1 -2
- package/dist/{resources.d.ts → resources/index.d.ts} +0 -1
- package/dist/{resources.js → resources/index.js} +87 -64
- package/dist/{instructions.d.ts → resources/instructions.d.ts} +0 -1
- package/dist/{instructions.js → resources/instructions.js} +5 -3
- package/dist/schemas/inputs.d.ts +7 -0
- package/dist/schemas/inputs.js +24 -0
- package/dist/schemas/outputs.d.ts +23 -0
- package/dist/schemas/outputs.js +77 -0
- package/dist/server.d.ts +0 -1
- package/dist/server.js +26 -25
- package/dist/tasks/execution.d.ts +0 -1
- package/dist/tasks/execution.js +106 -70
- package/dist/tasks/manager.d.ts +11 -3
- package/dist/tasks/manager.js +97 -73
- package/dist/tasks/owner.d.ts +3 -3
- package/dist/tasks/owner.js +2 -2
- package/dist/tasks/tool-registry.d.ts +11 -0
- package/dist/tasks/tool-registry.js +13 -0
- package/dist/tools/fetch-url.d.ts +28 -0
- package/dist/{tools.js → tools/fetch-url.js} +95 -147
- package/dist/tools/index.d.ts +2 -0
- package/dist/tools/index.js +4 -0
- package/dist/transform/html-translators.d.ts +1 -0
- package/dist/transform/html-translators.js +454 -0
- package/dist/transform/metadata.d.ts +4 -0
- package/dist/transform/metadata.js +183 -0
- package/dist/transform/transform.d.ts +0 -1
- package/dist/transform/transform.js +44 -679
- package/dist/transform/types.d.ts +9 -12
- package/dist/transform/types.js +0 -1
- package/dist/transform/worker-pool.d.ts +0 -1
- package/dist/transform/worker-pool.js +7 -16
- package/dist/transform/workers/shared.d.ts +7 -0
- package/dist/transform/workers/shared.js +130 -0
- package/dist/transform/workers/transform-child.d.ts +0 -1
- package/dist/transform/workers/transform-child.js +5 -135
- package/dist/transform/workers/transform-worker.d.ts +0 -1
- package/dist/transform/workers/transform-worker.js +7 -128
- package/package.json +11 -7
- package/dist/cache.d.ts +0 -54
- package/dist/cache.d.ts.map +0 -1
- package/dist/cache.js +0 -261
- package/dist/cache.js.map +0 -1
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/config.d.ts +0 -141
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js +0 -473
- package/dist/config.js.map +0 -1
- package/dist/crypto.d.ts +0 -4
- package/dist/crypto.d.ts.map +0 -1
- package/dist/crypto.js +0 -56
- package/dist/crypto.js.map +0 -1
- package/dist/dom-noise-removal.d.ts +0 -2
- package/dist/dom-noise-removal.d.ts.map +0 -1
- package/dist/dom-noise-removal.js +0 -494
- package/dist/dom-noise-removal.js.map +0 -1
- package/dist/download.d.ts +0 -4
- package/dist/download.d.ts.map +0 -1
- package/dist/download.js +0 -106
- package/dist/download.js.map +0 -1
- package/dist/errors.d.ts +0 -11
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js +0 -65
- 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 +0 -5
- package/dist/fetch-content.d.ts.map +0 -1
- package/dist/fetch-content.js +0 -164
- package/dist/fetch-content.js.map +0 -1
- package/dist/fetch-stream.d.ts +0 -5
- package/dist/fetch-stream.d.ts.map +0 -1
- package/dist/fetch-stream.js +0 -29
- 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 +0 -2
- package/dist/host-normalization.d.ts.map +0 -1
- package/dist/host-normalization.js +0 -91
- package/dist/host-normalization.js.map +0 -1
- package/dist/http/auth.d.ts.map +0 -1
- package/dist/http/auth.js.map +0 -1
- package/dist/http/health.d.ts.map +0 -1
- package/dist/http/health.js.map +0 -1
- package/dist/http/helpers.d.ts.map +0 -1
- package/dist/http/helpers.js.map +0 -1
- package/dist/http/native.d.ts.map +0 -1
- package/dist/http/native.js.map +0 -1
- package/dist/http/rate-limit.d.ts.map +0 -1
- package/dist/http/rate-limit.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/instructions.d.ts.map +0 -1
- package/dist/instructions.js.map +0 -1
- package/dist/ip-blocklist.d.ts +0 -9
- package/dist/ip-blocklist.d.ts.map +0 -1
- package/dist/ip-blocklist.js +0 -79
- package/dist/ip-blocklist.js.map +0 -1
- package/dist/json.d.ts +0 -2
- package/dist/json.d.ts.map +0 -1
- package/dist/json.js +0 -45
- package/dist/json.js.map +0 -1
- package/dist/language-detection.d.ts +0 -3
- package/dist/language-detection.d.ts.map +0 -1
- package/dist/language-detection.js +0 -355
- package/dist/language-detection.js.map +0 -1
- package/dist/markdown-cleanup.d.ts.map +0 -1
- package/dist/markdown-cleanup.js +0 -534
- package/dist/markdown-cleanup.js.map +0 -1
- package/dist/mcp-validator.d.ts +0 -17
- package/dist/mcp-validator.d.ts.map +0 -1
- package/dist/mcp-validator.js +0 -45
- package/dist/mcp-validator.js.map +0 -1
- package/dist/mcp.d.ts +0 -4
- package/dist/mcp.d.ts.map +0 -1
- package/dist/mcp.js.map +0 -1
- package/dist/observability.d.ts +0 -23
- package/dist/observability.d.ts.map +0 -1
- package/dist/observability.js +0 -238
- 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 +0 -15
- package/dist/server-tuning.d.ts.map +0 -1
- package/dist/server-tuning.js +0 -49
- package/dist/server-tuning.js.map +0 -1
- package/dist/server.d.ts.map +0 -1
- package/dist/server.js.map +0 -1
- package/dist/session.d.ts +0 -42
- package/dist/session.d.ts.map +0 -1
- package/dist/session.js +0 -255
- package/dist/session.js.map +0 -1
- package/dist/tasks/execution.d.ts.map +0 -1
- package/dist/tasks/execution.js.map +0 -1
- package/dist/tasks/manager.d.ts.map +0 -1
- package/dist/tasks/manager.js.map +0 -1
- package/dist/tasks/owner.d.ts.map +0 -1
- package/dist/tasks/owner.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 -27
- package/dist/timer-utils.js.map +0 -1
- package/dist/tool-errors.d.ts +0 -12
- package/dist/tool-errors.d.ts.map +0 -1
- package/dist/tool-errors.js +0 -55
- 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/transform/transform.d.ts.map +0 -1
- package/dist/transform/transform.js.map +0 -1
- package/dist/transform/types.d.ts.map +0 -1
- package/dist/transform/types.js.map +0 -1
- package/dist/transform/worker-pool.d.ts.map +0 -1
- package/dist/transform/worker-pool.js.map +0 -1
- package/dist/transform/workers/transform-child.d.ts.map +0 -1
- package/dist/transform/workers/transform-child.js.map +0 -1
- package/dist/transform/workers/transform-worker.d.ts.map +0 -1
- package/dist/transform/workers/transform-worker.js.map +0 -1
- package/dist/type-guards.d.ts +0 -16
- package/dist/type-guards.d.ts.map +0 -1
- package/dist/type-guards.js +0 -13
- package/dist/type-guards.js.map +0 -1
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const fetchUrlOutputSchema: z.ZodObject<{
|
|
3
|
+
url: z.ZodString;
|
|
4
|
+
inputUrl: z.ZodOptional<z.ZodString>;
|
|
5
|
+
resolvedUrl: z.ZodOptional<z.ZodString>;
|
|
6
|
+
finalUrl: z.ZodOptional<z.ZodString>;
|
|
7
|
+
cacheResourceUri: z.ZodOptional<z.ZodString>;
|
|
8
|
+
title: z.ZodOptional<z.ZodString>;
|
|
9
|
+
metadata: z.ZodOptional<z.ZodObject<{
|
|
10
|
+
title: z.ZodOptional<z.ZodString>;
|
|
11
|
+
description: z.ZodOptional<z.ZodString>;
|
|
12
|
+
author: z.ZodOptional<z.ZodString>;
|
|
13
|
+
image: z.ZodOptional<z.ZodString>;
|
|
14
|
+
favicon: z.ZodOptional<z.ZodString>;
|
|
15
|
+
publishedAt: z.ZodOptional<z.ZodString>;
|
|
16
|
+
modifiedAt: z.ZodOptional<z.ZodString>;
|
|
17
|
+
}, z.core.$strict>>;
|
|
18
|
+
markdown: z.ZodOptional<z.ZodString>;
|
|
19
|
+
fromCache: z.ZodOptional<z.ZodBoolean>;
|
|
20
|
+
fetchedAt: z.ZodOptional<z.ZodString>;
|
|
21
|
+
contentSize: z.ZodOptional<z.ZodNumber>;
|
|
22
|
+
truncated: z.ZodOptional<z.ZodBoolean>;
|
|
23
|
+
}, z.core.$strict>;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { config } from '../lib/core.js';
|
|
3
|
+
export const fetchUrlOutputSchema = z.strictObject({
|
|
4
|
+
url: z
|
|
5
|
+
.string()
|
|
6
|
+
.min(1)
|
|
7
|
+
.max(config.constants.maxUrlLength)
|
|
8
|
+
.describe('Fetched URL.'),
|
|
9
|
+
inputUrl: z
|
|
10
|
+
.string()
|
|
11
|
+
.max(config.constants.maxUrlLength)
|
|
12
|
+
.optional()
|
|
13
|
+
.describe('Original requested URL.'),
|
|
14
|
+
resolvedUrl: z
|
|
15
|
+
.string()
|
|
16
|
+
.max(config.constants.maxUrlLength)
|
|
17
|
+
.optional()
|
|
18
|
+
.describe('Final URL after raw-content transformations.'),
|
|
19
|
+
finalUrl: z
|
|
20
|
+
.string()
|
|
21
|
+
.max(config.constants.maxUrlLength)
|
|
22
|
+
.optional()
|
|
23
|
+
.describe('Final URL after HTTP redirects.'),
|
|
24
|
+
cacheResourceUri: z
|
|
25
|
+
.string()
|
|
26
|
+
.max(config.constants.maxUrlLength)
|
|
27
|
+
.optional()
|
|
28
|
+
.describe('URI for resources/read to get full markdown.'),
|
|
29
|
+
title: z.string().max(512).optional().describe('Page title.'),
|
|
30
|
+
metadata: z
|
|
31
|
+
.strictObject({
|
|
32
|
+
title: z.string().max(512).optional().describe('Detected page title.'),
|
|
33
|
+
description: z
|
|
34
|
+
.string()
|
|
35
|
+
.max(2048)
|
|
36
|
+
.optional()
|
|
37
|
+
.describe('Detected page description.'),
|
|
38
|
+
author: z.string().max(512).optional().describe('Detected page author.'),
|
|
39
|
+
image: z
|
|
40
|
+
.string()
|
|
41
|
+
.max(config.constants.maxUrlLength)
|
|
42
|
+
.optional()
|
|
43
|
+
.describe('Detected page preview image URL.'),
|
|
44
|
+
favicon: z
|
|
45
|
+
.string()
|
|
46
|
+
.max(config.constants.maxUrlLength)
|
|
47
|
+
.optional()
|
|
48
|
+
.describe('Detected page favicon URL.'),
|
|
49
|
+
publishedAt: z
|
|
50
|
+
.string()
|
|
51
|
+
.max(64)
|
|
52
|
+
.optional()
|
|
53
|
+
.describe('Detected publication date.'),
|
|
54
|
+
modifiedAt: z
|
|
55
|
+
.string()
|
|
56
|
+
.max(64)
|
|
57
|
+
.optional()
|
|
58
|
+
.describe('Detected last modified date.'),
|
|
59
|
+
})
|
|
60
|
+
.optional()
|
|
61
|
+
.describe('Extracted page metadata.'),
|
|
62
|
+
markdown: (config.constants.maxInlineContentChars > 0
|
|
63
|
+
? z.string().max(config.constants.maxInlineContentChars)
|
|
64
|
+
: z.string())
|
|
65
|
+
.optional()
|
|
66
|
+
.describe('Extracted Markdown. May be truncated (check truncated field).'),
|
|
67
|
+
fromCache: z.boolean().optional().describe('True if served from cache.'),
|
|
68
|
+
fetchedAt: z.string().max(64).optional().describe('ISO timestamp of fetch.'),
|
|
69
|
+
contentSize: z
|
|
70
|
+
.number()
|
|
71
|
+
.int()
|
|
72
|
+
.min(0)
|
|
73
|
+
.max(config.constants.maxHtmlSize * 4)
|
|
74
|
+
.optional()
|
|
75
|
+
.describe('Full markdown size before truncation.'),
|
|
76
|
+
truncated: z.boolean().optional().describe('True if markdown was truncated.'),
|
|
77
|
+
});
|
package/dist/server.d.ts
CHANGED
|
@@ -2,4 +2,3 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
|
2
2
|
export declare function createMcpServer(): Promise<McpServer>;
|
|
3
3
|
export declare function createMcpServerForHttpSession(): Promise<McpServer>;
|
|
4
4
|
export declare function startStdioServer(): Promise<void>;
|
|
5
|
-
//# sourceMappingURL=server.d.ts.map
|
package/dist/server.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
-
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
1
|
import * as fs from 'node:fs/promises';
|
|
4
2
|
import process from 'node:process';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { logError, logInfo, setLogLevel, setMcpServer
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
3
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
4
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
5
|
+
import { SetLevelRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
6
|
+
import { config } from './lib/core.js';
|
|
7
|
+
import { logError, logInfo, setLogLevel, setMcpServer } from './lib/core.js';
|
|
8
|
+
import { abortAllTaskExecutions, registerTaskHandlers, } from './lib/mcp-tools.js';
|
|
9
|
+
import { toError } from './lib/utils.js';
|
|
10
|
+
import { registerGetHelpPrompt } from './prompts/index.js';
|
|
11
|
+
import { registerCacheResourceTemplate, registerInstructionResource, } from './resources/index.js';
|
|
12
|
+
import { buildServerInstructions } from './resources/instructions.js';
|
|
13
|
+
import { registerAllTools } from './tools/index.js';
|
|
13
14
|
import { shutdownTransformWorkerPool } from './transform/transform.js';
|
|
14
15
|
async function getLocalIconInfo() {
|
|
15
16
|
const name = 'logo.svg';
|
|
@@ -64,6 +65,10 @@ function createServerInfo(icons) {
|
|
|
64
65
|
export async function createMcpServer() {
|
|
65
66
|
return createMcpServerWithOptions({ registerObservabilityServer: true });
|
|
66
67
|
}
|
|
68
|
+
const SHUTDOWN_SIGNALS = ['SIGINT', 'SIGTERM'];
|
|
69
|
+
function shouldRegisterObservabilityServer(options) {
|
|
70
|
+
return options?.registerObservabilityServer ?? true;
|
|
71
|
+
}
|
|
67
72
|
async function createMcpServerWithOptions(options) {
|
|
68
73
|
const localIcon = await getLocalIconInfo();
|
|
69
74
|
const serverConfig = {
|
|
@@ -74,13 +79,16 @@ async function createMcpServerWithOptions(options) {
|
|
|
74
79
|
}
|
|
75
80
|
const serverInfo = createServerInfo(localIcon ? [localIcon] : undefined);
|
|
76
81
|
const server = new McpServer(serverInfo, serverConfig);
|
|
77
|
-
if (options
|
|
82
|
+
if (shouldRegisterObservabilityServer(options)) {
|
|
78
83
|
setMcpServer(server);
|
|
79
84
|
}
|
|
80
|
-
|
|
85
|
+
registerAllTools(server);
|
|
81
86
|
registerGetHelpPrompt(server, serverInstructions, localIcon);
|
|
82
87
|
registerInstructionResource(server, serverInstructions, localIcon);
|
|
83
88
|
registerCacheResourceTemplate(server, localIcon);
|
|
89
|
+
// NOTE: Internally patches server.close and server.server.onclose for cleanup
|
|
90
|
+
// callbacks, and intercepts tools/call via Reflect.get on private SDK state.
|
|
91
|
+
// See src/lib/task-handlers.ts for risk documentation (S-2, S-3).
|
|
84
92
|
registerTaskHandlers(server);
|
|
85
93
|
registerLoggingSetLevelHandler(server);
|
|
86
94
|
attachServerErrorHandler(server);
|
|
@@ -90,20 +98,14 @@ export async function createMcpServerForHttpSession() {
|
|
|
90
98
|
return createMcpServerWithOptions({ registerObservabilityServer: false });
|
|
91
99
|
}
|
|
92
100
|
function registerLoggingSetLevelHandler(server) {
|
|
93
|
-
|
|
94
|
-
.object({
|
|
95
|
-
method: z.literal('logging/setLevel'),
|
|
96
|
-
params: z.object({ level: z.string() }).loose(),
|
|
97
|
-
})
|
|
98
|
-
.loose();
|
|
99
|
-
server.server.setRequestHandler(SetLevelRequestSchema, async (request) => {
|
|
101
|
+
server.server.setRequestHandler(SetLevelRequestSchema, (request) => {
|
|
100
102
|
setLogLevel(request.params.level);
|
|
101
|
-
return
|
|
103
|
+
return {};
|
|
102
104
|
});
|
|
103
105
|
}
|
|
104
106
|
function attachServerErrorHandler(server) {
|
|
105
107
|
server.server.onerror = (error) => {
|
|
106
|
-
logError('[MCP Error]', error
|
|
108
|
+
logError('[MCP Error]', toError(error));
|
|
107
109
|
};
|
|
108
110
|
}
|
|
109
111
|
async function shutdownServer(server, signal) {
|
|
@@ -129,7 +131,7 @@ function createShutdownHandler(server) {
|
|
|
129
131
|
Promise.resolve()
|
|
130
132
|
.then(() => shutdownServer(server, signal))
|
|
131
133
|
.catch((err) => {
|
|
132
|
-
const error =
|
|
134
|
+
const error = toError(err);
|
|
133
135
|
logError('Error during shutdown', error);
|
|
134
136
|
process.exitCode = 1;
|
|
135
137
|
})
|
|
@@ -140,7 +142,7 @@ function createShutdownHandler(server) {
|
|
|
140
142
|
};
|
|
141
143
|
}
|
|
142
144
|
function registerSignalHandlers(handler) {
|
|
143
|
-
for (const signal of
|
|
145
|
+
for (const signal of SHUTDOWN_SIGNALS) {
|
|
144
146
|
process.once(signal, () => {
|
|
145
147
|
handler(signal);
|
|
146
148
|
});
|
|
@@ -152,7 +154,7 @@ async function connectStdioServer(server, transport) {
|
|
|
152
154
|
logInfo('Fetch URL MCP server running on stdio');
|
|
153
155
|
}
|
|
154
156
|
catch (error) {
|
|
155
|
-
const err =
|
|
157
|
+
const err = toError(error);
|
|
156
158
|
throw new Error(`Failed to start stdio server: ${err.message}`, {
|
|
157
159
|
cause: error,
|
|
158
160
|
});
|
|
@@ -164,4 +166,3 @@ export async function startStdioServer() {
|
|
|
164
166
|
registerSignalHandlers(createShutdownHandler(server));
|
|
165
167
|
await connectStdioServer(server, transport);
|
|
166
168
|
}
|
|
167
|
-
//# sourceMappingURL=server.js.map
|
|
@@ -39,4 +39,3 @@ export declare function emitTaskStatusNotification(server: McpServer, task: Task
|
|
|
39
39
|
export declare function throwTaskNotFound(): never;
|
|
40
40
|
export declare function handleToolCallRequest(server: McpServer, request: ExtendedCallToolRequest, context: ToolCallContext): Promise<ServerResult>;
|
|
41
41
|
export {};
|
|
42
|
-
//# sourceMappingURL=execution.d.ts.map
|
package/dist/tasks/execution.js
CHANGED
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
import { ErrorCode, McpError, } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { config } from '../lib/core.js';
|
|
3
|
+
import { logWarn, runWithRequestContext } from '../lib/core.js';
|
|
4
|
+
import { getErrorMessage, RESOURCE_NOT_FOUND_ERROR_CODE, } from '../lib/utils.js';
|
|
5
|
+
import { isObject } from '../lib/utils.js';
|
|
5
6
|
import { taskManager, } from './manager.js';
|
|
6
7
|
import { compact, tryReadToolStructuredError, } from './owner.js';
|
|
8
|
+
import { getTaskCapableTool, hasTaskCapableTool, } from './tool-registry.js';
|
|
7
9
|
/* -------------------------------------------------------------------------------------------------
|
|
8
10
|
* Abort-controller management for in-flight task executions
|
|
9
11
|
* ------------------------------------------------------------------------------------------------- */
|
|
10
12
|
// Intentionally process-global (not session-scoped): abortAllTaskExecutions() is called
|
|
11
13
|
// during SIGTERM/SIGINT shutdown to cancel every in-flight task across all sessions.
|
|
12
|
-
//
|
|
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.
|
|
13
16
|
const taskAbortControllers = new Map();
|
|
14
17
|
function attachAbortController(taskId) {
|
|
15
18
|
const existing = taskAbortControllers.get(taskId);
|
|
16
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();
|
|
17
23
|
taskAbortControllers.delete(taskId);
|
|
18
24
|
}
|
|
19
25
|
const controller = new AbortController();
|
|
@@ -72,43 +78,56 @@ export function withRelatedTaskMeta(result, taskId) {
|
|
|
72
78
|
};
|
|
73
79
|
}
|
|
74
80
|
export function emitTaskStatusNotification(server, task) {
|
|
81
|
+
if (!config.tasks.emitStatusNotifications)
|
|
82
|
+
return;
|
|
75
83
|
if (!server.isConnected())
|
|
76
84
|
return;
|
|
77
|
-
// NOTE: 'notifications/tasks/status' is
|
|
78
|
-
//
|
|
85
|
+
// NOTE: 'notifications/tasks/status' is a non-spec extension (not in MCP v2025-11-25).
|
|
86
|
+
// Gated by config.tasks.emitStatusNotifications (TASKS_STATUS_NOTIFICATIONS env var).
|
|
87
|
+
// Clients should NOT depend on this for interoperability — behavior may change.
|
|
79
88
|
void server.server
|
|
80
89
|
.notification({
|
|
81
90
|
method: 'notifications/tasks/status',
|
|
82
|
-
params:
|
|
91
|
+
params: buildTaskStatusNotificationParams(task),
|
|
83
92
|
})
|
|
84
93
|
.catch((error) => {
|
|
85
94
|
logWarn('Failed to send task status notification', {
|
|
86
95
|
taskId: task.taskId,
|
|
87
96
|
status: task.status,
|
|
88
|
-
error,
|
|
97
|
+
error: getErrorMessage(error),
|
|
89
98
|
});
|
|
90
99
|
});
|
|
91
100
|
}
|
|
101
|
+
function buildTaskStatusNotificationParams(task) {
|
|
102
|
+
return {
|
|
103
|
+
taskId: task.taskId,
|
|
104
|
+
status: task.status,
|
|
105
|
+
...(task.statusMessage ? { statusMessage: task.statusMessage } : {}),
|
|
106
|
+
createdAt: task.createdAt,
|
|
107
|
+
lastUpdatedAt: task.lastUpdatedAt,
|
|
108
|
+
ttl: task.ttl,
|
|
109
|
+
pollInterval: task.pollInterval,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
92
112
|
/* -------------------------------------------------------------------------------------------------
|
|
93
113
|
* Validation helpers
|
|
94
114
|
* ------------------------------------------------------------------------------------------------- */
|
|
95
|
-
function requireFetchUrlArgs(args) {
|
|
96
|
-
const parsed = fetchUrlInputSchema.safeParse(args);
|
|
97
|
-
if (!parsed.success) {
|
|
98
|
-
throw new McpError(ErrorCode.InvalidParams, 'Invalid arguments for fetch-url');
|
|
99
|
-
}
|
|
100
|
-
return parsed.data;
|
|
101
|
-
}
|
|
102
|
-
// -32002 is the MCP extension code for resource-not-found; the SDK ErrorCode enum does not export it.
|
|
103
|
-
const RESOURCE_NOT_FOUND_ERROR_CODE = -32002;
|
|
104
115
|
export function throwTaskNotFound() {
|
|
105
116
|
throw new McpError(RESOURCE_NOT_FOUND_ERROR_CODE, 'Task not found');
|
|
106
117
|
}
|
|
107
|
-
function
|
|
108
|
-
|
|
109
|
-
|
|
118
|
+
function resolveTaskCapableTool(name) {
|
|
119
|
+
const descriptor = getTaskCapableTool(name);
|
|
120
|
+
if (descriptor)
|
|
121
|
+
return descriptor;
|
|
110
122
|
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: '${name}'`);
|
|
111
123
|
}
|
|
124
|
+
// Validates that the tool name is recognized before we attempt to execute it.
|
|
125
|
+
// 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.
|
|
126
|
+
function assertKnownTool(name) {
|
|
127
|
+
if (!hasTaskCapableTool(name)) {
|
|
128
|
+
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: '${name}'`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
112
131
|
/* -------------------------------------------------------------------------------------------------
|
|
113
132
|
* Task result builders
|
|
114
133
|
* ------------------------------------------------------------------------------------------------- */
|
|
@@ -143,18 +162,60 @@ function updateWorkingTaskStatus(server, taskId, statusMessage) {
|
|
|
143
162
|
return;
|
|
144
163
|
if (current.statusMessage === statusMessage)
|
|
145
164
|
return;
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
165
|
+
updateTaskAndEmitStatus(server, taskId, { statusMessage });
|
|
166
|
+
}
|
|
167
|
+
function updateTaskAndEmitStatus(server, taskId, update) {
|
|
168
|
+
taskManager.updateTask(taskId, update);
|
|
169
|
+
const task = taskManager.getTask(taskId);
|
|
170
|
+
if (task)
|
|
171
|
+
emitTaskStatusNotification(server, task);
|
|
172
|
+
}
|
|
173
|
+
function buildTaskFailureState(error) {
|
|
174
|
+
const statusMessage = getErrorMessage(error);
|
|
175
|
+
if (error instanceof McpError) {
|
|
176
|
+
return {
|
|
177
|
+
statusMessage,
|
|
178
|
+
error: {
|
|
179
|
+
code: error.code,
|
|
180
|
+
message: statusMessage,
|
|
181
|
+
data: error.data,
|
|
182
|
+
},
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
return {
|
|
186
|
+
statusMessage,
|
|
187
|
+
error: {
|
|
188
|
+
code: ErrorCode.InternalError,
|
|
189
|
+
message: statusMessage,
|
|
190
|
+
},
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
function resolveToolAndArgs(params) {
|
|
194
|
+
const tool = resolveTaskCapableTool(params.name);
|
|
195
|
+
const args = tool.parseArguments(params.arguments);
|
|
196
|
+
return { tool, args };
|
|
197
|
+
}
|
|
198
|
+
function buildTaskCompletionUpdate(result) {
|
|
199
|
+
const isToolError = isObject(result) && 'isError' in result && result.isError === true;
|
|
200
|
+
return {
|
|
201
|
+
status: isToolError ? 'failed' : 'completed',
|
|
202
|
+
statusMessage: isToolError
|
|
203
|
+
? (tryReadToolStructuredError(result) ?? 'Tool execution failed')
|
|
204
|
+
: 'Task completed successfully.',
|
|
205
|
+
result,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
async function runTaskToolExecution(params) {
|
|
209
|
+
const { server, taskId, args, tool, meta, sessionId, sendNotification } = params;
|
|
210
|
+
return runWithRequestContext({
|
|
211
|
+
requestId: taskId,
|
|
212
|
+
operationId: taskId,
|
|
213
|
+
...(sessionId ? { sessionId } : {}),
|
|
214
|
+
}, async () => {
|
|
154
215
|
const controller = attachAbortController(taskId);
|
|
155
216
|
try {
|
|
156
217
|
const relatedMeta = buildRelatedTaskMeta(taskId, meta);
|
|
157
|
-
const result = await
|
|
218
|
+
const result = await tool.execute(args, {
|
|
158
219
|
signal: controller.signal,
|
|
159
220
|
requestId: taskId,
|
|
160
221
|
_meta: relatedMeta,
|
|
@@ -163,40 +224,15 @@ async function runFetchTaskExecution(params) {
|
|
|
163
224
|
updateWorkingTaskStatus(server, taskId, message);
|
|
164
225
|
},
|
|
165
226
|
});
|
|
166
|
-
|
|
167
|
-
typeof result['isError'] === 'boolean' &&
|
|
168
|
-
result['isError'];
|
|
169
|
-
taskManager.updateTask(taskId, {
|
|
170
|
-
status: isToolError ? 'failed' : 'completed',
|
|
171
|
-
statusMessage: isToolError
|
|
172
|
-
? (tryReadToolStructuredError(result) ?? 'Tool execution failed')
|
|
173
|
-
: 'Task completed successfully.',
|
|
174
|
-
result,
|
|
175
|
-
});
|
|
176
|
-
const task = taskManager.getTask(taskId);
|
|
177
|
-
if (task)
|
|
178
|
-
emitTaskStatusNotification(server, task);
|
|
227
|
+
updateTaskAndEmitStatus(server, taskId, buildTaskCompletionUpdate(result));
|
|
179
228
|
}
|
|
180
229
|
catch (error) {
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
? {
|
|
184
|
-
code: error.code,
|
|
185
|
-
message: errorMessage,
|
|
186
|
-
data: error.data,
|
|
187
|
-
}
|
|
188
|
-
: {
|
|
189
|
-
code: ErrorCode.InternalError,
|
|
190
|
-
message: errorMessage,
|
|
191
|
-
};
|
|
192
|
-
taskManager.updateTask(taskId, {
|
|
230
|
+
const failure = buildTaskFailureState(error);
|
|
231
|
+
updateTaskAndEmitStatus(server, taskId, {
|
|
193
232
|
status: 'failed',
|
|
194
|
-
statusMessage:
|
|
195
|
-
error:
|
|
233
|
+
statusMessage: failure.statusMessage,
|
|
234
|
+
error: failure.error,
|
|
196
235
|
});
|
|
197
|
-
const task = taskManager.getTask(taskId);
|
|
198
|
-
if (task)
|
|
199
|
-
emitTaskStatusNotification(server, task);
|
|
200
236
|
}
|
|
201
237
|
finally {
|
|
202
238
|
clearTaskExecution(taskId);
|
|
@@ -204,38 +240,38 @@ async function runFetchTaskExecution(params) {
|
|
|
204
240
|
});
|
|
205
241
|
}
|
|
206
242
|
function handleTaskToolCall(server, params, context) {
|
|
207
|
-
|
|
208
|
-
const validArgs = requireFetchUrlArgs(params.arguments);
|
|
243
|
+
const { tool, args } = resolveToolAndArgs(params);
|
|
209
244
|
const task = taskManager.createTask(params.task?.ttl !== undefined ? { ttl: params.task.ttl } : undefined, 'Task started', context.ownerKey);
|
|
210
|
-
void
|
|
245
|
+
void runTaskToolExecution({
|
|
211
246
|
server,
|
|
212
247
|
taskId: task.taskId,
|
|
213
|
-
args
|
|
248
|
+
args,
|
|
249
|
+
tool,
|
|
214
250
|
...compact({
|
|
215
251
|
meta: params._meta,
|
|
252
|
+
sessionId: context.sessionId,
|
|
216
253
|
sendNotification: context.sendNotification,
|
|
217
254
|
}),
|
|
218
255
|
});
|
|
219
256
|
return buildCreateTaskResult(toTaskSummary(task));
|
|
220
257
|
}
|
|
221
258
|
async function handleDirectToolCall(params, context) {
|
|
222
|
-
const args =
|
|
259
|
+
const { tool, args } = resolveToolAndArgs(params);
|
|
223
260
|
const extra = compact({
|
|
224
261
|
signal: context.signal,
|
|
225
262
|
requestId: context.requestId,
|
|
226
263
|
sendNotification: context.sendNotification,
|
|
227
264
|
_meta: params._meta,
|
|
228
265
|
});
|
|
229
|
-
return
|
|
266
|
+
return tool.execute(args, extra);
|
|
230
267
|
}
|
|
231
268
|
export async function handleToolCallRequest(server, request, context) {
|
|
232
269
|
const { params } = request;
|
|
270
|
+
// Validate the tool name first so an unknown tool always produces MethodNotFound,
|
|
271
|
+
// regardless of whether a task:{} param was supplied (H-4).
|
|
272
|
+
assertKnownTool(params.name);
|
|
233
273
|
if (params.task) {
|
|
234
274
|
return handleTaskToolCall(server, params, context);
|
|
235
275
|
}
|
|
236
|
-
|
|
237
|
-
return handleDirectToolCall(params, context);
|
|
238
|
-
}
|
|
239
|
-
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${params.name}`);
|
|
276
|
+
return handleDirectToolCall(params, context);
|
|
240
277
|
}
|
|
241
|
-
//# sourceMappingURL=execution.js.map
|
package/dist/tasks/manager.d.ts
CHANGED
|
@@ -40,15 +40,20 @@ declare class TaskManager {
|
|
|
40
40
|
private tasks;
|
|
41
41
|
private ownerCounts;
|
|
42
42
|
private waiters;
|
|
43
|
-
|
|
44
|
-
private
|
|
43
|
+
private cleanupInterval;
|
|
44
|
+
private ensureCleanupLoop;
|
|
45
|
+
private stopCleanupLoop;
|
|
45
46
|
private removeExpiredTasks;
|
|
46
47
|
private removeTask;
|
|
48
|
+
private applyTaskUpdate;
|
|
49
|
+
private cancelActiveTask;
|
|
50
|
+
private releaseOwnerCount;
|
|
47
51
|
private countTasksForOwner;
|
|
48
52
|
private incrementOwnerCount;
|
|
49
53
|
private decrementOwnerCount;
|
|
50
54
|
private assertTaskCapacity;
|
|
51
55
|
createTask(options?: CreateTaskOptions, statusMessage?: string, ownerKey?: string): TaskState;
|
|
56
|
+
private lookupActiveTask;
|
|
52
57
|
getTask(taskId: string, ownerKey?: string): TaskState | undefined;
|
|
53
58
|
updateTask(taskId: string, updates: Partial<Omit<TaskState, 'taskId' | 'createdAt'>>): void;
|
|
54
59
|
cancelTask(taskId: string, ownerKey?: string): TaskState | undefined;
|
|
@@ -62,9 +67,13 @@ declare class TaskManager {
|
|
|
62
67
|
tasks: TaskState[];
|
|
63
68
|
nextCursor?: string;
|
|
64
69
|
};
|
|
70
|
+
private resolveAnchorTaskId;
|
|
71
|
+
private addWaiter;
|
|
72
|
+
private removeWaiter;
|
|
65
73
|
waitForTerminalTask(taskId: string, ownerKey: string, signal?: AbortSignal): Promise<TaskState | undefined>;
|
|
66
74
|
private notifyWaiters;
|
|
67
75
|
private isExpired;
|
|
76
|
+
private maybeUpdateLastUpdatedAt;
|
|
68
77
|
shrinkTtlAfterDelivery(taskId: string): void;
|
|
69
78
|
private encodeCursor;
|
|
70
79
|
private decodeCursor;
|
|
@@ -72,4 +81,3 @@ declare class TaskManager {
|
|
|
72
81
|
}
|
|
73
82
|
export declare const taskManager: TaskManager;
|
|
74
83
|
export {};
|
|
75
|
-
//# sourceMappingURL=manager.d.ts.map
|