@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.
Files changed (205) hide show
  1. package/README.md +24 -21
  2. package/dist/cli.d.ts +3 -3
  3. package/dist/cli.js +15 -8
  4. package/dist/http/auth.d.ts +6 -6
  5. package/dist/http/auth.js +78 -23
  6. package/dist/http/health.d.ts +1 -2
  7. package/dist/http/health.js +7 -18
  8. package/dist/http/helpers.d.ts +3 -11
  9. package/dist/http/helpers.js +28 -26
  10. package/dist/http/native.d.ts +0 -1
  11. package/dist/http/native.js +63 -41
  12. package/dist/http/rate-limit.d.ts +2 -2
  13. package/dist/http/rate-limit.js +11 -16
  14. package/dist/index.d.ts +0 -1
  15. package/dist/index.js +17 -20
  16. package/dist/{markdown-cleanup.d.ts → lib/content.d.ts} +4 -2
  17. package/dist/lib/content.js +1356 -0
  18. package/dist/lib/core.d.ts +253 -0
  19. package/dist/lib/core.js +1228 -0
  20. package/dist/{tool-pipeline.d.ts → lib/fetch-pipeline.d.ts} +1 -3
  21. package/dist/{tool-pipeline.js → lib/fetch-pipeline.js} +18 -44
  22. package/dist/{fetch.d.ts → lib/http.d.ts} +7 -9
  23. package/dist/{fetch.js → lib/http.js} +721 -1004
  24. package/dist/lib/mcp-tools.d.ts +28 -0
  25. package/dist/lib/mcp-tools.js +107 -0
  26. package/dist/{tool-progress.d.ts → lib/progress.d.ts} +0 -2
  27. package/dist/{tool-progress.js → lib/progress.js} +9 -14
  28. package/dist/lib/task-handlers.d.ts +5 -0
  29. package/dist/{mcp.js → lib/task-handlers.js} +95 -31
  30. package/dist/lib/url.d.ts +70 -0
  31. package/dist/lib/url.js +686 -0
  32. package/dist/lib/utils.d.ts +58 -0
  33. package/dist/lib/utils.js +304 -0
  34. package/dist/{prompts.d.ts → prompts/index.d.ts} +0 -1
  35. package/dist/{prompts.js → prompts/index.js} +1 -2
  36. package/dist/{resources.d.ts → resources/index.d.ts} +0 -1
  37. package/dist/{resources.js → resources/index.js} +87 -64
  38. package/dist/{instructions.d.ts → resources/instructions.d.ts} +0 -1
  39. package/dist/{instructions.js → resources/instructions.js} +5 -3
  40. package/dist/schemas/inputs.d.ts +7 -0
  41. package/dist/schemas/inputs.js +24 -0
  42. package/dist/schemas/outputs.d.ts +23 -0
  43. package/dist/schemas/outputs.js +77 -0
  44. package/dist/server.d.ts +0 -1
  45. package/dist/server.js +26 -25
  46. package/dist/tasks/execution.d.ts +0 -1
  47. package/dist/tasks/execution.js +106 -70
  48. package/dist/tasks/manager.d.ts +11 -3
  49. package/dist/tasks/manager.js +97 -73
  50. package/dist/tasks/owner.d.ts +3 -3
  51. package/dist/tasks/owner.js +2 -2
  52. package/dist/tasks/tool-registry.d.ts +11 -0
  53. package/dist/tasks/tool-registry.js +13 -0
  54. package/dist/tools/fetch-url.d.ts +28 -0
  55. package/dist/{tools.js → tools/fetch-url.js} +95 -147
  56. package/dist/tools/index.d.ts +2 -0
  57. package/dist/tools/index.js +4 -0
  58. package/dist/transform/html-translators.d.ts +1 -0
  59. package/dist/transform/html-translators.js +454 -0
  60. package/dist/transform/metadata.d.ts +4 -0
  61. package/dist/transform/metadata.js +183 -0
  62. package/dist/transform/transform.d.ts +0 -1
  63. package/dist/transform/transform.js +44 -679
  64. package/dist/transform/types.d.ts +9 -12
  65. package/dist/transform/types.js +0 -1
  66. package/dist/transform/worker-pool.d.ts +0 -1
  67. package/dist/transform/worker-pool.js +7 -16
  68. package/dist/transform/workers/shared.d.ts +7 -0
  69. package/dist/transform/workers/shared.js +130 -0
  70. package/dist/transform/workers/transform-child.d.ts +0 -1
  71. package/dist/transform/workers/transform-child.js +5 -135
  72. package/dist/transform/workers/transform-worker.d.ts +0 -1
  73. package/dist/transform/workers/transform-worker.js +7 -128
  74. package/package.json +11 -7
  75. package/dist/cache.d.ts +0 -54
  76. package/dist/cache.d.ts.map +0 -1
  77. package/dist/cache.js +0 -261
  78. package/dist/cache.js.map +0 -1
  79. package/dist/cli.d.ts.map +0 -1
  80. package/dist/cli.js.map +0 -1
  81. package/dist/config.d.ts +0 -141
  82. package/dist/config.d.ts.map +0 -1
  83. package/dist/config.js +0 -473
  84. package/dist/config.js.map +0 -1
  85. package/dist/crypto.d.ts +0 -4
  86. package/dist/crypto.d.ts.map +0 -1
  87. package/dist/crypto.js +0 -56
  88. package/dist/crypto.js.map +0 -1
  89. package/dist/dom-noise-removal.d.ts +0 -2
  90. package/dist/dom-noise-removal.d.ts.map +0 -1
  91. package/dist/dom-noise-removal.js +0 -494
  92. package/dist/dom-noise-removal.js.map +0 -1
  93. package/dist/download.d.ts +0 -4
  94. package/dist/download.d.ts.map +0 -1
  95. package/dist/download.js +0 -106
  96. package/dist/download.js.map +0 -1
  97. package/dist/errors.d.ts +0 -11
  98. package/dist/errors.d.ts.map +0 -1
  99. package/dist/errors.js +0 -65
  100. package/dist/errors.js.map +0 -1
  101. package/dist/examples/mcp-fetch-url-client.js +0 -329
  102. package/dist/examples/mcp-fetch-url-client.js.map +0 -1
  103. package/dist/fetch-content.d.ts +0 -5
  104. package/dist/fetch-content.d.ts.map +0 -1
  105. package/dist/fetch-content.js +0 -164
  106. package/dist/fetch-content.js.map +0 -1
  107. package/dist/fetch-stream.d.ts +0 -5
  108. package/dist/fetch-stream.d.ts.map +0 -1
  109. package/dist/fetch-stream.js +0 -29
  110. package/dist/fetch-stream.js.map +0 -1
  111. package/dist/fetch.d.ts.map +0 -1
  112. package/dist/fetch.js.map +0 -1
  113. package/dist/host-normalization.d.ts +0 -2
  114. package/dist/host-normalization.d.ts.map +0 -1
  115. package/dist/host-normalization.js +0 -91
  116. package/dist/host-normalization.js.map +0 -1
  117. package/dist/http/auth.d.ts.map +0 -1
  118. package/dist/http/auth.js.map +0 -1
  119. package/dist/http/health.d.ts.map +0 -1
  120. package/dist/http/health.js.map +0 -1
  121. package/dist/http/helpers.d.ts.map +0 -1
  122. package/dist/http/helpers.js.map +0 -1
  123. package/dist/http/native.d.ts.map +0 -1
  124. package/dist/http/native.js.map +0 -1
  125. package/dist/http/rate-limit.d.ts.map +0 -1
  126. package/dist/http/rate-limit.js.map +0 -1
  127. package/dist/index.d.ts.map +0 -1
  128. package/dist/index.js.map +0 -1
  129. package/dist/instructions.d.ts.map +0 -1
  130. package/dist/instructions.js.map +0 -1
  131. package/dist/ip-blocklist.d.ts +0 -9
  132. package/dist/ip-blocklist.d.ts.map +0 -1
  133. package/dist/ip-blocklist.js +0 -79
  134. package/dist/ip-blocklist.js.map +0 -1
  135. package/dist/json.d.ts +0 -2
  136. package/dist/json.d.ts.map +0 -1
  137. package/dist/json.js +0 -45
  138. package/dist/json.js.map +0 -1
  139. package/dist/language-detection.d.ts +0 -3
  140. package/dist/language-detection.d.ts.map +0 -1
  141. package/dist/language-detection.js +0 -355
  142. package/dist/language-detection.js.map +0 -1
  143. package/dist/markdown-cleanup.d.ts.map +0 -1
  144. package/dist/markdown-cleanup.js +0 -534
  145. package/dist/markdown-cleanup.js.map +0 -1
  146. package/dist/mcp-validator.d.ts +0 -17
  147. package/dist/mcp-validator.d.ts.map +0 -1
  148. package/dist/mcp-validator.js +0 -45
  149. package/dist/mcp-validator.js.map +0 -1
  150. package/dist/mcp.d.ts +0 -4
  151. package/dist/mcp.d.ts.map +0 -1
  152. package/dist/mcp.js.map +0 -1
  153. package/dist/observability.d.ts +0 -23
  154. package/dist/observability.d.ts.map +0 -1
  155. package/dist/observability.js +0 -238
  156. package/dist/observability.js.map +0 -1
  157. package/dist/prompts.d.ts.map +0 -1
  158. package/dist/prompts.js.map +0 -1
  159. package/dist/resources.d.ts.map +0 -1
  160. package/dist/resources.js.map +0 -1
  161. package/dist/server-tuning.d.ts +0 -15
  162. package/dist/server-tuning.d.ts.map +0 -1
  163. package/dist/server-tuning.js +0 -49
  164. package/dist/server-tuning.js.map +0 -1
  165. package/dist/server.d.ts.map +0 -1
  166. package/dist/server.js.map +0 -1
  167. package/dist/session.d.ts +0 -42
  168. package/dist/session.d.ts.map +0 -1
  169. package/dist/session.js +0 -255
  170. package/dist/session.js.map +0 -1
  171. package/dist/tasks/execution.d.ts.map +0 -1
  172. package/dist/tasks/execution.js.map +0 -1
  173. package/dist/tasks/manager.d.ts.map +0 -1
  174. package/dist/tasks/manager.js.map +0 -1
  175. package/dist/tasks/owner.d.ts.map +0 -1
  176. package/dist/tasks/owner.js.map +0 -1
  177. package/dist/timer-utils.d.ts +0 -6
  178. package/dist/timer-utils.d.ts.map +0 -1
  179. package/dist/timer-utils.js +0 -27
  180. package/dist/timer-utils.js.map +0 -1
  181. package/dist/tool-errors.d.ts +0 -12
  182. package/dist/tool-errors.d.ts.map +0 -1
  183. package/dist/tool-errors.js +0 -55
  184. package/dist/tool-errors.js.map +0 -1
  185. package/dist/tool-pipeline.d.ts.map +0 -1
  186. package/dist/tool-pipeline.js.map +0 -1
  187. package/dist/tool-progress.d.ts.map +0 -1
  188. package/dist/tool-progress.js.map +0 -1
  189. package/dist/tools.d.ts +0 -54
  190. package/dist/tools.d.ts.map +0 -1
  191. package/dist/tools.js.map +0 -1
  192. package/dist/transform/transform.d.ts.map +0 -1
  193. package/dist/transform/transform.js.map +0 -1
  194. package/dist/transform/types.d.ts.map +0 -1
  195. package/dist/transform/types.js.map +0 -1
  196. package/dist/transform/worker-pool.d.ts.map +0 -1
  197. package/dist/transform/worker-pool.js.map +0 -1
  198. package/dist/transform/workers/transform-child.d.ts.map +0 -1
  199. package/dist/transform/workers/transform-child.js.map +0 -1
  200. package/dist/transform/workers/transform-worker.d.ts.map +0 -1
  201. package/dist/transform/workers/transform-worker.js.map +0 -1
  202. package/dist/type-guards.d.ts +0 -16
  203. package/dist/type-guards.d.ts.map +0 -1
  204. package/dist/type-guards.js +0 -13
  205. package/dist/type-guards.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';
