@j0hanz/fetch-url-mcp 1.4.0 → 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/dist/cli.d.ts +2 -3
- package/dist/cli.js +1 -2
- package/dist/http/auth.d.ts +5 -3
- package/dist/http/auth.js +64 -15
- package/dist/http/health.d.ts +1 -2
- package/dist/http/health.js +7 -18
- package/dist/http/helpers.d.ts +3 -4
- package/dist/http/helpers.js +21 -21
- package/dist/http/native.d.ts +0 -1
- package/dist/http/native.js +34 -26
- package/dist/http/rate-limit.d.ts +0 -1
- package/dist/http/rate-limit.js +3 -4
- package/dist/index.d.ts +0 -1
- package/dist/index.js +17 -18
- package/dist/lib/{markdown-cleanup.d.ts → 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/lib/{tool-pipeline.d.ts → fetch-pipeline.d.ts} +1 -2
- package/dist/lib/{tool-pipeline.js → fetch-pipeline.js} +10 -19
- package/dist/lib/{fetch.d.ts → http.d.ts} +7 -9
- package/dist/lib/{fetch.js → http.js} +706 -944
- package/dist/lib/mcp-tools.d.ts +28 -0
- package/dist/lib/mcp-tools.js +107 -0
- package/dist/lib/{tool-progress.d.ts → progress.d.ts} +0 -1
- package/dist/lib/{tool-progress.js → progress.js} +8 -13
- package/dist/lib/task-handlers.d.ts +5 -0
- package/dist/lib/{mcp.js → task-handlers.js} +56 -12
- 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/index.d.ts +0 -1
- package/dist/prompts/index.js +0 -1
- package/dist/resources/index.d.ts +0 -1
- package/dist/resources/index.js +74 -33
- package/dist/resources/instructions.d.ts +0 -1
- package/dist/resources/instructions.js +2 -2
- package/dist/schemas/inputs.d.ts +0 -1
- package/dist/schemas/inputs.js +2 -3
- package/dist/schemas/outputs.d.ts +0 -1
- package/dist/schemas/outputs.js +1 -2
- package/dist/server.d.ts +0 -1
- package/dist/server.js +16 -26
- package/dist/tasks/execution.d.ts +0 -1
- package/dist/tasks/execution.js +27 -24
- package/dist/tasks/manager.d.ts +7 -3
- package/dist/tasks/manager.js +53 -34
- package/dist/tasks/owner.d.ts +1 -2
- package/dist/tasks/owner.js +1 -2
- package/dist/tasks/tool-registry.d.ts +1 -2
- package/dist/tasks/tool-registry.js +0 -1
- package/dist/tools/fetch-url.d.ts +1 -2
- package/dist/tools/fetch-url.js +39 -31
- package/dist/tools/index.d.ts +0 -1
- package/dist/tools/index.js +0 -1
- 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 +24 -641
- package/dist/transform/types.d.ts +9 -11
- 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 +0 -1
- package/dist/transform/workers/shared.js +1 -2
- package/dist/transform/workers/transform-child.d.ts +0 -1
- package/dist/transform/workers/transform-child.js +0 -1
- package/dist/transform/workers/transform-worker.d.ts +0 -1
- package/dist/transform/workers/transform-worker.js +0 -1
- package/package.json +6 -3
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.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/lib/cache.d.ts +0 -54
- package/dist/lib/cache.d.ts.map +0 -1
- package/dist/lib/cache.js +0 -264
- package/dist/lib/cache.js.map +0 -1
- package/dist/lib/config.d.ts +0 -143
- package/dist/lib/config.d.ts.map +0 -1
- package/dist/lib/config.js +0 -476
- package/dist/lib/config.js.map +0 -1
- package/dist/lib/crypto.d.ts +0 -4
- package/dist/lib/crypto.d.ts.map +0 -1
- package/dist/lib/crypto.js +0 -56
- package/dist/lib/crypto.js.map +0 -1
- package/dist/lib/dom-noise-removal.d.ts +0 -2
- package/dist/lib/dom-noise-removal.d.ts.map +0 -1
- package/dist/lib/dom-noise-removal.js +0 -494
- package/dist/lib/dom-noise-removal.js.map +0 -1
- package/dist/lib/download.d.ts +0 -4
- package/dist/lib/download.d.ts.map +0 -1
- package/dist/lib/download.js +0 -106
- package/dist/lib/download.js.map +0 -1
- package/dist/lib/errors.d.ts +0 -14
- package/dist/lib/errors.d.ts.map +0 -1
- package/dist/lib/errors.js +0 -72
- package/dist/lib/errors.js.map +0 -1
- package/dist/lib/fetch-content.d.ts +0 -5
- package/dist/lib/fetch-content.d.ts.map +0 -1
- package/dist/lib/fetch-content.js +0 -164
- package/dist/lib/fetch-content.js.map +0 -1
- package/dist/lib/fetch-stream.d.ts +0 -5
- package/dist/lib/fetch-stream.d.ts.map +0 -1
- package/dist/lib/fetch-stream.js +0 -29
- package/dist/lib/fetch-stream.js.map +0 -1
- package/dist/lib/fetch.d.ts.map +0 -1
- package/dist/lib/fetch.js.map +0 -1
- package/dist/lib/host-normalization.d.ts +0 -2
- package/dist/lib/host-normalization.d.ts.map +0 -1
- package/dist/lib/host-normalization.js +0 -91
- package/dist/lib/host-normalization.js.map +0 -1
- package/dist/lib/ip-blocklist.d.ts +0 -9
- package/dist/lib/ip-blocklist.d.ts.map +0 -1
- package/dist/lib/ip-blocklist.js +0 -79
- package/dist/lib/ip-blocklist.js.map +0 -1
- package/dist/lib/json.d.ts +0 -2
- package/dist/lib/json.d.ts.map +0 -1
- package/dist/lib/json.js +0 -45
- package/dist/lib/json.js.map +0 -1
- package/dist/lib/language-detection.d.ts +0 -3
- package/dist/lib/language-detection.d.ts.map +0 -1
- package/dist/lib/language-detection.js +0 -355
- package/dist/lib/language-detection.js.map +0 -1
- package/dist/lib/markdown-cleanup.d.ts.map +0 -1
- package/dist/lib/markdown-cleanup.js +0 -532
- package/dist/lib/markdown-cleanup.js.map +0 -1
- package/dist/lib/mcp-lifecycle.d.ts +0 -5
- package/dist/lib/mcp-lifecycle.d.ts.map +0 -1
- package/dist/lib/mcp-lifecycle.js +0 -51
- package/dist/lib/mcp-lifecycle.js.map +0 -1
- package/dist/lib/mcp-validator.d.ts +0 -17
- package/dist/lib/mcp-validator.d.ts.map +0 -1
- package/dist/lib/mcp-validator.js +0 -45
- package/dist/lib/mcp-validator.js.map +0 -1
- package/dist/lib/mcp.d.ts +0 -4
- package/dist/lib/mcp.d.ts.map +0 -1
- package/dist/lib/mcp.js.map +0 -1
- package/dist/lib/observability.d.ts +0 -23
- package/dist/lib/observability.d.ts.map +0 -1
- package/dist/lib/observability.js +0 -238
- package/dist/lib/observability.js.map +0 -1
- package/dist/lib/server-tuning.d.ts +0 -15
- package/dist/lib/server-tuning.d.ts.map +0 -1
- package/dist/lib/server-tuning.js +0 -49
- package/dist/lib/server-tuning.js.map +0 -1
- package/dist/lib/session.d.ts +0 -45
- package/dist/lib/session.d.ts.map +0 -1
- package/dist/lib/session.js +0 -263
- package/dist/lib/session.js.map +0 -1
- package/dist/lib/timer-utils.d.ts +0 -13
- package/dist/lib/timer-utils.d.ts.map +0 -1
- package/dist/lib/timer-utils.js +0 -44
- package/dist/lib/timer-utils.js.map +0 -1
- package/dist/lib/tool-errors.d.ts +0 -12
- package/dist/lib/tool-errors.d.ts.map +0 -1
- package/dist/lib/tool-errors.js +0 -55
- package/dist/lib/tool-errors.js.map +0 -1
- package/dist/lib/tool-pipeline.d.ts.map +0 -1
- package/dist/lib/tool-pipeline.js.map +0 -1
- package/dist/lib/tool-progress.d.ts.map +0 -1
- package/dist/lib/tool-progress.js.map +0 -1
- package/dist/lib/type-guards.d.ts +0 -16
- package/dist/lib/type-guards.d.ts.map +0 -1
- package/dist/lib/type-guards.js +0 -13
- package/dist/lib/type-guards.js.map +0 -1
- package/dist/prompts/index.d.ts.map +0 -1
- package/dist/prompts/index.js.map +0 -1
- package/dist/resources/index.d.ts.map +0 -1
- package/dist/resources/index.js.map +0 -1
- package/dist/resources/instructions.d.ts.map +0 -1
- package/dist/resources/instructions.js.map +0 -1
- package/dist/schemas/inputs.d.ts.map +0 -1
- package/dist/schemas/inputs.js.map +0 -1
- package/dist/schemas/outputs.d.ts.map +0 -1
- package/dist/schemas/outputs.js.map +0 -1
- package/dist/server.d.ts.map +0 -1
- package/dist/server.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/tasks/tool-registry.d.ts.map +0 -1
- package/dist/tasks/tool-registry.js.map +0 -1
- package/dist/tools/fetch-url.d.ts.map +0 -1
- package/dist/tools/fetch-url.js.map +0 -1
- package/dist/tools/index.d.ts.map +0 -1
- package/dist/tools/index.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/shared.d.ts.map +0 -1
- package/dist/transform/workers/shared.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
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
export type JsonRpcId = string | number | null;
|
|
3
|
+
interface McpRequestParams {
|
|
4
|
+
_meta?: Record<string, unknown>;
|
|
5
|
+
[key: string]: unknown;
|
|
6
|
+
}
|
|
7
|
+
interface McpRequestBody {
|
|
8
|
+
jsonrpc: '2.0';
|
|
9
|
+
method: string;
|
|
10
|
+
id?: JsonRpcId;
|
|
11
|
+
params?: McpRequestParams;
|
|
12
|
+
}
|
|
13
|
+
export declare function isJsonRpcBatchRequest(body: unknown): boolean;
|
|
14
|
+
export declare function isMcpRequestBody(body: unknown): body is McpRequestBody;
|
|
15
|
+
export declare function acceptsEventStream(header: string | null | undefined): boolean;
|
|
16
|
+
export declare function acceptsJsonAndEventStream(header: string | null | undefined): boolean;
|
|
17
|
+
type ToolErrorResponse = CallToolResult & {
|
|
18
|
+
isError: true;
|
|
19
|
+
};
|
|
20
|
+
export declare function createToolErrorResponse(message: string, url: string, extra?: {
|
|
21
|
+
code?: string;
|
|
22
|
+
statusCode?: number;
|
|
23
|
+
details?: Record<string, unknown>;
|
|
24
|
+
}): ToolErrorResponse;
|
|
25
|
+
export declare function handleToolError(error: unknown, url: string, fallbackMessage?: string): ToolErrorResponse;
|
|
26
|
+
export { registerServerLifecycleCleanup, registerTaskHandlers, cancelTasksForOwner, abortAllTaskExecutions, } from './task-handlers.js';
|
|
27
|
+
export { readString, readNestedRecord, withSignal, TRUNCATION_MARKER, type InlineContentResult, appendTruncationMarker, type PipelineResult, executeFetchPipeline, type MarkdownPipelineResult, parseCachedMarkdownResult, markdownTransform, serializeMarkdownResult, performSharedFetch, } from './fetch-pipeline.js';
|
|
28
|
+
export { type ProgressNotificationParams, type ProgressNotification, type ToolHandlerExtra, type ProgressReporter, createProgressReporter, } from './progress.js';
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import {} from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { FetchError, isAbortError, isSystemError } from './utils.js';
|
|
4
|
+
const paramsSchema = z.looseObject({});
|
|
5
|
+
const mcpRequestSchema = z.strictObject({
|
|
6
|
+
jsonrpc: z.literal('2.0'),
|
|
7
|
+
method: z.string().min(1),
|
|
8
|
+
id: z.union([z.string(), z.number(), z.null()]).optional(),
|
|
9
|
+
params: paramsSchema.optional(),
|
|
10
|
+
});
|
|
11
|
+
export function isJsonRpcBatchRequest(body) {
|
|
12
|
+
return Array.isArray(body);
|
|
13
|
+
}
|
|
14
|
+
export function isMcpRequestBody(body) {
|
|
15
|
+
return mcpRequestSchema.safeParse(body).success;
|
|
16
|
+
}
|
|
17
|
+
function parseAcceptMediaTypes(header) {
|
|
18
|
+
if (!header)
|
|
19
|
+
return [];
|
|
20
|
+
return header
|
|
21
|
+
.split(',')
|
|
22
|
+
.map((value) => extractAcceptMediaType(value.trim()))
|
|
23
|
+
.filter((value) => value.length > 0);
|
|
24
|
+
}
|
|
25
|
+
function extractAcceptMediaType(value) {
|
|
26
|
+
return value.split(';', 1)[0]?.trim().toLowerCase() ?? '';
|
|
27
|
+
}
|
|
28
|
+
export function acceptsEventStream(header) {
|
|
29
|
+
const mediaTypes = parseAcceptMediaTypes(header);
|
|
30
|
+
return mediaTypes.some((mediaType) => mediaType === 'text/event-stream');
|
|
31
|
+
}
|
|
32
|
+
function hasAcceptedMediaType(mediaTypes, exact, wildcardPrefix) {
|
|
33
|
+
return mediaTypes.some((mediaType) => typeof mediaType === 'string' &&
|
|
34
|
+
mediaType.length > 0 &&
|
|
35
|
+
(mediaType === '*/*' ||
|
|
36
|
+
mediaType === exact ||
|
|
37
|
+
mediaType === wildcardPrefix));
|
|
38
|
+
}
|
|
39
|
+
export function acceptsJsonAndEventStream(header) {
|
|
40
|
+
const mediaTypes = parseAcceptMediaTypes(header);
|
|
41
|
+
const acceptsJson = hasAcceptedMediaType(mediaTypes, 'application/json', 'application/*');
|
|
42
|
+
if (!acceptsJson)
|
|
43
|
+
return false;
|
|
44
|
+
return hasAcceptedMediaType(mediaTypes, 'text/event-stream', 'text/*');
|
|
45
|
+
}
|
|
46
|
+
export function createToolErrorResponse(message, url, extra) {
|
|
47
|
+
const errorContent = {
|
|
48
|
+
error: message,
|
|
49
|
+
...(extra?.code ? { code: extra.code } : {}),
|
|
50
|
+
url,
|
|
51
|
+
...(extra?.statusCode !== undefined
|
|
52
|
+
? { statusCode: extra.statusCode }
|
|
53
|
+
: {}),
|
|
54
|
+
...(extra?.details ? { details: extra.details } : {}),
|
|
55
|
+
};
|
|
56
|
+
return {
|
|
57
|
+
content: [{ type: 'text', text: JSON.stringify(errorContent) }],
|
|
58
|
+
isError: true,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function isValidationError(error) {
|
|
62
|
+
return (error instanceof Error &&
|
|
63
|
+
isSystemError(error) &&
|
|
64
|
+
error.code === 'VALIDATION_ERROR');
|
|
65
|
+
}
|
|
66
|
+
function isHandledToolError(error) {
|
|
67
|
+
return error instanceof FetchError || isValidationError(error);
|
|
68
|
+
}
|
|
69
|
+
function resolveToolErrorMessage(error, fallbackMessage) {
|
|
70
|
+
if (isHandledToolError(error)) {
|
|
71
|
+
return error.message;
|
|
72
|
+
}
|
|
73
|
+
if (error instanceof Error) {
|
|
74
|
+
return `${fallbackMessage}: ${error.message}`;
|
|
75
|
+
}
|
|
76
|
+
return `${fallbackMessage}: Unknown error`;
|
|
77
|
+
}
|
|
78
|
+
function resolveToolErrorCode(error) {
|
|
79
|
+
if (error instanceof FetchError)
|
|
80
|
+
return error.code;
|
|
81
|
+
if (isValidationError(error))
|
|
82
|
+
return 'VALIDATION_ERROR';
|
|
83
|
+
if (isAbortError(error))
|
|
84
|
+
return 'ABORTED';
|
|
85
|
+
return 'FETCH_ERROR';
|
|
86
|
+
}
|
|
87
|
+
export function handleToolError(error, url, fallbackMessage = 'Operation failed') {
|
|
88
|
+
const message = resolveToolErrorMessage(error, fallbackMessage);
|
|
89
|
+
const code = resolveToolErrorCode(error);
|
|
90
|
+
if (error instanceof FetchError) {
|
|
91
|
+
return createToolErrorResponse(message, url, {
|
|
92
|
+
code,
|
|
93
|
+
statusCode: error.statusCode,
|
|
94
|
+
details: error.details,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
return createToolErrorResponse(message, url, { code });
|
|
98
|
+
}
|
|
99
|
+
/* -------------------------------------------------------------------------------------------------
|
|
100
|
+
* Re-exports from split modules
|
|
101
|
+
*
|
|
102
|
+
* Preserves backward compatibility — consumers import from 'lib/mcp-tools.js'
|
|
103
|
+
* without changes. Direct imports from the sub-modules are preferred for new code.
|
|
104
|
+
* ------------------------------------------------------------------------------------------------- */
|
|
105
|
+
export { registerServerLifecycleCleanup, registerTaskHandlers, cancelTasksForOwner, abortAllTaskExecutions, } from './task-handlers.js';
|
|
106
|
+
export { readString, readNestedRecord, withSignal, TRUNCATION_MARKER, appendTruncationMarker, executeFetchPipeline, parseCachedMarkdownResult, markdownTransform, serializeMarkdownResult, performSharedFetch, } from './fetch-pipeline.js';
|
|
107
|
+
export { createProgressReporter, } from './progress.js';
|
|
@@ -1,14 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { isObject } from './type-guards.js';
|
|
4
|
-
/* -------------------------------------------------------------------------------------------------
|
|
5
|
-
* Constants
|
|
6
|
-
* ------------------------------------------------------------------------------------------------- */
|
|
1
|
+
import { logWarn } from './core.js';
|
|
2
|
+
import { getErrorMessage, isObject } from './utils.js';
|
|
7
3
|
const FETCH_PROGRESS_TOTAL = 4;
|
|
8
4
|
const PROGRESS_NOTIFICATION_TIMEOUT_MS = 5000;
|
|
9
|
-
/* -------------------------------------------------------------------------------------------------
|
|
10
|
-
* Helpers
|
|
11
|
-
* ------------------------------------------------------------------------------------------------- */
|
|
12
5
|
function resolveRelatedTaskMeta(meta) {
|
|
13
6
|
if (!meta)
|
|
14
7
|
return undefined;
|
|
@@ -18,9 +11,6 @@ function resolveRelatedTaskMeta(meta) {
|
|
|
18
11
|
const { taskId } = related;
|
|
19
12
|
return typeof taskId === 'string' ? { taskId } : undefined;
|
|
20
13
|
}
|
|
21
|
-
/* -------------------------------------------------------------------------------------------------
|
|
22
|
-
* Progress reporter
|
|
23
|
-
* ------------------------------------------------------------------------------------------------- */
|
|
24
14
|
class ToolProgressReporter {
|
|
25
15
|
token;
|
|
26
16
|
sendNotification;
|
|
@@ -45,6 +35,12 @@ class ToolProgressReporter {
|
|
|
45
35
|
}
|
|
46
36
|
return new ToolProgressReporter(token, sendNotification, relatedTaskMeta, onProgress);
|
|
47
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Report progress toward completion. Steps are monotonic (never decrease)
|
|
40
|
+
* and may be skipped under normal conditions (e.g., fast responses skip
|
|
41
|
+
* intermediate steps). Clients should treat progress as "at least this far"
|
|
42
|
+
* rather than expecting every step to fire sequentially.
|
|
43
|
+
*/
|
|
48
44
|
report(progress, message) {
|
|
49
45
|
if (this.isTerminal)
|
|
50
46
|
return;
|
|
@@ -126,4 +122,3 @@ class ToolProgressReporter {
|
|
|
126
122
|
export function createProgressReporter(extra) {
|
|
127
123
|
return ToolProgressReporter.create(extra);
|
|
128
124
|
}
|
|
129
|
-
//# sourceMappingURL=tool-progress.js.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
type CleanupCallback = () => void;
|
|
3
|
+
export declare function registerServerLifecycleCleanup(server: McpServer, callback: CleanupCallback): void;
|
|
4
|
+
export { cancelTasksForOwner, abortAllTaskExecutions, } from '../tasks/execution.js';
|
|
5
|
+
export declare function registerTaskHandlers(server: McpServer): void;
|
|
@@ -1,15 +1,59 @@
|
|
|
1
|
-
import { CallToolRequestSchema, ErrorCode, McpError, } from '@modelcontextprotocol/sdk/types.js';
|
|
2
1
|
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import {} from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
import { CallToolRequestSchema, ErrorCode, McpError, } from '@modelcontextprotocol/sdk/types.js';
|
|
3
4
|
import { z } from 'zod';
|
|
4
5
|
import { abortTaskExecution, emitTaskStatusNotification, handleToolCallRequest, throwTaskNotFound, toTaskSummary, withRelatedTaskMeta, } from '../tasks/execution.js';
|
|
5
6
|
import { taskManager } from '../tasks/manager.js';
|
|
6
7
|
import { isServerResult, parseHandlerExtra, resolveTaskOwnerKey, resolveToolCallContext, } from '../tasks/owner.js';
|
|
7
8
|
import { hasTaskCapableTool } from '../tasks/tool-registry.js';
|
|
8
|
-
import { runWithRequestContext } from './
|
|
9
|
-
|
|
9
|
+
import { logWarn, runWithRequestContext } from './core.js';
|
|
10
|
+
const patchedCleanupServers = new WeakSet();
|
|
11
|
+
const serverCleanupCallbacks = new WeakMap();
|
|
12
|
+
function getServerCleanupCallbackSet(server) {
|
|
13
|
+
let callbacks = serverCleanupCallbacks.get(server);
|
|
14
|
+
if (!callbacks) {
|
|
15
|
+
callbacks = new Set();
|
|
16
|
+
serverCleanupCallbacks.set(server, callbacks);
|
|
17
|
+
}
|
|
18
|
+
return callbacks;
|
|
19
|
+
}
|
|
20
|
+
function drainServerCleanupCallbacks(server) {
|
|
21
|
+
const callbacks = serverCleanupCallbacks.get(server);
|
|
22
|
+
if (!callbacks || callbacks.size === 0)
|
|
23
|
+
return;
|
|
24
|
+
const pending = [...callbacks];
|
|
25
|
+
callbacks.clear();
|
|
26
|
+
for (const callback of pending) {
|
|
27
|
+
try {
|
|
28
|
+
callback();
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
logWarn('Server cleanup callback failed', { error });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function ensureServerCleanupHooks(server) {
|
|
36
|
+
if (patchedCleanupServers.has(server))
|
|
37
|
+
return;
|
|
38
|
+
patchedCleanupServers.add(server);
|
|
39
|
+
const originalOnClose = server.server.onclose;
|
|
40
|
+
server.server.onclose = () => {
|
|
41
|
+
drainServerCleanupCallbacks(server);
|
|
42
|
+
originalOnClose?.();
|
|
43
|
+
};
|
|
44
|
+
const originalClose = server.close.bind(server);
|
|
45
|
+
server.close = async () => {
|
|
46
|
+
drainServerCleanupCallbacks(server);
|
|
47
|
+
await originalClose();
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export function registerServerLifecycleCleanup(server, callback) {
|
|
51
|
+
ensureServerCleanupHooks(server);
|
|
52
|
+
getServerCleanupCallbackSet(server).add(callback);
|
|
53
|
+
}
|
|
10
54
|
export { cancelTasksForOwner, abortAllTaskExecutions, } from '../tasks/execution.js';
|
|
11
55
|
/* -------------------------------------------------------------------------------------------------
|
|
12
|
-
*
|
|
56
|
+
* Task handler schemas and registration
|
|
13
57
|
* ------------------------------------------------------------------------------------------------- */
|
|
14
58
|
const TaskGetSchema = z
|
|
15
59
|
.object({
|
|
@@ -40,9 +84,6 @@ const TaskResultSchema = z
|
|
|
40
84
|
params: z.object({ taskId: z.string() }).loose(),
|
|
41
85
|
})
|
|
42
86
|
.loose();
|
|
43
|
-
/* -------------------------------------------------------------------------------------------------
|
|
44
|
-
* Tool call interception (tools/call) with task support
|
|
45
|
-
* ------------------------------------------------------------------------------------------------- */
|
|
46
87
|
const MIN_TASK_TTL_MS = 1_000;
|
|
47
88
|
const MAX_TASK_TTL_MS = 86_400_000;
|
|
48
89
|
const ExtendedCallToolRequestSchema = z
|
|
@@ -81,7 +122,11 @@ function parseExtendedCallToolRequest(request) {
|
|
|
81
122
|
const parsed = ExtendedCallToolRequestSchema.safeParse(request);
|
|
82
123
|
if (parsed.success)
|
|
83
124
|
return parsed.data;
|
|
84
|
-
|
|
125
|
+
const flat = z.flattenError(parsed.error);
|
|
126
|
+
const details = Object.entries(flat.fieldErrors)
|
|
127
|
+
.map(([k, v]) => `${k}: ${(v ?? []).join(', ')}`)
|
|
128
|
+
.join('; ') || flat.formErrors.join('; ');
|
|
129
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid tool request params: ${details}`);
|
|
85
130
|
}
|
|
86
131
|
function resolveOwnerScopedExtra(extra) {
|
|
87
132
|
const parsedExtra = parseHandlerExtra(extra);
|
|
@@ -97,11 +142,11 @@ function getSdkCallToolHandler(server) {
|
|
|
97
142
|
const handler = maybeHandlers.get('tools/call');
|
|
98
143
|
return typeof handler === 'function' ? handler : null;
|
|
99
144
|
}
|
|
100
|
-
/* -------------------------------------------------------------------------------------------------
|
|
101
|
-
* Register handlers
|
|
102
|
-
* ------------------------------------------------------------------------------------------------- */
|
|
103
145
|
export function registerTaskHandlers(server) {
|
|
104
146
|
const sdkCallToolHandler = getSdkCallToolHandler(server);
|
|
147
|
+
if (!sdkCallToolHandler) {
|
|
148
|
+
logWarn('Task call interception disabled: SDK tools/call handler unavailable; task-capable tools require MCP SDK compatibility update', { sdkVersion: 'unknown' });
|
|
149
|
+
}
|
|
105
150
|
if (sdkCallToolHandler) {
|
|
106
151
|
server.server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
|
|
107
152
|
const parsedExtra = parseHandlerExtra(extra);
|
|
@@ -192,4 +237,3 @@ export function registerTaskHandlers(server) {
|
|
|
192
237
|
return toTaskSummary(task);
|
|
193
238
|
});
|
|
194
239
|
}
|
|
195
|
-
//# sourceMappingURL=mcp.js.map
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { BlockList } from 'node:net';
|
|
2
|
+
import { type config } from './core.js';
|
|
3
|
+
export declare class SafeDnsResolver {
|
|
4
|
+
private readonly ipBlocker;
|
|
5
|
+
private readonly security;
|
|
6
|
+
private readonly blockedHostSuffixes;
|
|
7
|
+
constructor(ipBlocker: IpBlocker, security: SecurityConfig, blockedHostSuffixes: readonly string[]);
|
|
8
|
+
resolveAndValidate(hostname: string, signal?: AbortSignal): Promise<string>;
|
|
9
|
+
private isBlockedHostname;
|
|
10
|
+
private assertNoBlockedCname;
|
|
11
|
+
private resolveCname;
|
|
12
|
+
}
|
|
13
|
+
type HostnamePreflight = (url: string, signal?: AbortSignal) => Promise<string>;
|
|
14
|
+
export declare function createDnsPreflight(dnsResolver: SafeDnsResolver): HostnamePreflight;
|
|
15
|
+
export declare function normalizeHost(value: string): string | null;
|
|
16
|
+
type IpFamily = 'ipv4' | 'ipv6';
|
|
17
|
+
export declare function createDefaultBlockList(): BlockList;
|
|
18
|
+
export declare function normalizeIpForBlockList(input: string): {
|
|
19
|
+
ip: string;
|
|
20
|
+
family: IpFamily;
|
|
21
|
+
} | null;
|
|
22
|
+
export interface TransformResult {
|
|
23
|
+
readonly url: string;
|
|
24
|
+
readonly transformed: boolean;
|
|
25
|
+
readonly platform?: string;
|
|
26
|
+
}
|
|
27
|
+
export declare class RawUrlTransformer {
|
|
28
|
+
private readonly logger;
|
|
29
|
+
constructor(logger: Logger);
|
|
30
|
+
transformToRawUrl(url: string): TransformResult;
|
|
31
|
+
isRawTextContentUrl(urlString: string): boolean;
|
|
32
|
+
private isRawUrl;
|
|
33
|
+
private splitParams;
|
|
34
|
+
private tryTransformWithUrl;
|
|
35
|
+
private transformGithubBlob;
|
|
36
|
+
private transformGithubGist;
|
|
37
|
+
private transformGitLab;
|
|
38
|
+
private transformBitbucket;
|
|
39
|
+
}
|
|
40
|
+
export interface Logger {
|
|
41
|
+
debug(message: string, data?: Record<string, unknown>): void;
|
|
42
|
+
warn(message: string, data?: Record<string, unknown>): void;
|
|
43
|
+
error(message: string, data?: Record<string, unknown>): void;
|
|
44
|
+
}
|
|
45
|
+
export declare const VALIDATION_ERROR_CODE = "VALIDATION_ERROR";
|
|
46
|
+
export declare const BLOCKED_HOST_SUFFIXES: readonly string[];
|
|
47
|
+
type SecurityConfig = typeof config.security;
|
|
48
|
+
export declare class IpBlocker {
|
|
49
|
+
private readonly security;
|
|
50
|
+
private readonly blockList;
|
|
51
|
+
constructor(security: SecurityConfig);
|
|
52
|
+
isBlockedIp(candidate: string): boolean;
|
|
53
|
+
}
|
|
54
|
+
type ConstantsConfig = typeof config.constants;
|
|
55
|
+
export declare class UrlNormalizer {
|
|
56
|
+
private readonly constants;
|
|
57
|
+
private readonly security;
|
|
58
|
+
private readonly ipBlocker;
|
|
59
|
+
private readonly blockedHostSuffixes;
|
|
60
|
+
constructor(constants: ConstantsConfig, security: SecurityConfig, ipBlocker: IpBlocker, blockedHostSuffixes: readonly string[]);
|
|
61
|
+
normalize(urlString: string): {
|
|
62
|
+
normalizedUrl: string;
|
|
63
|
+
hostname: string;
|
|
64
|
+
};
|
|
65
|
+
validateAndNormalize(urlString: string): string;
|
|
66
|
+
private requireTrimmedUrl;
|
|
67
|
+
private normalizeHostname;
|
|
68
|
+
private assertHostnameAllowed;
|
|
69
|
+
}
|
|
70
|
+
export {};
|