@j0hanz/fetch-url-mcp 1.10.2 → 1.10.4
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/native.d.ts.map +1 -1
- package/dist/http/native.js +20 -26
- package/dist/http/session-teardown.d.ts +17 -0
- package/dist/http/session-teardown.d.ts.map +1 -0
- package/dist/http/session-teardown.js +30 -0
- package/dist/lib/code-lang.d.ts.map +1 -1
- package/dist/lib/code-lang.js +2 -8
- package/dist/lib/core.d.ts.map +1 -1
- package/dist/lib/core.js +2 -0
- package/dist/lib/dom-prep.d.ts +2 -0
- package/dist/lib/dom-prep.d.ts.map +1 -1
- package/dist/lib/dom-prep.js +150 -139
- package/dist/lib/md-cleanup.d.ts.map +1 -1
- package/dist/lib/md-cleanup.js +53 -20
- package/dist/lib/progress.d.ts.map +1 -1
- package/dist/lib/progress.js +59 -32
- package/dist/lib/sdk-interop.d.ts +8 -0
- package/dist/lib/sdk-interop.d.ts.map +1 -0
- package/dist/lib/sdk-interop.js +73 -0
- package/dist/lib/task-handlers.d.ts +0 -2
- package/dist/lib/task-handlers.d.ts.map +1 -1
- package/dist/lib/task-handlers.js +9 -94
- package/dist/resources/index.js +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +10 -3
- package/dist/tasks/call-contract.d.ts +25 -0
- package/dist/tasks/call-contract.d.ts.map +1 -0
- package/dist/tasks/call-contract.js +58 -0
- package/dist/tasks/cursor-codec.d.ts +5 -0
- package/dist/tasks/cursor-codec.d.ts.map +1 -0
- package/dist/tasks/cursor-codec.js +41 -0
- package/dist/tasks/execution.d.ts +1 -20
- package/dist/tasks/execution.d.ts.map +1 -1
- package/dist/tasks/execution.js +7 -32
- package/dist/tasks/manager.d.ts +1 -5
- package/dist/tasks/manager.d.ts.map +1 -1
- package/dist/tasks/manager.js +16 -144
- package/dist/tasks/owner.d.ts +12 -2
- package/dist/tasks/owner.d.ts.map +1 -1
- package/dist/tasks/owner.js +52 -3
- package/dist/tasks/tool-registry.d.ts +1 -0
- package/dist/tasks/tool-registry.d.ts.map +1 -1
- package/dist/tasks/waiters.d.ts +27 -0
- package/dist/tasks/waiters.d.ts.map +1 -0
- package/dist/tasks/waiters.js +113 -0
- package/dist/tools/fetch-url-progress.d.ts +17 -0
- package/dist/tools/fetch-url-progress.d.ts.map +1 -0
- package/dist/tools/fetch-url-progress.js +78 -0
- package/dist/tools/fetch-url.d.ts +5 -9
- package/dist/tools/fetch-url.d.ts.map +1 -1
- package/dist/tools/fetch-url.js +43 -96
- package/dist/transform/next-flight.d.ts +2 -0
- package/dist/transform/next-flight.d.ts.map +1 -0
- package/dist/transform/next-flight.js +285 -0
- package/dist/transform/title-policy.d.ts +12 -0
- package/dist/transform/title-policy.d.ts.map +1 -0
- package/dist/transform/title-policy.js +85 -0
- package/dist/transform/transform.d.ts.map +1 -1
- package/dist/transform/transform.js +62 -475
- package/package.json +4 -4
- package/dist/tools/index.d.ts +0 -3
- package/dist/tools/index.d.ts.map +0 -1
- package/dist/tools/index.js +0 -4
package/dist/lib/progress.js
CHANGED
|
@@ -19,6 +19,9 @@ class ToolProgressReporter {
|
|
|
19
19
|
canReportProgress;
|
|
20
20
|
isTerminal = false;
|
|
21
21
|
lastProgress = -1;
|
|
22
|
+
lastMessage;
|
|
23
|
+
pendingNotification;
|
|
24
|
+
isDispatching = false;
|
|
22
25
|
constructor(token, sendNotification, relatedTaskMeta, onProgress, canReportProgress) {
|
|
23
26
|
this.token = token;
|
|
24
27
|
this.sendNotification = sendNotification;
|
|
@@ -50,13 +53,13 @@ class ToolProgressReporter {
|
|
|
50
53
|
return;
|
|
51
54
|
const effectiveProgress = Math.max(progress, this.lastProgress);
|
|
52
55
|
const isIncreasing = effectiveProgress > this.lastProgress;
|
|
56
|
+
const isMessageChanged = message !== this.lastMessage;
|
|
53
57
|
this.lastProgress = effectiveProgress;
|
|
58
|
+
this.lastMessage = message;
|
|
54
59
|
if (effectiveProgress >= FETCH_PROGRESS_TOTAL) {
|
|
55
60
|
this.isTerminal = true;
|
|
56
61
|
}
|
|
57
|
-
|
|
58
|
-
// task status updates (onProgress drives updateWorkingTaskStatus in task mode).
|
|
59
|
-
if (isIncreasing && this.onProgress) {
|
|
62
|
+
if ((isIncreasing || isMessageChanged) && this.onProgress) {
|
|
60
63
|
try {
|
|
61
64
|
this.onProgress(effectiveProgress, message);
|
|
62
65
|
}
|
|
@@ -70,44 +73,68 @@ class ToolProgressReporter {
|
|
|
70
73
|
}
|
|
71
74
|
if (!isIncreasing || this.token === null || !this.sendNotification)
|
|
72
75
|
return;
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
76
|
+
this.pendingNotification = this.createProgressNotification(this.token, effectiveProgress, message);
|
|
77
|
+
this.flushNotifications();
|
|
78
|
+
}
|
|
79
|
+
flushNotifications() {
|
|
80
|
+
if (this.isDispatching || !this.sendNotification)
|
|
81
|
+
return;
|
|
82
|
+
this.isDispatching = true;
|
|
77
83
|
void (async () => {
|
|
78
|
-
let timeoutId;
|
|
79
|
-
const timeoutPromise = new Promise((resolve) => {
|
|
80
|
-
timeoutId = setTimeout(() => {
|
|
81
|
-
resolve({ timeout: true });
|
|
82
|
-
}, PROGRESS_NOTIFICATION_TIMEOUT_MS);
|
|
83
|
-
timeoutId.unref();
|
|
84
|
-
});
|
|
85
84
|
try {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
});
|
|
85
|
+
while (this.pendingNotification) {
|
|
86
|
+
if (this.canReportProgress && !this.canReportProgress()) {
|
|
87
|
+
this.pendingNotification = undefined;
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const notification = this.pendingNotification;
|
|
91
|
+
this.pendingNotification = undefined;
|
|
92
|
+
await this.sendWithTimeout(notification);
|
|
95
93
|
}
|
|
96
94
|
}
|
|
97
|
-
catch (error) {
|
|
98
|
-
logWarn('Failed to send progress notification', {
|
|
99
|
-
error: getErrorMessage(error),
|
|
100
|
-
progress: effectiveProgress,
|
|
101
|
-
message,
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
95
|
finally {
|
|
105
|
-
|
|
106
|
-
|
|
96
|
+
this.isDispatching = false;
|
|
97
|
+
if (this.pendingNotification) {
|
|
98
|
+
this.flushNotifications();
|
|
107
99
|
}
|
|
108
100
|
}
|
|
109
101
|
})();
|
|
110
102
|
}
|
|
103
|
+
async sendWithTimeout(notification) {
|
|
104
|
+
if (!this.sendNotification)
|
|
105
|
+
return;
|
|
106
|
+
let timeoutId;
|
|
107
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
108
|
+
timeoutId = setTimeout(() => {
|
|
109
|
+
resolve({ timeout: true });
|
|
110
|
+
}, PROGRESS_NOTIFICATION_TIMEOUT_MS);
|
|
111
|
+
timeoutId.unref();
|
|
112
|
+
});
|
|
113
|
+
try {
|
|
114
|
+
const outcome = await Promise.race([
|
|
115
|
+
this.sendNotification(notification).then(() => ({ ok: true })),
|
|
116
|
+
timeoutPromise,
|
|
117
|
+
]);
|
|
118
|
+
if ('timeout' in outcome) {
|
|
119
|
+
logWarn('Progress notification timed out', {
|
|
120
|
+
progress: notification.params.progress,
|
|
121
|
+
message: notification.params.message,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
logWarn('Failed to send progress notification', {
|
|
127
|
+
error: getErrorMessage(error),
|
|
128
|
+
progress: notification.params.progress,
|
|
129
|
+
message: notification.params.message,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
finally {
|
|
133
|
+
if (timeoutId) {
|
|
134
|
+
clearTimeout(timeoutId);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
111
138
|
createProgressNotification(token, progress, message) {
|
|
112
139
|
return {
|
|
113
140
|
method: 'notifications/progress',
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
type CleanupCallback = () => void;
|
|
3
|
+
type RequestHandlerFn = (request: unknown, extra?: unknown) => Promise<unknown>;
|
|
4
|
+
export declare function registerServerLifecycleCleanup(server: McpServer, callback: CleanupCallback): void;
|
|
5
|
+
export declare function getSdkCallToolHandler(server: McpServer): RequestHandlerFn | null;
|
|
6
|
+
export declare function setTaskToolCallCapability(server: McpServer, enabled: boolean): void;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=sdk-interop.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sdk-interop.d.ts","sourceRoot":"","sources":["../../src/lib/sdk-interop.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKzE,KAAK,eAAe,GAAG,MAAM,IAAI,CAAC;AAClC,KAAK,gBAAgB,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AA8ChF,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,SAAS,EACjB,QAAQ,EAAE,eAAe,GACxB,IAAI,CAGN;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,SAAS,GAChB,gBAAgB,GAAG,IAAI,CAMzB;AAED,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,OAAO,GACf,IAAI,CAoBN"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { logWarn } from './core.js';
|
|
2
|
+
import { isObject } from './utils.js';
|
|
3
|
+
const patchedCleanupServers = new WeakSet();
|
|
4
|
+
const serverCleanupCallbacks = new WeakMap();
|
|
5
|
+
function getServerCleanupCallbackSet(server) {
|
|
6
|
+
let callbacks = serverCleanupCallbacks.get(server);
|
|
7
|
+
if (!callbacks) {
|
|
8
|
+
callbacks = new Set();
|
|
9
|
+
serverCleanupCallbacks.set(server, callbacks);
|
|
10
|
+
}
|
|
11
|
+
return callbacks;
|
|
12
|
+
}
|
|
13
|
+
function drainServerCleanupCallbacks(server) {
|
|
14
|
+
const callbacks = serverCleanupCallbacks.get(server);
|
|
15
|
+
if (!callbacks || callbacks.size === 0)
|
|
16
|
+
return;
|
|
17
|
+
const pending = [...callbacks];
|
|
18
|
+
callbacks.clear();
|
|
19
|
+
for (const callback of pending) {
|
|
20
|
+
try {
|
|
21
|
+
callback();
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
logWarn('Server cleanup callback failed', { error });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function ensureServerCleanupHooks(server) {
|
|
29
|
+
if (patchedCleanupServers.has(server))
|
|
30
|
+
return;
|
|
31
|
+
patchedCleanupServers.add(server);
|
|
32
|
+
const originalOnClose = server.server.onclose;
|
|
33
|
+
server.server.onclose = () => {
|
|
34
|
+
drainServerCleanupCallbacks(server);
|
|
35
|
+
originalOnClose?.();
|
|
36
|
+
};
|
|
37
|
+
const originalClose = server.close.bind(server);
|
|
38
|
+
server.close = async () => {
|
|
39
|
+
drainServerCleanupCallbacks(server);
|
|
40
|
+
await originalClose();
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export function registerServerLifecycleCleanup(server, callback) {
|
|
44
|
+
ensureServerCleanupHooks(server);
|
|
45
|
+
getServerCleanupCallbackSet(server).add(callback);
|
|
46
|
+
}
|
|
47
|
+
export function getSdkCallToolHandler(server) {
|
|
48
|
+
const maybeHandlers = Reflect.get(server.server, '_requestHandlers');
|
|
49
|
+
if (!(maybeHandlers instanceof Map))
|
|
50
|
+
return null;
|
|
51
|
+
const handler = maybeHandlers.get('tools/call');
|
|
52
|
+
return typeof handler === 'function' ? handler : null;
|
|
53
|
+
}
|
|
54
|
+
export function setTaskToolCallCapability(server, enabled) {
|
|
55
|
+
const capabilities = Reflect.get(server.server, '_capabilities');
|
|
56
|
+
if (!isObject(capabilities))
|
|
57
|
+
return;
|
|
58
|
+
const tasks = isObject(capabilities.tasks)
|
|
59
|
+
? capabilities.tasks
|
|
60
|
+
: undefined;
|
|
61
|
+
if (!tasks)
|
|
62
|
+
return;
|
|
63
|
+
const requests = isObject(tasks.requests)
|
|
64
|
+
? tasks.requests
|
|
65
|
+
: undefined;
|
|
66
|
+
if (!requests)
|
|
67
|
+
return;
|
|
68
|
+
if (enabled) {
|
|
69
|
+
requests.tools = { call: {} };
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
delete requests.tools;
|
|
73
|
+
}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
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
2
|
export { cancelTasksForOwner, abortAllTaskExecutions, } from '../tasks/execution.js';
|
|
5
3
|
interface TaskHandlerRegistrationOptions {
|
|
6
4
|
requireInterception?: boolean;
|
|
@@ -1 +1 @@
|
|
|
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;
|
|
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;AAoC/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,CA0J/B"}
|
|
@@ -2,56 +2,13 @@ import { randomUUID } from 'node:crypto';
|
|
|
2
2
|
import {} from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
3
|
import { CallToolRequestSchema, ErrorCode, McpError, } from '@modelcontextprotocol/sdk/types.js';
|
|
4
4
|
import { z } from 'zod';
|
|
5
|
-
import {
|
|
5
|
+
import { parseExtendedCallToolRequest, withRelatedTaskMeta, } from '../tasks/call-contract.js';
|
|
6
|
+
import { abortTaskExecution, emitTaskStatusNotification, handleToolCallRequest, throwTaskNotFound, toTaskSummary, } from '../tasks/execution.js';
|
|
6
7
|
import { taskManager } from '../tasks/manager.js';
|
|
7
8
|
import { isServerResult, parseHandlerExtra, resolveTaskOwnerKey, resolveToolCallContext, } from '../tasks/owner.js';
|
|
8
9
|
import { hasRegisteredTaskCapableTools, hasTaskCapableTool, } from '../tasks/tool-registry.js';
|
|
9
10
|
import { logWarn, runWithRequestContext } from './core.js';
|
|
10
|
-
import {
|
|
11
|
-
const patchedCleanupServers = new WeakSet();
|
|
12
|
-
const serverCleanupCallbacks = new WeakMap();
|
|
13
|
-
function getServerCleanupCallbackSet(server) {
|
|
14
|
-
let callbacks = serverCleanupCallbacks.get(server);
|
|
15
|
-
if (!callbacks) {
|
|
16
|
-
callbacks = new Set();
|
|
17
|
-
serverCleanupCallbacks.set(server, callbacks);
|
|
18
|
-
}
|
|
19
|
-
return callbacks;
|
|
20
|
-
}
|
|
21
|
-
function drainServerCleanupCallbacks(server) {
|
|
22
|
-
const callbacks = serverCleanupCallbacks.get(server);
|
|
23
|
-
if (!callbacks || callbacks.size === 0)
|
|
24
|
-
return;
|
|
25
|
-
const pending = [...callbacks];
|
|
26
|
-
callbacks.clear();
|
|
27
|
-
for (const callback of pending) {
|
|
28
|
-
try {
|
|
29
|
-
callback();
|
|
30
|
-
}
|
|
31
|
-
catch (error) {
|
|
32
|
-
logWarn('Server cleanup callback failed', { error });
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
function ensureServerCleanupHooks(server) {
|
|
37
|
-
if (patchedCleanupServers.has(server))
|
|
38
|
-
return;
|
|
39
|
-
patchedCleanupServers.add(server);
|
|
40
|
-
const originalOnClose = server.server.onclose;
|
|
41
|
-
server.server.onclose = () => {
|
|
42
|
-
drainServerCleanupCallbacks(server);
|
|
43
|
-
originalOnClose?.();
|
|
44
|
-
};
|
|
45
|
-
const originalClose = server.close.bind(server);
|
|
46
|
-
server.close = async () => {
|
|
47
|
-
drainServerCleanupCallbacks(server);
|
|
48
|
-
await originalClose();
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
export function registerServerLifecycleCleanup(server, callback) {
|
|
52
|
-
ensureServerCleanupHooks(server);
|
|
53
|
-
getServerCleanupCallbackSet(server).add(callback);
|
|
54
|
-
}
|
|
11
|
+
import { getSdkCallToolHandler } from './sdk-interop.js';
|
|
55
12
|
export { cancelTasksForOwner, abortAllTaskExecutions, } from '../tasks/execution.js';
|
|
56
13
|
/* -------------------------------------------------------------------------------------------------
|
|
57
14
|
* Task handler schemas and registration
|
|
@@ -76,41 +33,6 @@ const TaskResultSchema = z.looseObject({
|
|
|
76
33
|
method: z.literal('tasks/result'),
|
|
77
34
|
params: z.looseObject({ taskId: z.string() }),
|
|
78
35
|
});
|
|
79
|
-
const MIN_TASK_TTL_MS = 1_000;
|
|
80
|
-
const MAX_TASK_TTL_MS = 86_400_000;
|
|
81
|
-
const ExtendedCallToolRequestSchema = z.looseObject({
|
|
82
|
-
method: z.literal('tools/call'),
|
|
83
|
-
params: z.strictObject({
|
|
84
|
-
name: z.string().min(1),
|
|
85
|
-
arguments: z.record(z.string(), z.unknown()).optional(),
|
|
86
|
-
task: z
|
|
87
|
-
.strictObject({
|
|
88
|
-
ttl: z
|
|
89
|
-
.number()
|
|
90
|
-
.int()
|
|
91
|
-
.min(MIN_TASK_TTL_MS)
|
|
92
|
-
.max(MAX_TASK_TTL_MS)
|
|
93
|
-
.optional(),
|
|
94
|
-
})
|
|
95
|
-
.optional(),
|
|
96
|
-
_meta: z
|
|
97
|
-
.looseObject({
|
|
98
|
-
progressToken: z.union([z.string(), z.number()]).optional(),
|
|
99
|
-
'io.modelcontextprotocol/related-task': z
|
|
100
|
-
.strictObject({
|
|
101
|
-
taskId: z.string(),
|
|
102
|
-
})
|
|
103
|
-
.optional(),
|
|
104
|
-
})
|
|
105
|
-
.optional(),
|
|
106
|
-
}),
|
|
107
|
-
});
|
|
108
|
-
function parseExtendedCallToolRequest(request) {
|
|
109
|
-
const parsed = ExtendedCallToolRequestSchema.safeParse(request);
|
|
110
|
-
if (parsed.success)
|
|
111
|
-
return parsed.data;
|
|
112
|
-
throw new McpError(ErrorCode.InvalidParams, `Invalid tool request params: ${formatZodError(parsed.error)}`);
|
|
113
|
-
}
|
|
114
36
|
function resolveOwnerScopedExtra(extra) {
|
|
115
37
|
const parsedExtra = parseHandlerExtra(extra);
|
|
116
38
|
return {
|
|
@@ -118,14 +40,6 @@ function resolveOwnerScopedExtra(extra) {
|
|
|
118
40
|
ownerKey: resolveTaskOwnerKey(parsedExtra),
|
|
119
41
|
};
|
|
120
42
|
}
|
|
121
|
-
function getSdkCallToolHandler(server) {
|
|
122
|
-
// S-2: see tests/sdk-compat-guard.test.ts
|
|
123
|
-
const maybeHandlers = Reflect.get(server.server, '_requestHandlers');
|
|
124
|
-
if (!(maybeHandlers instanceof Map))
|
|
125
|
-
return null;
|
|
126
|
-
const handler = maybeHandlers.get('tools/call');
|
|
127
|
-
return typeof handler === 'function' ? handler : null;
|
|
128
|
-
}
|
|
129
43
|
export function registerTaskHandlers(server, options) {
|
|
130
44
|
const sdkCallToolHandler = getSdkCallToolHandler(server);
|
|
131
45
|
const taskCapableToolsRegistered = hasRegisteredTaskCapableTools();
|
|
@@ -139,15 +53,15 @@ export function registerTaskHandlers(server, options) {
|
|
|
139
53
|
if (sdkCallToolHandler) {
|
|
140
54
|
server.server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
|
|
141
55
|
const parsedExtra = parseHandlerExtra(extra);
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
? String(context.requestId)
|
|
56
|
+
const requestId = parsedExtra?.requestId !== undefined
|
|
57
|
+
? String(parsedExtra.requestId)
|
|
145
58
|
: randomUUID();
|
|
146
|
-
const sessionId = parsedExtra?.sessionId;
|
|
147
59
|
return runWithRequestContext({
|
|
148
60
|
requestId,
|
|
149
61
|
operationId: requestId,
|
|
150
|
-
...(sessionId
|
|
62
|
+
...(parsedExtra?.sessionId
|
|
63
|
+
? { sessionId: parsedExtra.sessionId }
|
|
64
|
+
: {}),
|
|
151
65
|
}, () => {
|
|
152
66
|
const toolName = request.params.name;
|
|
153
67
|
// Only intercept task-capable tools managed by the local task registry.
|
|
@@ -156,6 +70,7 @@ export function registerTaskHandlers(server, options) {
|
|
|
156
70
|
return sdkCallToolHandler(request, extra);
|
|
157
71
|
}
|
|
158
72
|
const parsed = parseExtendedCallToolRequest(request);
|
|
73
|
+
const context = resolveToolCallContext(parsedExtra, parsed.params._meta);
|
|
159
74
|
return handleToolCallRequest(server, parsed, context);
|
|
160
75
|
});
|
|
161
76
|
});
|
package/dist/resources/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { ResourceTemplate, } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
|
2
2
|
import { ErrorCode, McpError, SubscribeRequestSchema, UnsubscribeRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
3
3
|
import { get as getCacheEntry, getEntryMeta, keys as listCacheKeys, onCacheUpdate, parseCacheKey, } from '../lib/core.js';
|
|
4
4
|
import { logWarn } from '../lib/core.js';
|
|
5
|
-
import { registerServerLifecycleCleanup } from '../lib/
|
|
5
|
+
import { registerServerLifecycleCleanup } from '../lib/sdk-interop.js';
|
|
6
6
|
import { buildOptionalIcons } from '../lib/types.js';
|
|
7
7
|
import { isObject } from '../lib/utils.js';
|
|
8
8
|
import { parseCachedPayload, resolveCachedPayloadContent } from '../schemas.js';
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA0GpE,wBAAsB,eAAe,IAAI,OAAO,CAAC,SAAS,CAAC,CAE1D;AAiDD,wBAAsB,6BAA6B,IAAI,OAAO,CAAC,SAAS,CAAC,CAExE;AAkFD,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAMtD"}
|
package/dist/server.js
CHANGED
|
@@ -5,12 +5,13 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
|
|
|
5
5
|
import { SetLevelRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
6
6
|
import { config } from './lib/core.js';
|
|
7
7
|
import { getSessionId, logError, logInfo, setLogLevel, setMcpServer, } from './lib/core.js';
|
|
8
|
+
import { setTaskToolCallCapability } from './lib/sdk-interop.js';
|
|
8
9
|
import { abortAllTaskExecutions, registerTaskHandlers, } from './lib/task-handlers.js';
|
|
9
10
|
import { toError } from './lib/utils.js';
|
|
10
11
|
import { registerGetHelpPrompt } from './prompts/index.js';
|
|
11
12
|
import { registerCacheResourceTemplate, registerInstructionResource, } from './resources/index.js';
|
|
12
13
|
import { buildServerInstructions } from './resources/instructions.js';
|
|
13
|
-
import {
|
|
14
|
+
import { registerTools as registerFetchUrlTool } from './tools/fetch-url.js';
|
|
14
15
|
import { shutdownTransformWorkerPool } from './transform/transform.js';
|
|
15
16
|
/* -------------------------------------------------------------------------------------------------
|
|
16
17
|
* Icons + server info
|
|
@@ -50,6 +51,9 @@ function createServerCapabilities() {
|
|
|
50
51
|
},
|
|
51
52
|
};
|
|
52
53
|
}
|
|
54
|
+
function syncTaskCapabilityAdvertisement(server, taskToolCallEnabled) {
|
|
55
|
+
setTaskToolCallCapability(server, taskToolCallEnabled);
|
|
56
|
+
}
|
|
53
57
|
function createServerInfo(icons) {
|
|
54
58
|
return {
|
|
55
59
|
name: config.server.name,
|
|
@@ -83,13 +87,16 @@ async function createMcpServerWithOptions(options) {
|
|
|
83
87
|
if (shouldRegisterObservabilityServer(options)) {
|
|
84
88
|
setMcpServer(server);
|
|
85
89
|
}
|
|
86
|
-
|
|
90
|
+
const toolControls = registerFetchUrlTool(server);
|
|
87
91
|
registerGetHelpPrompt(server, serverInstructions, localIcon);
|
|
88
92
|
registerInstructionResource(server, serverInstructions, localIcon);
|
|
89
93
|
registerCacheResourceTemplate(server, localIcon);
|
|
90
|
-
registerTaskHandlers(server, {
|
|
94
|
+
const taskRegistration = registerTaskHandlers(server, {
|
|
91
95
|
requireInterception: config.tasks.requireInterception,
|
|
92
96
|
});
|
|
97
|
+
const taskToolCallEnabled = taskRegistration.interceptedToolsCall;
|
|
98
|
+
toolControls.setTaskSupport(taskToolCallEnabled ? 'optional' : 'forbidden');
|
|
99
|
+
syncTaskCapabilityAdvertisement(server, taskToolCallEnabled);
|
|
93
100
|
registerLoggingSetLevelHandler(server);
|
|
94
101
|
attachServerErrorHandler(server);
|
|
95
102
|
return server;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ServerResult } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
export declare const extendedCallToolRequestSchema: z.ZodObject<{
|
|
4
|
+
method: z.ZodLiteral<"tools/call">;
|
|
5
|
+
params: z.ZodObject<{
|
|
6
|
+
name: z.ZodString;
|
|
7
|
+
arguments: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
8
|
+
task: z.ZodOptional<z.ZodObject<{
|
|
9
|
+
ttl: z.ZodOptional<z.ZodNumber>;
|
|
10
|
+
}, z.core.$strict>>;
|
|
11
|
+
_meta: z.ZodOptional<z.ZodObject<{
|
|
12
|
+
progressToken: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
|
|
13
|
+
'io.modelcontextprotocol/related-task': z.ZodOptional<z.ZodObject<{
|
|
14
|
+
taskId: z.ZodString;
|
|
15
|
+
}, z.core.$strict>>;
|
|
16
|
+
}, z.core.$loose>>;
|
|
17
|
+
}, z.core.$strict>;
|
|
18
|
+
}, z.core.$loose>;
|
|
19
|
+
export type ExtendedCallToolRequest = z.infer<typeof extendedCallToolRequestSchema>;
|
|
20
|
+
export type ToolCallRequestMeta = ExtendedCallToolRequest['params']['_meta'];
|
|
21
|
+
export declare function parseExtendedCallToolRequest(request: unknown): ExtendedCallToolRequest;
|
|
22
|
+
export declare function sanitizeToolCallMeta(meta?: ToolCallRequestMeta): ToolCallRequestMeta | undefined;
|
|
23
|
+
export declare function buildRelatedTaskMeta(taskId: string, meta?: ToolCallRequestMeta): Record<string, unknown>;
|
|
24
|
+
export declare function withRelatedTaskMeta(result: ServerResult, taskId: string): ServerResult;
|
|
25
|
+
//# sourceMappingURL=call-contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"call-contract.d.ts","sourceRoot":"","sources":["../../src/tasks/call-contract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAEvE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAgBxB,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;iBAiBxC,CAAC;AAEH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAC3C,OAAO,6BAA6B,CACrC,CAAC;AACF,MAAM,MAAM,mBAAmB,GAAG,uBAAuB,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC;AAE7E,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,OAAO,GACf,uBAAuB,CAQzB;AAED,wBAAgB,oBAAoB,CAClC,IAAI,CAAC,EAAE,mBAAmB,GACzB,mBAAmB,GAAG,SAAS,CAMjC;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,mBAAmB,GACzB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAKzB;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,MAAM,GACb,YAAY,CAQd"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { formatZodError } from '../lib/zod.js';
|
|
4
|
+
const MIN_TASK_TTL_MS = 1_000;
|
|
5
|
+
const MAX_TASK_TTL_MS = 86_400_000;
|
|
6
|
+
const relatedTaskMetaSchema = z.strictObject({
|
|
7
|
+
taskId: z.string(),
|
|
8
|
+
});
|
|
9
|
+
const toolCallMetaSchema = z.looseObject({
|
|
10
|
+
progressToken: z.union([z.string(), z.number()]).optional(),
|
|
11
|
+
'io.modelcontextprotocol/related-task': relatedTaskMetaSchema.optional(),
|
|
12
|
+
});
|
|
13
|
+
export const extendedCallToolRequestSchema = z.looseObject({
|
|
14
|
+
method: z.literal('tools/call'),
|
|
15
|
+
params: z.strictObject({
|
|
16
|
+
name: z.string().min(1),
|
|
17
|
+
arguments: z.record(z.string(), z.unknown()).optional(),
|
|
18
|
+
task: z
|
|
19
|
+
.strictObject({
|
|
20
|
+
ttl: z
|
|
21
|
+
.number()
|
|
22
|
+
.int()
|
|
23
|
+
.min(MIN_TASK_TTL_MS)
|
|
24
|
+
.max(MAX_TASK_TTL_MS)
|
|
25
|
+
.optional(),
|
|
26
|
+
})
|
|
27
|
+
.optional(),
|
|
28
|
+
_meta: toolCallMetaSchema.optional(),
|
|
29
|
+
}),
|
|
30
|
+
});
|
|
31
|
+
export function parseExtendedCallToolRequest(request) {
|
|
32
|
+
const parsed = extendedCallToolRequestSchema.safeParse(request);
|
|
33
|
+
if (parsed.success)
|
|
34
|
+
return parsed.data;
|
|
35
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid tool request params: ${formatZodError(parsed.error)}`);
|
|
36
|
+
}
|
|
37
|
+
export function sanitizeToolCallMeta(meta) {
|
|
38
|
+
if (!meta)
|
|
39
|
+
return undefined;
|
|
40
|
+
const sanitized = { ...meta };
|
|
41
|
+
delete sanitized['io.modelcontextprotocol/related-task'];
|
|
42
|
+
return Object.keys(sanitized).length > 0 ? sanitized : undefined;
|
|
43
|
+
}
|
|
44
|
+
export function buildRelatedTaskMeta(taskId, meta) {
|
|
45
|
+
return {
|
|
46
|
+
...(sanitizeToolCallMeta(meta) ?? {}),
|
|
47
|
+
'io.modelcontextprotocol/related-task': { taskId },
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export function withRelatedTaskMeta(result, taskId) {
|
|
51
|
+
return {
|
|
52
|
+
...result,
|
|
53
|
+
_meta: {
|
|
54
|
+
...result._meta,
|
|
55
|
+
'io.modelcontextprotocol/related-task': { taskId },
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor-codec.d.ts","sourceRoot":"","sources":["../../src/tasks/cursor-codec.ts"],"names":[],"mappings":"AAkBA,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAO7D;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,GACb;IAAE,YAAY,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAuBjC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { createHmac, randomBytes, timingSafeEqual } from 'node:crypto';
|
|
2
|
+
const MAX_CURSOR_LENGTH = 256;
|
|
3
|
+
const CURSOR_SECRET = randomBytes(32);
|
|
4
|
+
function signPayload(payload) {
|
|
5
|
+
return createHmac('sha256', CURSOR_SECRET)
|
|
6
|
+
.update(payload)
|
|
7
|
+
.digest('base64url');
|
|
8
|
+
}
|
|
9
|
+
function safeCompare(left, right) {
|
|
10
|
+
const leftBuffer = Buffer.from(left);
|
|
11
|
+
const rightBuffer = Buffer.from(right);
|
|
12
|
+
if (leftBuffer.length !== rightBuffer.length)
|
|
13
|
+
return false;
|
|
14
|
+
return timingSafeEqual(leftBuffer, rightBuffer);
|
|
15
|
+
}
|
|
16
|
+
export function encodeTaskCursor(anchorTaskId) {
|
|
17
|
+
const payload = Buffer.from(JSON.stringify({ anchorTaskId }), 'utf8').toString('base64url');
|
|
18
|
+
const signature = signPayload(payload);
|
|
19
|
+
return `${payload}.${signature}`;
|
|
20
|
+
}
|
|
21
|
+
export function decodeTaskCursor(cursor) {
|
|
22
|
+
if (!cursor || cursor.length > MAX_CURSOR_LENGTH)
|
|
23
|
+
return null;
|
|
24
|
+
const [payload, signature, ...rest] = cursor.split('.');
|
|
25
|
+
if (!payload || !signature || rest.length > 0)
|
|
26
|
+
return null;
|
|
27
|
+
if (!safeCompare(signPayload(payload), signature))
|
|
28
|
+
return null;
|
|
29
|
+
try {
|
|
30
|
+
const decoded = JSON.parse(Buffer.from(payload, 'base64url').toString('utf8'));
|
|
31
|
+
if (typeof decoded.anchorTaskId !== 'string' ||
|
|
32
|
+
decoded.anchorTaskId.length === 0 ||
|
|
33
|
+
decoded.anchorTaskId.length > 128) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
return { anchorTaskId: decoded.anchorTaskId };
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -1,26 +1,8 @@
|
|
|
1
1
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
2
|
import { type ServerResult } from '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
import { type ExtendedCallToolRequest } from './call-contract.js';
|
|
3
4
|
import { type CreateTaskResult, type TaskState } from './manager.js';
|
|
4
5
|
import { type ToolCallContext } from './owner.js';
|
|
5
|
-
export interface ExtendedCallToolRequest {
|
|
6
|
-
method: 'tools/call';
|
|
7
|
-
params: {
|
|
8
|
-
name: string;
|
|
9
|
-
arguments?: Record<string, unknown> | undefined;
|
|
10
|
-
task?: {
|
|
11
|
-
ttl?: number | undefined;
|
|
12
|
-
} | undefined;
|
|
13
|
-
_meta?: {
|
|
14
|
-
progressToken?: string | number | undefined;
|
|
15
|
-
'io.modelcontextprotocol/related-task'?: {
|
|
16
|
-
taskId: string;
|
|
17
|
-
} | undefined;
|
|
18
|
-
[key: string]: unknown;
|
|
19
|
-
} | undefined;
|
|
20
|
-
[key: string]: unknown;
|
|
21
|
-
};
|
|
22
|
-
[key: string]: unknown;
|
|
23
|
-
}
|
|
24
6
|
export declare function abortTaskExecution(taskId: string): void;
|
|
25
7
|
export declare function cancelTasksForOwner(ownerKey: string, statusMessage?: string): number;
|
|
26
8
|
export declare function abortAllTaskExecutions(): void;
|
|
@@ -34,7 +16,6 @@ export declare function toTaskSummary(task: {
|
|
|
34
16
|
ttl: number;
|
|
35
17
|
pollInterval: number;
|
|
36
18
|
}): TaskSummary;
|
|
37
|
-
export declare function withRelatedTaskMeta(result: ServerResult, taskId: string): ServerResult;
|
|
38
19
|
export declare function emitTaskStatusNotification(server: McpServer, task: TaskState): void;
|
|
39
20
|
export declare function throwTaskNotFound(): never;
|
|
40
21
|
export declare function handleToolCallRequest(server: McpServer, request: ExtendedCallToolRequest, context: ToolCallContext): Promise<ServerResult>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execution.d.ts","sourceRoot":"","sources":["../../src/tasks/execution.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAGL,KAAK,YAAY,EAClB,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"execution.d.ts","sourceRoot":"","sources":["../../src/tasks/execution.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAGL,KAAK,YAAY,EAClB,MAAM,oCAAoC,CAAC;AAQ5C,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,KAAK,gBAAgB,EAErB,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AACtB,OAAO,EAGL,KAAK,eAAe,EAErB,MAAM,YAAY,CAAC;AAgCpB,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAKvD;AAMD,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,aAAa,SAA4D,GACxE,MAAM,CASR;AAED,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C;AAgBD,KAAK,WAAW,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;AAE5C,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,WAAW,CAUd;AAED,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,SAAS,GACd,IAAI,CAmBN;AAoBD,wBAAgB,iBAAiB,IAAI,KAAK,CAEzC;AA+LD,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,uBAAuB,EAChC,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,YAAY,CAAC,CAYvB"}
|