@@ -26,7 +26,5 @@ export interface ToolHandlerExtra {
26
26
  export interface ProgressReporter {
27
27
  report: (progress: number, message: string) => void;
28
28
  }
29
- export declare const FETCH_PROGRESS_TOTAL = 4;
30
29
  export declare function createProgressReporter(extra?: ToolHandlerExtra): ProgressReporter;
31
30
  export {};
32
- //# sourceMappingURL=tool-progress.d.ts.map
@@ -1,14 +1,7 @@
1
- import { getErrorMessage } from './errors.js';
2
- import { logWarn } from './observability.js';
3
- import { isObject } from './type-guards.js';
4
- /* -------------------------------------------------------------------------------------------------
5
- * Constants
6
- * ------------------------------------------------------------------------------------------------- */
7
- export const FETCH_PROGRESS_TOTAL = 4;
1
+ import { logWarn } from './core.js';
2
+ import { getErrorMessage, isObject } from './utils.js';
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,14 +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
- import { runWithRequestContext } from './observability.js';
5
- import { abortTaskExecution, emitTaskStatusNotification, handleToolCallRequest, throwTaskNotFound, toTaskSummary, withRelatedTaskMeta, } from './tasks/execution.js';
6
- import { taskManager } from './tasks/manager.js';
7
- import { isServerResult, parseHandlerExtra, resolveTaskOwnerKey, resolveToolCallContext, } from './tasks/owner.js';
8
- // Re-export public API so existing consumers (tests, other modules) keep working.
9
- export { cancelTasksForOwner, abortAllTaskExecutions, } from './tasks/execution.js';
5
+ import { abortTaskExecution, emitTaskStatusNotification, handleToolCallRequest, throwTaskNotFound, toTaskSummary, withRelatedTaskMeta, } from '../tasks/execution.js';
6
+ import { taskManager } from '../tasks/manager.js';
7
+ import { isServerResult, parseHandlerExtra, resolveTaskOwnerKey, resolveToolCallContext, } from '../tasks/owner.js';
8
+ import { hasTaskCapableTool } from '../tasks/tool-registry.js';
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
+ }
54
+ export { cancelTasksForOwner, abortAllTaskExecutions, } from '../tasks/execution.js';
10
55
  /* -------------------------------------------------------------------------------------------------
11
- * Tasks API schemas
56
+ * Task handler schemas and registration
12
57
  * ------------------------------------------------------------------------------------------------- */
