@j0hanz/fetch-url-mcp 1.11.4 → 1.11.6
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/http/health.js +1 -1
- package/dist/http/native.d.ts.map +1 -1
- package/dist/http/native.js +2 -6
- package/dist/lib/cache.d.ts +48 -0
- package/dist/lib/cache.d.ts.map +1 -0
- package/dist/lib/cache.js +273 -0
- package/dist/lib/core.d.ts +1 -40
- package/dist/lib/core.d.ts.map +1 -1
- package/dist/lib/core.js +2 -233
- package/dist/lib/fetch-pipeline.d.ts.map +1 -1
- package/dist/lib/fetch-pipeline.js +5 -2
- package/dist/lib/http.d.ts.map +1 -1
- package/dist/lib/http.js +77 -112
- package/dist/lib/mcp-interop.d.ts +2 -2
- package/dist/lib/mcp-interop.js +2 -2
- package/dist/resources/index.d.ts +21 -0
- package/dist/resources/index.d.ts.map +1 -1
- package/dist/resources/index.js +47 -72
- package/dist/tasks/execution.d.ts.map +1 -1
- package/dist/tasks/execution.js +18 -3
- package/dist/tasks/handlers.d.ts.map +1 -1
- package/dist/tasks/handlers.js +3 -4
- package/dist/tasks/manager.js +3 -3
- package/dist/tasks/waiters.js +1 -1
- package/dist/tools/fetch-url.d.ts.map +1 -1
- package/dist/tools/fetch-url.js +3 -6
- package/dist/transform/transform.js +1 -2
- package/package.json +1 -1
- package/dist/lib/task-handlers.d.ts +0 -11
- package/dist/lib/task-handlers.d.ts.map +0 -1
- package/dist/lib/task-handlers.js +0 -151
package/dist/tasks/handlers.js
CHANGED
|
@@ -91,15 +91,14 @@ export function registerTaskHandlers(server, options) {
|
|
|
91
91
|
throwTaskNotFound();
|
|
92
92
|
try {
|
|
93
93
|
if (task.status === 'failed') {
|
|
94
|
-
if (task.error) {
|
|
95
|
-
throw new McpError(task.error.code, task.error.message, task.error.data);
|
|
96
|
-
}
|
|
97
94
|
const failedResult = (task.result ?? null);
|
|
98
95
|
const fallback = failedResult ?? {
|
|
99
96
|
content: [
|
|
100
97
|
{
|
|
101
98
|
type: 'text',
|
|
102
|
-
text:
|
|
99
|
+
text: JSON.stringify({
|
|
100
|
+
error: task.statusMessage ?? 'Task execution failed',
|
|
101
|
+
}),
|
|
103
102
|
},
|
|
104
103
|
],
|
|
105
104
|
isError: true,
|
package/dist/tasks/manager.js
CHANGED
|
@@ -35,9 +35,9 @@ function resolveNextTaskStatus(task, updates) {
|
|
|
35
35
|
return nextStatus;
|
|
36
36
|
}
|
|
37
37
|
function normalizeTaskTtl(ttl) {
|
|
38
|
-
if (!Number.isFinite(ttl))
|
|
38
|
+
if (ttl === undefined || !Number.isFinite(ttl))
|
|
39
39
|
return DEFAULT_TTL_MS;
|
|
40
|
-
return Math.max(MIN_TTL_MS, Math.min(Math.trunc(
|
|
40
|
+
return Math.max(MIN_TTL_MS, Math.min(Math.trunc(ttl), MAX_TTL_MS));
|
|
41
41
|
}
|
|
42
42
|
class TaskManager {
|
|
43
43
|
tasks = new Map();
|
|
@@ -218,7 +218,7 @@ class TaskManager {
|
|
|
218
218
|
}
|
|
219
219
|
const anchorIndex = validTasks.findIndex((t) => t.taskId === anchorTaskId);
|
|
220
220
|
if (anchorIndex === -1) {
|
|
221
|
-
|
|
221
|
+
throw new McpError(ErrorCode.InvalidParams, 'Invalid cursor');
|
|
222
222
|
}
|
|
223
223
|
return validTasks.slice(anchorIndex + 1, anchorIndex + 1 + pageSize + 1);
|
|
224
224
|
}
|
package/dist/tasks/waiters.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-url.d.ts","sourceRoot":"","sources":["../../src/tools/fetch-url.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EACV,YAAY,EAEb,MAAM,oCAAoC,CAAC;AAE5C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAc7B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"fetch-url.d.ts","sourceRoot":"","sources":["../../src/tools/fetch-url.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EACV,YAAY,EAEb,MAAM,oCAAoC,CAAC;AAE5C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAc7B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAGL,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACtB,MAAM,uBAAuB,CAAC;AAU/B,OAAO,EACL,mBAAmB,EAIpB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAIL,KAAK,sBAAsB,EAE5B,MAAM,sBAAsB,CAAC;AAE9B,KAAK,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEzD,UAAU,gBAAgB;IACxB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IACxD,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,eAAO,MAAM,mBAAmB,cAAc,CAAC;AAwI/C,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,YAAY,GACnB,MAAM,GAAG,SAAS,CAUpB;AAED,qBAAa,oBAAoB;IAI7B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAJ1B,OAAO,CAAC,WAAW,CAA0B;gBAG1B,QAAQ,EAAE,gBAAgB,EAC1B,OAAO,EAAE,MAAM;IAGlC,WAAW,IAAI,IAAI;IAInB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI;IAO1C,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAIxC,aAAa,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI;IAIvC,OAAO,CAAC,iBAAiB;IAYzB,OAAO,CAAC,QAAQ;CAmCjB;AAuED,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,aAAa,EACpB,KAAK,CAAC,EAAE,gBAAgB,GACvB,OAAO,CAAC,gBAAgB,CAAC,CAQ3B;AAqBD,MAAM,WAAW,wBAAwB;IACvC,cAAc,EAAE,CAAC,OAAO,EAAE,sBAAsB,KAAK,IAAI,CAAC;CAC3D;AAqBD,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,wBAAwB,CAoCzE"}
|
package/dist/tools/fetch-url.js
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
|
|
2
2
|
import { config, logDebug, logError, logWarn } from '../lib/core.js';
|
|
3
3
|
import { finalizeInlineMarkdown, markdownTransform, parseCachedMarkdownResult, performSharedFetch, serializeMarkdownResult, withSignal, } from '../lib/fetch-pipeline.js';
|
|
4
|
-
import { handleToolError } from '../lib/mcp-interop.js';
|
|
5
|
-
import {
|
|
6
|
-
import { composeAbortSignal, isAbortError, parseUrlOrNull, toError, } from '../lib/utils.js';
|
|
7
|
-
import { isObject } from '../lib/utils.js';
|
|
4
|
+
import { createProgressReporter, handleToolError, } from '../lib/mcp-interop.js';
|
|
5
|
+
import { composeAbortSignal, isAbortError, isObject, parseUrlOrNull, toError, } from '../lib/utils.js';
|
|
8
6
|
import { formatZodError } from '../lib/zod.js';
|
|
9
7
|
import { fetchUrlInputSchema, fetchUrlOutputSchema, normalizeExtractedMetadata, normalizePageTitle, } from '../schemas.js';
|
|
10
8
|
import { withRequestContextIfMissing } from '../tasks/owner.js';
|
|
@@ -287,10 +285,9 @@ export function registerTools(server) {
|
|
|
287
285
|
execution: { taskSupport: 'optional' },
|
|
288
286
|
icons: [TOOL_ICON],
|
|
289
287
|
}, withRequestContextIfMissing(TOOL_DEFINITION.handler));
|
|
290
|
-
const registeredToolRecord = registeredTool;
|
|
291
288
|
const updateTaskSupport = (support) => {
|
|
292
289
|
setTaskCapableToolSupport(FETCH_URL_TOOL_NAME, support);
|
|
293
|
-
|
|
290
|
+
registeredTool.execution = { taskSupport: support };
|
|
294
291
|
};
|
|
295
292
|
updateTaskSupport('optional');
|
|
296
293
|
return { setTaskSupport: updateTaskSupport };
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import diagnosticsChannel from 'node:diagnostics_channel';
|
|
2
2
|
import { isProbablyReaderable, Readability } from '@mozilla/readability';
|
|
3
3
|
import { parseHTML } from 'linkedom';
|
|
4
|
-
import { config } from '../lib/core.js';
|
|
5
|
-
import { getOperationId, getRequestId, logDebug, logError, logInfo, logWarn, redactUrl, } from '../lib/core.js';
|
|
4
|
+
import { config, getOperationId, getRequestId, logDebug, logError, logInfo, logWarn, redactUrl, } from '../lib/core.js';
|
|
6
5
|
import { isRawTextContentUrl } from '../lib/http.js';
|
|
7
6
|
import { composeAbortSignal, FetchError, getErrorMessage, getUtf8ByteLength, isAsciiOnly, isObject, throwIfAborted, toError, trimDanglingTagFragment, truncateToUtf8Boundary, } from '../lib/utils.js';
|
|
8
7
|
import { evaluateArticleContent, extractNoscriptImages, getVisibleTextLength, normalizeTabContent, prepareDocumentForMarkdown, removeNoiseFromHtml, serializeDocumentForMarkdown, stripDocsControls, stripScreenReaderText, surfaceCodeEditorContent, } from './dom-prep.js';
|
package/package.json
CHANGED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { type McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
-
export { cancelTasksForOwner, abortAllTaskExecutions, } from '../tasks/execution.js';
|
|
3
|
-
interface TaskHandlerRegistrationOptions {
|
|
4
|
-
requireInterception?: boolean;
|
|
5
|
-
}
|
|
6
|
-
interface TaskHandlerRegistrationResult {
|
|
7
|
-
interceptedToolsCall: boolean;
|
|
8
|
-
taskCapableToolsRegistered: boolean;
|
|
9
|
-
}
|
|
10
|
-
export declare function registerTaskHandlers(server: McpServer, options?: TaskHandlerRegistrationOptions): TaskHandlerRegistrationResult;
|
|
11
|
-
//# sourceMappingURL=task-handlers.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"task-handlers.d.ts","sourceRoot":"","sources":["../../src/lib/task-handlers.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAkCzE,OAAO,EACL,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,uBAAuB,CAAC;AA4D/B,UAAU,8BAA8B;IACtC,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,UAAU,6BAA6B;IACrC,oBAAoB,EAAE,OAAO,CAAC;IAC9B,0BAA0B,EAAE,OAAO,CAAC;CACrC;AACD,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,SAAS,EACjB,OAAO,CAAC,EAAE,8BAA8B,GACvC,6BAA6B,CA+J/B"}
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
import { randomUUID } from 'node:crypto';
|
|
2
|
-
import {} from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
-
import { CallToolRequestSchema, ErrorCode, McpError, } from '@modelcontextprotocol/sdk/types.js';
|
|
4
|
-
import { z } from 'zod';
|
|
5
|
-
import { parseExtendedCallToolRequest, withRelatedTaskMeta, } from '../tasks/call-contract.js';
|
|
6
|
-
import { abortTaskExecution, emitTaskStatusNotification, handleToolCallRequest, throwTaskNotFound, toTaskSummary, } from '../tasks/execution.js';
|
|
7
|
-
import { taskManager } from '../tasks/manager.js';
|
|
8
|
-
import { isServerResult, parseHandlerExtra, resolveTaskOwnerKey, resolveToolCallContext, } from '../tasks/owner.js';
|
|
9
|
-
import { hasRegisteredTaskCapableTools, hasTaskCapableTool, } from '../tasks/registry.js';
|
|
10
|
-
import { logWarn, runWithRequestContext } from './core.js';
|
|
11
|
-
import { getSdkCallToolHandler } from './mcp-interop.js';
|
|
12
|
-
export { cancelTasksForOwner, abortAllTaskExecutions, } from '../tasks/execution.js';
|
|
13
|
-
/* -------------------------------------------------------------------------------------------------
|
|
14
|
-
* Task handler schemas and registration
|
|
15
|
-
* ------------------------------------------------------------------------------------------------- */
|
|
16
|
-
const TaskGetSchema = z.looseObject({
|
|
17
|
-
method: z.literal('tasks/get', 'Expected "tasks/get"'),
|
|
18
|
-
params: z.looseObject({ taskId: z.string('Expected string') }, 'Expected object'),
|
|
19
|
-
}, 'Invalid request');
|
|
20
|
-
const TaskListSchema = z.looseObject({
|
|
21
|
-
method: z.literal('tasks/list', 'Expected "tasks/list"'),
|
|
22
|
-
params: z
|
|
23
|
-
.looseObject({
|
|
24
|
-
cursor: z.string('Expected string').optional(),
|
|
25
|
-
}, 'Expected object')
|
|
26
|
-
.optional(),
|
|
27
|
-
}, 'Invalid request');
|
|
28
|
-
const TaskCancelSchema = z.looseObject({
|
|
29
|
-
method: z.literal('tasks/cancel', 'Expected "tasks/cancel"'),
|
|
30
|
-
params: z.looseObject({ taskId: z.string('Expected string') }, 'Expected object'),
|
|
31
|
-
}, 'Invalid request');
|
|
32
|
-
const TaskResultSchema = z.looseObject({
|
|
33
|
-
method: z.literal('tasks/result', 'Expected "tasks/result"'),
|
|
34
|
-
params: z.looseObject({ taskId: z.string('Expected string') }, 'Expected object'),
|
|
35
|
-
}, 'Invalid request');
|
|
36
|
-
function resolveOwnerScopedExtra(extra) {
|
|
37
|
-
const parsedExtra = parseHandlerExtra(extra);
|
|
38
|
-
return {
|
|
39
|
-
parsedExtra,
|
|
40
|
-
ownerKey: resolveTaskOwnerKey(parsedExtra),
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
export function registerTaskHandlers(server, options) {
|
|
44
|
-
const sdkCallToolHandler = getSdkCallToolHandler(server);
|
|
45
|
-
const taskCapableToolsRegistered = hasRegisteredTaskCapableTools();
|
|
46
|
-
const requireInterception = options?.requireInterception ?? true;
|
|
47
|
-
if (!sdkCallToolHandler) {
|
|
48
|
-
if (taskCapableToolsRegistered && requireInterception) {
|
|
49
|
-
throw new Error('Task-capable tools are registered but SDK tools/call interception is unavailable. Upgrade compatibility or disable strict interception with TASKS_REQUIRE_INTERCEPTION=false.');
|
|
50
|
-
}
|
|
51
|
-
logWarn('Task call interception disabled: SDK tools/call handler unavailable; task-capable tools require MCP SDK compatibility update', { sdkVersion: 'unknown' });
|
|
52
|
-
}
|
|
53
|
-
if (sdkCallToolHandler) {
|
|
54
|
-
server.server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
|
|
55
|
-
const parsedExtra = parseHandlerExtra(extra);
|
|
56
|
-
const requestId = parsedExtra?.requestId !== undefined
|
|
57
|
-
? String(parsedExtra.requestId)
|
|
58
|
-
: randomUUID();
|
|
59
|
-
return runWithRequestContext({
|
|
60
|
-
requestId,
|
|
61
|
-
operationId: requestId,
|
|
62
|
-
...(parsedExtra?.sessionId
|
|
63
|
-
? { sessionId: parsedExtra.sessionId }
|
|
64
|
-
: {}),
|
|
65
|
-
}, () => {
|
|
66
|
-
const toolName = request.params.name;
|
|
67
|
-
// Only intercept task-capable tools managed by the local task registry.
|
|
68
|
-
// Delegate all other tools to the SDK handler to avoid shadowing future tools.
|
|
69
|
-
if (!hasTaskCapableTool(toolName)) {
|
|
70
|
-
return sdkCallToolHandler(request, extra);
|
|
71
|
-
}
|
|
72
|
-
const parsed = parseExtendedCallToolRequest(request);
|
|
73
|
-
const context = resolveToolCallContext(parsedExtra, parsed.params._meta);
|
|
74
|
-
return handleToolCallRequest(server, parsed, context);
|
|
75
|
-
});
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
server.server.setRequestHandler(TaskGetSchema, (request, extra) => {
|
|
79
|
-
const { taskId } = request.params;
|
|
80
|
-
const { ownerKey } = resolveOwnerScopedExtra(extra);
|
|
81
|
-
const task = taskManager.getTask(taskId, ownerKey);
|
|
82
|
-
if (!task)
|
|
83
|
-
throwTaskNotFound();
|
|
84
|
-
return toTaskSummary(task);
|
|
85
|
-
});
|
|
86
|
-
server.server.setRequestHandler(TaskResultSchema, async (request, extra) => {
|
|
87
|
-
const { taskId } = request.params;
|
|
88
|
-
const { parsedExtra, ownerKey } = resolveOwnerScopedExtra(extra);
|
|
89
|
-
const task = await taskManager.waitForTerminalTask(taskId, ownerKey, parsedExtra?.signal);
|
|
90
|
-
if (!task)
|
|
91
|
-
throwTaskNotFound();
|
|
92
|
-
try {
|
|
93
|
-
if (task.status === 'failed') {
|
|
94
|
-
if (task.error) {
|
|
95
|
-
throw new McpError(task.error.code, task.error.message, task.error.data);
|
|
96
|
-
}
|
|
97
|
-
const failedResult = (task.result ?? null);
|
|
98
|
-
const fallback = failedResult ?? {
|
|
99
|
-
content: [
|
|
100
|
-
{
|
|
101
|
-
type: 'text',
|
|
102
|
-
text: task.statusMessage ?? 'Task execution failed',
|
|
103
|
-
},
|
|
104
|
-
],
|
|
105
|
-
isError: true,
|
|
106
|
-
};
|
|
107
|
-
return withRelatedTaskMeta(fallback, task.taskId);
|
|
108
|
-
}
|
|
109
|
-
if (task.status === 'cancelled') {
|
|
110
|
-
throw new McpError(ErrorCode.InvalidRequest, 'Task was cancelled', {
|
|
111
|
-
taskId: task.taskId,
|
|
112
|
-
status: 'cancelled',
|
|
113
|
-
...(task.statusMessage ? { statusMessage: task.statusMessage } : {}),
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
const result = isServerResult(task.result)
|
|
117
|
-
? task.result
|
|
118
|
-
: { content: [] };
|
|
119
|
-
return withRelatedTaskMeta(result, task.taskId);
|
|
120
|
-
}
|
|
121
|
-
finally {
|
|
122
|
-
// Shrink TTL only after the result has been fully constructed and
|
|
123
|
-
// is about to be delivered — avoids premature expiry if result
|
|
124
|
-
// construction throws.
|
|
125
|
-
taskManager.shrinkTtlAfterDelivery(taskId);
|
|
126
|
-
}
|
|
127
|
-
});
|
|
128
|
-
server.server.setRequestHandler(TaskListSchema, (request, extra) => {
|
|
129
|
-
const { ownerKey } = resolveOwnerScopedExtra(extra);
|
|
130
|
-
const cursor = request.params?.cursor;
|
|
131
|
-
const { tasks, nextCursor } = taskManager.listTasks(cursor === undefined ? { ownerKey } : { ownerKey, cursor });
|
|
132
|
-
return {
|
|
133
|
-
tasks: tasks.map((task) => toTaskSummary(task)),
|
|
134
|
-
nextCursor,
|
|
135
|
-
};
|
|
136
|
-
});
|
|
137
|
-
server.server.setRequestHandler(TaskCancelSchema, (request, extra) => {
|
|
138
|
-
const { taskId } = request.params;
|
|
139
|
-
const { ownerKey } = resolveOwnerScopedExtra(extra);
|
|
140
|
-
const task = taskManager.cancelTask(taskId, ownerKey);
|
|
141
|
-
if (!task)
|
|
142
|
-
throwTaskNotFound();
|
|
143
|
-
abortTaskExecution(taskId);
|
|
144
|
-
emitTaskStatusNotification(server, task);
|
|
145
|
-
return toTaskSummary(task);
|
|
146
|
-
});
|
|
147
|
-
return {
|
|
148
|
-
interceptedToolsCall: sdkCallToolHandler !== null,
|
|
149
|
-
taskCapableToolsRegistered,
|
|
150
|
-
};
|
|
151
|
-
}
|