@j0hanz/fetch-url-mcp 1.11.2 → 1.11.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/helpers.d.ts +1 -1
- package/dist/http/helpers.d.ts.map +1 -1
- package/dist/http/helpers.js +1 -1
- package/dist/http/native.js +1 -1
- package/dist/lib/config.d.ts +152 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +478 -0
- package/dist/lib/core.d.ts +1 -150
- package/dist/lib/core.d.ts.map +1 -1
- package/dist/lib/core.js +3 -459
- package/dist/lib/{mcp-tools.d.ts → mcp-interop.d.ts} +49 -1
- package/dist/lib/mcp-interop.d.ts.map +1 -0
- package/dist/lib/mcp-interop.js +354 -0
- package/dist/lib/task-handlers.js +1 -1
- package/dist/resources/index.js +1 -1
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +1 -1
- package/dist/server.js +2 -2
- package/dist/tasks/handlers.d.ts +11 -0
- package/dist/tasks/handlers.d.ts.map +1 -0
- package/dist/tasks/handlers.js +151 -0
- package/dist/tasks/owner.d.ts +1 -2
- package/dist/tasks/owner.d.ts.map +1 -1
- package/dist/tasks/registry.d.ts +1 -1
- package/dist/tasks/registry.d.ts.map +1 -1
- package/dist/tools/fetch-url.d.ts +2 -3
- package/dist/tools/fetch-url.d.ts.map +1 -1
- package/dist/tools/fetch-url.js +3 -4
- package/dist/{lib → transform}/dom-prep.d.ts +1 -1
- package/dist/transform/dom-prep.d.ts.map +1 -0
- package/dist/{lib → transform}/dom-prep.js +2 -2
- package/dist/transform/html-translators.d.ts.map +1 -1
- package/dist/transform/html-translators.js +1 -1
- package/dist/transform/metadata.d.ts +8 -0
- package/dist/transform/metadata.d.ts.map +1 -1
- package/dist/transform/metadata.js +66 -0
- package/dist/transform/transform.d.ts.map +1 -1
- package/dist/transform/transform.js +2 -3
- package/package.json +1 -1
- package/dist/lib/dom-prep.d.ts.map +0 -1
- package/dist/lib/mcp-tools.d.ts.map +0 -1
- package/dist/lib/mcp-tools.js +0 -129
- package/dist/lib/progress.d.ts +0 -32
- package/dist/lib/progress.d.ts.map +0 -1
- package/dist/lib/progress.js +0 -143
- package/dist/lib/sdk-interop.d.ts +0 -20
- package/dist/lib/sdk-interop.d.ts.map +0 -1
- package/dist/lib/sdk-interop.js +0 -85
- package/dist/transform/title-policy.d.ts +0 -9
- package/dist/transform/title-policy.d.ts.map +0 -1
- package/dist/transform/title-policy.js +0 -67
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
1
2
|
import { type CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
2
3
|
import { z } from 'zod';
|
|
3
4
|
export type JsonRpcId = string | number | null;
|
|
@@ -60,5 +61,52 @@ export declare function createToolErrorResponse(message: string, url: string, ex
|
|
|
60
61
|
details?: Record<string, unknown>;
|
|
61
62
|
}): ToolErrorResponse;
|
|
62
63
|
export declare function handleToolError(error: unknown, url: string, fallbackMessage?: string): ToolErrorResponse;
|
|
64
|
+
type CleanupCallback = () => void;
|
|
65
|
+
type RequestHandlerFn = (request: unknown, extra?: unknown) => Promise<unknown>;
|
|
66
|
+
export declare function registerServerLifecycleCleanup(server: McpServer, callback: CleanupCallback): void;
|
|
67
|
+
/**
|
|
68
|
+
* Retrieves the SDK's internal request-handler map.
|
|
69
|
+
*
|
|
70
|
+
* Depends on SDK private API `_requestHandlers` (verified against ^1.27.1).
|
|
71
|
+
* If the SDK changes this internal, the sdk-compat-guard.test.ts tests will fail.
|
|
72
|
+
*/
|
|
73
|
+
export declare function getSdkCallToolHandler(server: McpServer): RequestHandlerFn | null;
|
|
74
|
+
/**
|
|
75
|
+
* Patches the SDK's internal capabilities to enable/disable task-mode tool calls.
|
|
76
|
+
*
|
|
77
|
+
* Depends on SDK private API `_capabilities.tasks.requests` (verified against ^1.27.1).
|
|
78
|
+
* If the SDK changes this internal, the sdk-compat-guard.test.ts tests will fail.
|
|
79
|
+
*/
|
|
80
|
+
export declare function setTaskToolCallCapability(server: McpServer, enabled: boolean): void;
|
|
81
|
+
type ProgressToken = string | number;
|
|
82
|
+
interface RequestMeta {
|
|
83
|
+
progressToken?: ProgressToken | undefined;
|
|
84
|
+
[key: string]: unknown;
|
|
85
|
+
}
|
|
86
|
+
export interface ProgressNotificationParams {
|
|
87
|
+
progressToken: ProgressToken;
|
|
88
|
+
progress: number;
|
|
89
|
+
total?: number;
|
|
90
|
+
message?: string;
|
|
91
|
+
_meta?: Record<string, unknown>;
|
|
92
|
+
}
|
|
93
|
+
export interface ProgressNotification {
|
|
94
|
+
method: 'notifications/progress';
|
|
95
|
+
params: ProgressNotificationParams;
|
|
96
|
+
}
|
|
97
|
+
export interface ToolHandlerExtra {
|
|
98
|
+
signal?: AbortSignal;
|
|
99
|
+
requestId?: string | number;
|
|
100
|
+
sessionId?: unknown;
|
|
101
|
+
requestInfo?: unknown;
|
|
102
|
+
_meta?: RequestMeta;
|
|
103
|
+
sendNotification?: (notification: ProgressNotification) => Promise<void>;
|
|
104
|
+
onProgress?: (progress: number, message: string) => void;
|
|
105
|
+
canReportProgress?: () => boolean;
|
|
106
|
+
}
|
|
107
|
+
export interface ProgressReporter {
|
|
108
|
+
report: (progress: number, message: string) => void;
|
|
109
|
+
}
|
|
110
|
+
export declare const createProgressReporter: (extra?: ToolHandlerExtra) => ProgressReporter;
|
|
63
111
|
export {};
|
|
64
|
-
//# sourceMappingURL=mcp-
|
|
112
|
+
//# sourceMappingURL=mcp-interop.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-interop.d.ts","sourceRoot":"","sources":["../../src/lib/mcp-interop.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
import { setTimeout as setTimeoutPromise } from 'node:timers/promises';
|
|
2
|
+
import {} from '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { logError, logWarn } from './core.js';
|
|
5
|
+
import { FetchError, getErrorMessage, isAbortError, isObject, isSystemError, } from './utils.js';
|
|
6
|
+
const paramsSchema = z.looseObject({
|
|
7
|
+
_meta: z.record(z.string(), z.unknown()).optional(),
|
|
8
|
+
});
|
|
9
|
+
const jsonRpcRequestIdSchema = z.union([z.string(), z.number()]);
|
|
10
|
+
const jsonRpcRequestSchema = z.strictObject({
|
|
11
|
+
jsonrpc: z.literal('2.0'),
|
|
12
|
+
method: z.string().min(1),
|
|
13
|
+
id: jsonRpcRequestIdSchema.optional(),
|
|
14
|
+
params: paramsSchema.optional(),
|
|
15
|
+
});
|
|
16
|
+
const jsonRpcResultResponseSchema = z.strictObject({
|
|
17
|
+
jsonrpc: z.literal('2.0'),
|
|
18
|
+
id: jsonRpcRequestIdSchema,
|
|
19
|
+
result: z.record(z.string(), z.unknown()),
|
|
20
|
+
});
|
|
21
|
+
const jsonRpcErrorResponseSchema = z.strictObject({
|
|
22
|
+
jsonrpc: z.literal('2.0'),
|
|
23
|
+
id: jsonRpcRequestIdSchema.or(z.null()).optional(),
|
|
24
|
+
error: z.strictObject({
|
|
25
|
+
code: z.number().int(),
|
|
26
|
+
message: z.string(),
|
|
27
|
+
data: z.unknown().optional(),
|
|
28
|
+
}),
|
|
29
|
+
});
|
|
30
|
+
const jsonRpcResponseSchema = z.union([
|
|
31
|
+
jsonRpcResultResponseSchema,
|
|
32
|
+
jsonRpcErrorResponseSchema,
|
|
33
|
+
]);
|
|
34
|
+
const jsonRpcMessageSchema = z.union([
|
|
35
|
+
jsonRpcRequestSchema,
|
|
36
|
+
jsonRpcResponseSchema,
|
|
37
|
+
]);
|
|
38
|
+
export function isJsonRpcBatchRequest(body) {
|
|
39
|
+
return Array.isArray(body);
|
|
40
|
+
}
|
|
41
|
+
export function isMcpRequestBody(body) {
|
|
42
|
+
return jsonRpcRequestSchema.safeParse(body).success;
|
|
43
|
+
}
|
|
44
|
+
export function isJsonRpcResponseBody(body) {
|
|
45
|
+
return jsonRpcResponseSchema.safeParse(body).success;
|
|
46
|
+
}
|
|
47
|
+
export function isMcpMessageBody(body) {
|
|
48
|
+
return jsonRpcMessageSchema.safeParse(body).success;
|
|
49
|
+
}
|
|
50
|
+
function parseAcceptMediaTypes(header) {
|
|
51
|
+
if (!header)
|
|
52
|
+
return [];
|
|
53
|
+
return header
|
|
54
|
+
.split(',')
|
|
55
|
+
.map((v) => v.split(';', 1)[0]?.trim().toLowerCase() ?? '')
|
|
56
|
+
.filter((v) => v.length > 0);
|
|
57
|
+
}
|
|
58
|
+
export function acceptsEventStream(header) {
|
|
59
|
+
const mediaTypes = parseAcceptMediaTypes(header);
|
|
60
|
+
return mediaTypes.some((mediaType) => mediaType === 'text/event-stream');
|
|
61
|
+
}
|
|
62
|
+
export function acceptsJsonAndEventStream(header) {
|
|
63
|
+
const mediaTypes = parseAcceptMediaTypes(header);
|
|
64
|
+
const acceptsJson = mediaTypes.some((m) => m === '*/*' || m === 'application/json' || m === 'application/*');
|
|
65
|
+
if (!acceptsJson)
|
|
66
|
+
return false;
|
|
67
|
+
return mediaTypes.some((m) => m === '*/*' || m === 'text/event-stream' || m === 'text/*');
|
|
68
|
+
}
|
|
69
|
+
const PUBLIC_ERROR_REASONS = new Set(['aborted', 'queue_full', 'timeout']);
|
|
70
|
+
function sanitizeToolErrorDetails(details) {
|
|
71
|
+
const sanitized = {};
|
|
72
|
+
const { retryAfter, timeout, reason } = details;
|
|
73
|
+
if (typeof retryAfter === 'number' ||
|
|
74
|
+
typeof retryAfter === 'string' ||
|
|
75
|
+
retryAfter === null) {
|
|
76
|
+
sanitized['retryAfter'] = retryAfter;
|
|
77
|
+
}
|
|
78
|
+
if (typeof timeout === 'number' && Number.isFinite(timeout) && timeout >= 0) {
|
|
79
|
+
sanitized['timeout'] = timeout;
|
|
80
|
+
}
|
|
81
|
+
if (typeof reason === 'string' && PUBLIC_ERROR_REASONS.has(reason)) {
|
|
82
|
+
sanitized['reason'] = reason;
|
|
83
|
+
}
|
|
84
|
+
return Object.keys(sanitized).length > 0 ? sanitized : undefined;
|
|
85
|
+
}
|
|
86
|
+
export function createToolErrorResponse(message, url, extra) {
|
|
87
|
+
const errorContent = {
|
|
88
|
+
error: message,
|
|
89
|
+
...(extra?.code ? { code: extra.code } : {}),
|
|
90
|
+
url,
|
|
91
|
+
...(extra?.statusCode !== undefined
|
|
92
|
+
? { statusCode: extra.statusCode }
|
|
93
|
+
: {}),
|
|
94
|
+
...(extra?.details ? { details: extra.details } : {}),
|
|
95
|
+
};
|
|
96
|
+
return {
|
|
97
|
+
content: [{ type: 'text', text: JSON.stringify(errorContent) }],
|
|
98
|
+
isError: true,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function isValidationError(error) {
|
|
102
|
+
return (error instanceof Error &&
|
|
103
|
+
isSystemError(error) &&
|
|
104
|
+
error.code === 'VALIDATION_ERROR');
|
|
105
|
+
}
|
|
106
|
+
export function handleToolError(error, url, fallbackMessage = 'Operation failed') {
|
|
107
|
+
if (error instanceof FetchError) {
|
|
108
|
+
const { code: detailsCode, reason } = error.details;
|
|
109
|
+
const code = (typeof detailsCode === 'string'
|
|
110
|
+
? detailsCode
|
|
111
|
+
: reason === 'queue_full'
|
|
112
|
+
? 'queue_full'
|
|
113
|
+
: undefined) ?? error.code;
|
|
114
|
+
const details = sanitizeToolErrorDetails(error.details);
|
|
115
|
+
return createToolErrorResponse(error.message, url, {
|
|
116
|
+
code,
|
|
117
|
+
statusCode: error.statusCode,
|
|
118
|
+
...(details ? { details } : {}),
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
if (isValidationError(error)) {
|
|
122
|
+
return createToolErrorResponse(error.message, url, {
|
|
123
|
+
code: 'VALIDATION_ERROR',
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
const code = isAbortError(error) ? 'ABORTED' : 'FETCH_ERROR';
|
|
127
|
+
const message = error instanceof Error
|
|
128
|
+
? `${fallbackMessage}: ${error.message}`
|
|
129
|
+
: `${fallbackMessage}: Unknown error`;
|
|
130
|
+
return createToolErrorResponse(message, url, { code });
|
|
131
|
+
}
|
|
132
|
+
const patchedCleanupServers = new WeakSet();
|
|
133
|
+
const serverCleanupCallbacks = new WeakMap();
|
|
134
|
+
function getServerCleanupCallbackSet(server) {
|
|
135
|
+
let callbacks = serverCleanupCallbacks.get(server);
|
|
136
|
+
if (!callbacks) {
|
|
137
|
+
callbacks = new Set();
|
|
138
|
+
serverCleanupCallbacks.set(server, callbacks);
|
|
139
|
+
}
|
|
140
|
+
return callbacks;
|
|
141
|
+
}
|
|
142
|
+
function drainServerCleanupCallbacks(server) {
|
|
143
|
+
const callbacks = serverCleanupCallbacks.get(server);
|
|
144
|
+
if (!callbacks || callbacks.size === 0)
|
|
145
|
+
return;
|
|
146
|
+
const pending = [...callbacks];
|
|
147
|
+
callbacks.clear();
|
|
148
|
+
for (const callback of pending) {
|
|
149
|
+
try {
|
|
150
|
+
callback();
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
logWarn('Server cleanup callback failed', { error });
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
function ensureServerCleanupHooks(server) {
|
|
158
|
+
if (patchedCleanupServers.has(server))
|
|
159
|
+
return;
|
|
160
|
+
patchedCleanupServers.add(server);
|
|
161
|
+
const originalOnClose = server.server.onclose;
|
|
162
|
+
server.server.onclose = () => {
|
|
163
|
+
drainServerCleanupCallbacks(server);
|
|
164
|
+
originalOnClose?.();
|
|
165
|
+
};
|
|
166
|
+
const originalClose = server.close.bind(server);
|
|
167
|
+
server.close = async () => {
|
|
168
|
+
drainServerCleanupCallbacks(server);
|
|
169
|
+
await originalClose();
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
export function registerServerLifecycleCleanup(server, callback) {
|
|
173
|
+
ensureServerCleanupHooks(server);
|
|
174
|
+
getServerCleanupCallbackSet(server).add(callback);
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Retrieves the SDK's internal request-handler map.
|
|
178
|
+
*
|
|
179
|
+
* Depends on SDK private API `_requestHandlers` (verified against ^1.27.1).
|
|
180
|
+
* If the SDK changes this internal, the sdk-compat-guard.test.ts tests will fail.
|
|
181
|
+
*/
|
|
182
|
+
export function getSdkCallToolHandler(server) {
|
|
183
|
+
const maybeHandlers = Reflect.get(server.server, '_requestHandlers');
|
|
184
|
+
if (!(maybeHandlers instanceof Map))
|
|
185
|
+
return null;
|
|
186
|
+
const handler = maybeHandlers.get('tools/call');
|
|
187
|
+
return typeof handler === 'function' ? handler : null;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Patches the SDK's internal capabilities to enable/disable task-mode tool calls.
|
|
191
|
+
*
|
|
192
|
+
* Depends on SDK private API `_capabilities.tasks.requests` (verified against ^1.27.1).
|
|
193
|
+
* If the SDK changes this internal, the sdk-compat-guard.test.ts tests will fail.
|
|
194
|
+
*/
|
|
195
|
+
export function setTaskToolCallCapability(server, enabled) {
|
|
196
|
+
const capabilities = Reflect.get(server.server, '_capabilities');
|
|
197
|
+
if (!isObject(capabilities))
|
|
198
|
+
return;
|
|
199
|
+
const tasks = isObject(capabilities.tasks)
|
|
200
|
+
? capabilities.tasks
|
|
201
|
+
: undefined;
|
|
202
|
+
if (!tasks)
|
|
203
|
+
return;
|
|
204
|
+
const requests = isObject(tasks.requests)
|
|
205
|
+
? tasks.requests
|
|
206
|
+
: undefined;
|
|
207
|
+
if (!requests)
|
|
208
|
+
return;
|
|
209
|
+
if (enabled) {
|
|
210
|
+
requests.tools = { call: {} };
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
delete requests.tools;
|
|
214
|
+
}
|
|
215
|
+
const DEFAULT_PROGRESS_TOTAL = 8;
|
|
216
|
+
const PROGRESS_NOTIFICATION_TIMEOUT_MS = 5000;
|
|
217
|
+
function resolveRelatedTaskMeta(meta) {
|
|
218
|
+
const related = meta?.['io.modelcontextprotocol/related-task'];
|
|
219
|
+
if (!isObject(related))
|
|
220
|
+
return undefined;
|
|
221
|
+
const { taskId } = related;
|
|
222
|
+
return typeof taskId === 'string' ? { taskId } : undefined;
|
|
223
|
+
}
|
|
224
|
+
class ToolProgressReporter {
|
|
225
|
+
token;
|
|
226
|
+
handlers;
|
|
227
|
+
taskMeta;
|
|
228
|
+
isTerminal = false;
|
|
229
|
+
lastProgress = -1;
|
|
230
|
+
lastMessage;
|
|
231
|
+
pendingNotification;
|
|
232
|
+
isDispatching = false;
|
|
233
|
+
constructor(token, handlers, taskMeta) {
|
|
234
|
+
this.token = token;
|
|
235
|
+
this.handlers = handlers;
|
|
236
|
+
this.taskMeta = taskMeta;
|
|
237
|
+
}
|
|
238
|
+
static create(extra = {}) {
|
|
239
|
+
const token = extra._meta?.progressToken ?? null;
|
|
240
|
+
const { onProgress } = extra;
|
|
241
|
+
if (token === null && !onProgress) {
|
|
242
|
+
return { report: () => { } };
|
|
243
|
+
}
|
|
244
|
+
return new ToolProgressReporter(token, {
|
|
245
|
+
send: extra.sendNotification,
|
|
246
|
+
onProgress,
|
|
247
|
+
canReport: extra.canReportProgress,
|
|
248
|
+
}, resolveRelatedTaskMeta(extra._meta));
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Report progress toward completion. Steps are monotonic (never decrease)
|
|
252
|
+
* and may be skipped under normal conditions (e.g., fast responses skip
|
|
253
|
+
* intermediate steps). Clients should treat progress as "at least this far"
|
|
254
|
+
* rather than expecting every step to fire sequentially.
|
|
255
|
+
*/
|
|
256
|
+
report(progress, message) {
|
|
257
|
+
if (this.isTerminal || this.handlers.canReport?.() === false)
|
|
258
|
+
return;
|
|
259
|
+
const effectiveProgress = Math.max(progress, this.lastProgress);
|
|
260
|
+
const isIncreasing = effectiveProgress > this.lastProgress;
|
|
261
|
+
const isMessageChanged = message !== this.lastMessage;
|
|
262
|
+
this.lastProgress = effectiveProgress;
|
|
263
|
+
this.lastMessage = message;
|
|
264
|
+
if (effectiveProgress >= DEFAULT_PROGRESS_TOTAL) {
|
|
265
|
+
this.isTerminal = true;
|
|
266
|
+
}
|
|
267
|
+
if (isIncreasing || isMessageChanged) {
|
|
268
|
+
try {
|
|
269
|
+
this.handlers.onProgress?.(effectiveProgress, message);
|
|
270
|
+
}
|
|
271
|
+
catch (error) {
|
|
272
|
+
logError('Progress callback failed', {
|
|
273
|
+
error: getErrorMessage(error),
|
|
274
|
+
progress: effectiveProgress,
|
|
275
|
+
message,
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
if (!isIncreasing || this.token === null || !this.handlers.send)
|
|
280
|
+
return;
|
|
281
|
+
this.pendingNotification = this.createProgressNotification(this.token, effectiveProgress, message);
|
|
282
|
+
this.flushNotifications();
|
|
283
|
+
}
|
|
284
|
+
flushNotifications() {
|
|
285
|
+
if (this.isDispatching || !this.handlers.send)
|
|
286
|
+
return;
|
|
287
|
+
this.isDispatching = true;
|
|
288
|
+
void (async () => {
|
|
289
|
+
try {
|
|
290
|
+
while (this.pendingNotification) {
|
|
291
|
+
if (this.handlers.canReport?.() === false) {
|
|
292
|
+
this.pendingNotification = undefined;
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
const notification = this.pendingNotification;
|
|
296
|
+
this.pendingNotification = undefined;
|
|
297
|
+
await this.sendWithTimeout(notification);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
finally {
|
|
301
|
+
this.isDispatching = false;
|
|
302
|
+
}
|
|
303
|
+
})();
|
|
304
|
+
}
|
|
305
|
+
async sendWithTimeout(notification) {
|
|
306
|
+
if (!this.handlers.send)
|
|
307
|
+
return;
|
|
308
|
+
const ac = new AbortController();
|
|
309
|
+
const timeoutPromise = setTimeoutPromise(PROGRESS_NOTIFICATION_TIMEOUT_MS, { timeout: true }, { signal: ac.signal, ref: false }).catch((err) => {
|
|
310
|
+
if (err.name === 'AbortError')
|
|
311
|
+
return { ok: true };
|
|
312
|
+
throw err;
|
|
313
|
+
});
|
|
314
|
+
try {
|
|
315
|
+
const outcome = await Promise.race([
|
|
316
|
+
this.handlers.send(notification).then(() => {
|
|
317
|
+
ac.abort();
|
|
318
|
+
return { ok: true };
|
|
319
|
+
}),
|
|
320
|
+
timeoutPromise,
|
|
321
|
+
]);
|
|
322
|
+
if ('timeout' in outcome) {
|
|
323
|
+
logWarn('Progress notification timed out', {
|
|
324
|
+
progress: notification.params.progress,
|
|
325
|
+
message: notification.params.message,
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
catch (error) {
|
|
330
|
+
logWarn('Failed to send progress notification', {
|
|
331
|
+
error: getErrorMessage(error),
|
|
332
|
+
progress: notification.params.progress,
|
|
333
|
+
message: notification.params.message,
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
createProgressNotification(token, progress, message) {
|
|
338
|
+
return {
|
|
339
|
+
method: 'notifications/progress',
|
|
340
|
+
params: {
|
|
341
|
+
progressToken: token,
|
|
342
|
+
progress,
|
|
343
|
+
total: DEFAULT_PROGRESS_TOTAL,
|
|
344
|
+
message,
|
|
345
|
+
...(this.taskMeta && {
|
|
346
|
+
_meta: {
|
|
347
|
+
'io.modelcontextprotocol/related-task': this.taskMeta,
|
|
348
|
+
},
|
|
349
|
+
}),
|
|
350
|
+
},
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
export const createProgressReporter = (extra) => ToolProgressReporter.create(extra);
|
|
@@ -8,7 +8,7 @@ import { taskManager } from '../tasks/manager.js';
|
|
|
8
8
|
import { isServerResult, parseHandlerExtra, resolveTaskOwnerKey, resolveToolCallContext, } from '../tasks/owner.js';
|
|
9
9
|
import { hasRegisteredTaskCapableTools, hasTaskCapableTool, } from '../tasks/registry.js';
|
|
10
10
|
import { logWarn, runWithRequestContext } from './core.js';
|
|
11
|
-
import { getSdkCallToolHandler } from './
|
|
11
|
+
import { getSdkCallToolHandler } from './mcp-interop.js';
|
|
12
12
|
export { cancelTasksForOwner, abortAllTaskExecutions, } from '../tasks/execution.js';
|
|
13
13
|
/* -------------------------------------------------------------------------------------------------
|
|
14
14
|
* Task handler schemas and registration
|
package/dist/resources/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { ErrorCode, McpError, SubscribeRequestSchema, UnsubscribeRequestSchema,
|
|
|
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
5
|
import { config } from '../lib/core.js';
|
|
6
|
-
import { registerServerLifecycleCleanup } from '../lib/
|
|
6
|
+
import { registerServerLifecycleCleanup } from '../lib/mcp-interop.js';
|
|
7
7
|
import { buildOptionalIcons } from '../lib/utils.js';
|
|
8
8
|
import { isObject } from '../lib/utils.js';
|
|
9
9
|
import { parseCachedPayload, resolveCachedPayloadContent } from '../schemas.js';
|
package/dist/schemas.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAoD9D,eAAO,MAAM,uBAAuB,EAAE,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAG9D,CAAC;AAgBJ,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,OAAO,GACb,iBAAiB,GAAG,SAAS,CAQ/B;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAErE;AAUD,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,QAAQ,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;IACzC,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACjC;AAED,eAAO,MAAM,wBAAwB,EAAE,CAAC,CAAC,OAAO,CAAC,aAAa,CAM1D,CAAC;AAwCL,eAAO,MAAM,mBAAmB;;;
|
|
1
|
+
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAoD9D,eAAO,MAAM,uBAAuB,EAAE,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAG9D,CAAC;AAgBJ,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,OAAO,GACb,iBAAiB,GAAG,SAAS,CAQ/B;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAErE;AAUD,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,QAAQ,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;IACzC,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACjC;AAED,eAAO,MAAM,wBAAwB,EAAE,CAAC,CAAC,OAAO,CAAC,aAAa,CAM1D,CAAC;AAwCL,eAAO,MAAM,mBAAmB;;;kBAkB/B,CAAC;AAEF,eAAO,MAAM,oBAAoB;;;;;;;;;;;;kBAqC/B,CAAC;AAEH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAkBpE;AAED,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,GAChD,MAAM,CAER;AAED,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG;IAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAC7D,MAAM,GAAG,IAAI,CAEf"}
|
package/dist/schemas.js
CHANGED
|
@@ -99,7 +99,7 @@ export const fetchUrlInputSchema = z.strictObject({
|
|
|
99
99
|
.httpUrl('Expected HTTP or HTTPS URL')
|
|
100
100
|
.min(1, 'URL required')
|
|
101
101
|
.max(config.constants.maxUrlLength, `URL exceeds ${config.constants.maxUrlLength} chars`)
|
|
102
|
-
.describe(`Target URL. Max ${config.constants.maxUrlLength} chars
|
|
102
|
+
.describe(`Target URL. Max ${config.constants.maxUrlLength} chars. Example: https://example.com`),
|
|
103
103
|
forceRefresh: z
|
|
104
104
|
.boolean('Expected boolean')
|
|
105
105
|
.optional()
|
package/dist/server.js
CHANGED
|
@@ -5,10 +5,10 @@ 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/
|
|
9
|
-
import { abortAllTaskExecutions, registerTaskHandlers, } from './lib/task-handlers.js';
|
|
8
|
+
import { setTaskToolCallCapability } from './lib/mcp-interop.js';
|
|
10
9
|
import { toError } from './lib/utils.js';
|
|
11
10
|
import { buildServerInstructions, registerCacheResourceTemplate, registerGetHelpPrompt, registerInstructionResource, } from './resources/index.js';
|
|
11
|
+
import { abortAllTaskExecutions, registerTaskHandlers, } from './tasks/handlers.js';
|
|
12
12
|
import { registerTools as registerFetchUrlTool } from './tools/fetch-url.js';
|
|
13
13
|
import { shutdownTransformWorkerPool } from './transform/transform.js';
|
|
14
14
|
/* -------------------------------------------------------------------------------------------------
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
export { cancelTasksForOwner, abortAllTaskExecutions } from './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=handlers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../src/tasks/handlers.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAmCzE,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AA4D7E,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"}
|
|
@@ -0,0 +1,151 @@
|
|
|
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 { logWarn, runWithRequestContext } from '../lib/core.js';
|
|
6
|
+
import { getSdkCallToolHandler } from '../lib/mcp-interop.js';
|
|
7
|
+
import { parseExtendedCallToolRequest, withRelatedTaskMeta, } from './call-contract.js';
|
|
8
|
+
import { abortTaskExecution, emitTaskStatusNotification, handleToolCallRequest, throwTaskNotFound, toTaskSummary, } from './execution.js';
|
|
9
|
+
import { taskManager } from './manager.js';
|
|
10
|
+
import { isServerResult, parseHandlerExtra, resolveTaskOwnerKey, resolveToolCallContext, } from './owner.js';
|
|
11
|
+
import { hasRegisteredTaskCapableTools, hasTaskCapableTool, } from './registry.js';
|
|
12
|
+
export { cancelTasksForOwner, abortAllTaskExecutions } from './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
|
+
}
|
package/dist/tasks/owner.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { ServerResult } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
-
import type { ProgressNotification } from '../lib/
|
|
3
|
-
import type { ToolHandlerExtra } from '../lib/progress.js';
|
|
2
|
+
import type { ProgressNotification, ToolHandlerExtra } from '../lib/mcp-interop.js';
|
|
4
3
|
import { type ToolCallRequestMeta } from './call-contract.js';
|
|
5
4
|
interface HandlerExtra {
|
|
6
5
|
sessionId?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"owner.d.ts","sourceRoot":"","sources":["../../src/tasks/owner.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAIvE,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"owner.d.ts","sourceRoot":"","sources":["../../src/tasks/owner.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAIvE,OAAO,KAAK,EACV,oBAAoB,EACpB,gBAAgB,EACjB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,oBAAoB,CAAC;AAM5B,UAAU,YAAY;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACjD,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,gBAAgB,CAAC,EAAE,CAAC,YAAY,EAAE,oBAAoB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzE,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,gBAAgB,CAAC,EAAE,CAAC,YAAY,EAAE,oBAAoB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzE,WAAW,CAAC,EAAE,mBAAmB,CAAC;CACnC;AAED,MAAM,MAAM,eAAe,GAAG,oBAAoB,CAAC;AAEnD;;sDAEsD;AACtD,KAAK,SAAS,CAAC,CAAC,SAAS,MAAM,IAAI;KAChC,CAAC,IAAI,MAAM,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,SAAS,KAAK,GACnD,KAAK,GACL,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC;CAClC,CAAC;AAEF,wBAAgB,OAAO,CAAC,CAAC,SAAS,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAQ9D;AA2BD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY,GAAG,SAAS,CA0B1E;AAED,wBAAgB,mBAAmB,CAAC,KAAK,CAAC,EAAE,YAAY,GAAG,MAAM,CAMhE;AAuDD,wBAAgB,sBAAsB,CACpC,KAAK,CAAC,EAAE,YAAY,EACpB,WAAW,CAAC,EAAE,mBAAmB,GAChC,eAAe,CAEjB;AAED,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,oBAAoB,EAC7B,WAAW,CAAC,EAAE,mBAAmB,GAChC,gBAAgB,CAOlB;AAED,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,EAC5E,OAAO,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,GAC7D,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAmBvD;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,YAAY,CAIpE;AAWD,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAgB7E"}
|
package/dist/tasks/registry.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ServerResult } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
-
import type { ToolHandlerExtra } from '../lib/
|
|
2
|
+
import type { ToolHandlerExtra } from '../lib/mcp-interop.js';
|
|
3
3
|
export type TaskCapableToolSupport = 'optional' | 'forbidden';
|
|
4
4
|
export interface TaskCapableToolDescriptor<TArgs = unknown> {
|
|
5
5
|
name: string;
|