13
58
  const TaskGetSchema = z
14
59
  .object({
@@ -39,9 +84,6 @@ const TaskResultSchema = z
39
84
  params: z.object({ taskId: z.string() }).loose(),
40
85
  })
41
86
  .loose();
42
- /* -------------------------------------------------------------------------------------------------
43
- * Tool call interception (tools/call) with task support
44
- * ------------------------------------------------------------------------------------------------- */
45
87
  const MIN_TASK_TTL_MS = 1_000;
46
88
  const MAX_TASK_TTL_MS = 86_400_000;
47
89
  const ExtendedCallToolRequestSchema = z
@@ -80,7 +122,11 @@ function parseExtendedCallToolRequest(request) {
80
122
  const parsed = ExtendedCallToolRequestSchema.safeParse(request);
81
123
  if (parsed.success)
82
124
  return parsed.data;
83
- throw new McpError(ErrorCode.InvalidParams, 'Invalid tool request');
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}`);
84
130
  }
85
131
  function resolveOwnerScopedExtra(extra) {
86
132
  const parsedExtra = parseHandlerExtra(extra);
@@ -89,26 +135,42 @@ function resolveOwnerScopedExtra(extra) {
89
135
  ownerKey: resolveTaskOwnerKey(parsedExtra),
90
136
  };
91
137
  }
92
- /* -------------------------------------------------------------------------------------------------
93
- * Register handlers
94
- * ------------------------------------------------------------------------------------------------- */
138
+ function getSdkCallToolHandler(server) {
139
+ const maybeHandlers = Reflect.get(server.server, '_requestHandlers');
140
+ if (!(maybeHandlers instanceof Map))
141
+ return null;
142
+ const handler = maybeHandlers.get('tools/call');
143
+ return typeof handler === 'function' ? handler : null;
144
+ }
95
145
  export function registerTaskHandlers(server) {
96
- server.server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
97
- const parsedExtra = parseHandlerExtra(extra);
98
- const context = resolveToolCallContext(parsedExtra);
99
- const requestId = context.requestId !== undefined
100
- ? String(context.requestId)
101
- : randomUUID();
102
- const sessionId = parsedExtra?.sessionId;
103
- return runWithRequestContext({
104
- requestId,
105
- operationId: requestId,
106
- ...(sessionId ? { sessionId } : {}),
107
- }, () => {
108
- const parsed = parseExtendedCallToolRequest(request);
109
- return handleToolCallRequest(server, parsed, context);
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
+ }
150
+ if (sdkCallToolHandler) {
151
+ server.server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
152
+ const parsedExtra = parseHandlerExtra(extra);
153
+ const context = resolveToolCallContext(parsedExtra);
154
+ const requestId = context.requestId !== undefined
155
+ ? String(context.requestId)
156
+ : randomUUID();
157
+ const sessionId = parsedExtra?.sessionId;
158
+ return runWithRequestContext({
159
+ requestId,
160
+ operationId: requestId,
161
+ ...(sessionId ? { sessionId } : {}),
162
+ }, () => {
163
+ const toolName = request.params.name;
164
+ // Only intercept task-capable tools managed by the local task registry.
165
+ // Delegate all other tools to the SDK handler to avoid shadowing future tools.
166
+ if (!hasTaskCapableTool(toolName)) {
167
+ return sdkCallToolHandler(request, extra);
168
+ }
169
+ const parsed = parseExtendedCallToolRequest(request);
170
+ return handleToolCallRequest(server, parsed, context);
171
+ });
110
172
  });
111
- });
173
+ }
112
174
  server.server.setRequestHandler(TaskGetSchema, (request, extra) => {
113
175
  const { taskId } = request.params;
114
176
  const { ownerKey } = resolveOwnerScopedExtra(extra);
@@ -147,6 +209,9 @@ export function registerTaskHandlers(server) {
147
209
  ...(task.statusMessage ? { statusMessage: task.statusMessage } : {}),
148
210
  });
149
211
  }
212
+ if (task.status === 'input_required') {
213
+ throw new McpError(ErrorCode.InvalidRequest, 'Task requires additional input', { taskId: task.taskId, status: 'input_required' });
214
+ }
150
215
  const result = isServerResult(task.result)
151
216
  ? task.result
152
217
  : { content: [] };
@@ -172,4 +237,3 @@ export function registerTaskHandlers(server) {
172
237
  return toTaskSummary(task);
173
238
  });
174
239
  }
175
- //# 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 {};