@j0hanz/superfetch 2.4.4 → 2.4.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/README.md +195 -138
- package/dist/config.d.ts +1 -0
- package/dist/config.js +1 -0
- package/dist/http-native.js +2 -2
- package/dist/instructions.md +30 -38
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.js +292 -99
- package/dist/observability.js +2 -1
- package/dist/tasks.d.ts +24 -5
- package/dist/tasks.js +125 -8
- package/dist/tools.d.ts +2 -3
- package/dist/tools.js +76 -15
- package/dist/transform.js +40 -14
- package/package.json +1 -1
package/dist/mcp.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { McpServer, ResourceTemplate, } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
4
4
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
5
|
-
import { CallToolRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
5
|
+
import { CallToolRequestSchema, ErrorCode, McpError, } from '@modelcontextprotocol/sdk/types.js';
|
|
6
6
|
import { registerCachedContentResource } from './cache.js';
|
|
7
7
|
import { config } from './config.js';
|
|
8
8
|
import { destroyAgents } from './fetch.js';
|
|
@@ -12,10 +12,10 @@ import { taskManager } from './tasks.js';
|
|
|
12
12
|
import { FETCH_URL_TOOL_NAME, fetchUrlToolHandler, registerTools, } from './tools.js';
|
|
13
13
|
import { shutdownTransformWorkerPool } from './transform.js';
|
|
14
14
|
import { isObject } from './type-guards.js';
|
|
15
|
-
function getLocalIcons() {
|
|
15
|
+
async function getLocalIcons() {
|
|
16
16
|
try {
|
|
17
17
|
const iconPath = new URL('../assets/logo.svg', import.meta.url);
|
|
18
|
-
const buffer =
|
|
18
|
+
const buffer = await readFile(iconPath);
|
|
19
19
|
return [
|
|
20
20
|
{
|
|
21
21
|
src: `data:image/svg+xml;base64,${buffer.toString('base64')}`,
|
|
@@ -28,8 +28,8 @@ function getLocalIcons() {
|
|
|
28
28
|
return undefined;
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
|
-
function createServerInfo() {
|
|
32
|
-
const localIcons = getLocalIcons();
|
|
31
|
+
async function createServerInfo() {
|
|
32
|
+
const localIcons = await getLocalIcons();
|
|
33
33
|
return {
|
|
34
34
|
name: config.server.name,
|
|
35
35
|
version: config.server.version,
|
|
@@ -40,6 +40,7 @@ function createServerCapabilities() {
|
|
|
40
40
|
return {
|
|
41
41
|
tools: { listChanged: true },
|
|
42
42
|
resources: { listChanged: true, subscribe: true },
|
|
43
|
+
prompts: {},
|
|
43
44
|
logging: {},
|
|
44
45
|
tasks: {
|
|
45
46
|
list: {},
|
|
@@ -52,9 +53,9 @@ function createServerCapabilities() {
|
|
|
52
53
|
},
|
|
53
54
|
};
|
|
54
55
|
}
|
|
55
|
-
function createServerInstructions(serverVersion) {
|
|
56
|
+
async function createServerInstructions(serverVersion) {
|
|
56
57
|
try {
|
|
57
|
-
const raw =
|
|
58
|
+
const raw = await readFile(new URL('./instructions.md', import.meta.url), 'utf8');
|
|
58
59
|
return raw.replaceAll('{{SERVER_VERSION}}', serverVersion).trim();
|
|
59
60
|
}
|
|
60
61
|
catch {
|
|
@@ -77,83 +78,233 @@ function registerInstructionsResource(server, instructions) {
|
|
|
77
78
|
}));
|
|
78
79
|
}
|
|
79
80
|
// Schemas based on methods strings
|
|
80
|
-
const TaskGetSchema = z.object({
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
81
|
+
const TaskGetSchema = z.object({
|
|
82
|
+
method: z.literal('tasks/get'),
|
|
83
|
+
params: z.object({ taskId: z.string() }),
|
|
84
|
+
});
|
|
85
|
+
const TaskListSchema = z.object({
|
|
86
|
+
method: z.literal('tasks/list'),
|
|
87
|
+
params: z
|
|
88
|
+
.object({
|
|
89
|
+
cursor: z.string().optional(),
|
|
90
|
+
})
|
|
91
|
+
.optional(),
|
|
92
|
+
});
|
|
93
|
+
const TaskCancelSchema = z.object({
|
|
94
|
+
method: z.literal('tasks/cancel'),
|
|
95
|
+
params: z.object({ taskId: z.string() }),
|
|
96
|
+
});
|
|
97
|
+
const TaskResultSchema = z.object({
|
|
98
|
+
method: z.literal('tasks/result'),
|
|
99
|
+
params: z.object({ taskId: z.string() }),
|
|
100
|
+
});
|
|
101
|
+
function isNonEmptyString(value) {
|
|
102
|
+
return typeof value === 'string' && value.length > 0;
|
|
103
|
+
}
|
|
104
|
+
function isRecord(value) {
|
|
105
|
+
return isObject(value);
|
|
106
|
+
}
|
|
107
|
+
function isValidTask(task) {
|
|
108
|
+
if (task === undefined)
|
|
109
|
+
return true;
|
|
110
|
+
if (!isRecord(task))
|
|
111
|
+
return false;
|
|
112
|
+
const { ttl } = task;
|
|
113
|
+
return ttl === undefined || typeof ttl === 'number';
|
|
114
|
+
}
|
|
115
|
+
function isValidMeta(meta) {
|
|
116
|
+
if (meta === undefined)
|
|
117
|
+
return true;
|
|
118
|
+
if (!isRecord(meta))
|
|
119
|
+
return false;
|
|
120
|
+
const { progressToken } = meta;
|
|
121
|
+
if (progressToken !== undefined &&
|
|
122
|
+
typeof progressToken !== 'string' &&
|
|
123
|
+
typeof progressToken !== 'number') {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
const related = meta['io.modelcontextprotocol/related-task'];
|
|
127
|
+
if (related === undefined)
|
|
128
|
+
return true;
|
|
129
|
+
if (!isRecord(related))
|
|
130
|
+
return false;
|
|
131
|
+
const { taskId } = related;
|
|
132
|
+
return typeof taskId === 'string';
|
|
133
|
+
}
|
|
134
|
+
function isExtendedCallToolRequest(request) {
|
|
135
|
+
if (!isRecord(request))
|
|
136
|
+
return false;
|
|
137
|
+
const { method, params } = request;
|
|
138
|
+
if (method !== 'tools/call')
|
|
139
|
+
return false;
|
|
140
|
+
if (!isRecord(params))
|
|
141
|
+
return false;
|
|
142
|
+
const { name, arguments: args, task, _meta, } = params;
|
|
143
|
+
return (isNonEmptyString(name) &&
|
|
144
|
+
(args === undefined || isRecord(args)) &&
|
|
145
|
+
isValidTask(task) &&
|
|
146
|
+
isValidMeta(_meta));
|
|
147
|
+
}
|
|
148
|
+
function resolveTaskOwnerKey(extra) {
|
|
149
|
+
if (extra?.sessionId)
|
|
150
|
+
return `session:${extra.sessionId}`;
|
|
151
|
+
if (extra?.authInfo?.clientId)
|
|
152
|
+
return `client:${extra.authInfo.clientId}`;
|
|
153
|
+
if (extra?.authInfo?.token)
|
|
154
|
+
return `token:${extra.authInfo.token}`;
|
|
155
|
+
return 'default';
|
|
156
|
+
}
|
|
157
|
+
function resolveToolCallContext(extra) {
|
|
158
|
+
const context = {
|
|
159
|
+
ownerKey: resolveTaskOwnerKey(extra),
|
|
160
|
+
};
|
|
161
|
+
if (extra?.signal)
|
|
162
|
+
context.signal = extra.signal;
|
|
163
|
+
if (extra?.requestId !== undefined)
|
|
164
|
+
context.requestId = extra.requestId;
|
|
165
|
+
if (extra?.sendNotification)
|
|
166
|
+
context.sendNotification = extra.sendNotification;
|
|
167
|
+
return context;
|
|
168
|
+
}
|
|
169
|
+
function requireFetchUrlArgs(args) {
|
|
170
|
+
if (!isObject(args) || typeof args.url !== 'string') {
|
|
171
|
+
throw new McpError(ErrorCode.InvalidParams, 'Invalid arguments for fetch-url');
|
|
172
|
+
}
|
|
173
|
+
return { url: args.url };
|
|
174
|
+
}
|
|
175
|
+
function throwTaskNotFound() {
|
|
176
|
+
throw new McpError(ErrorCode.InvalidParams, 'Failed to retrieve task: Task not found');
|
|
177
|
+
}
|
|
178
|
+
function requireFetchUrlToolName(name) {
|
|
179
|
+
if (name === FETCH_URL_TOOL_NAME)
|
|
180
|
+
return;
|
|
181
|
+
throw new McpError(ErrorCode.MethodNotFound, `Tool '${name}' does not support task execution`);
|
|
182
|
+
}
|
|
183
|
+
function buildRelatedTaskMeta(taskId, meta) {
|
|
184
|
+
return {
|
|
185
|
+
...(meta ?? {}),
|
|
186
|
+
'io.modelcontextprotocol/related-task': { taskId },
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
function buildCreateTaskResult(task) {
|
|
190
|
+
return {
|
|
191
|
+
task,
|
|
192
|
+
_meta: {
|
|
193
|
+
'io.modelcontextprotocol/related-task': {
|
|
194
|
+
taskId: task.taskId,
|
|
195
|
+
status: task.status,
|
|
196
|
+
...(task.statusMessage ? { statusMessage: task.statusMessage } : {}),
|
|
197
|
+
createdAt: task.createdAt,
|
|
198
|
+
lastUpdatedAt: task.lastUpdatedAt,
|
|
199
|
+
ttl: task.ttl,
|
|
200
|
+
pollInterval: task.pollInterval,
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
async function runFetchTaskExecution(params) {
|
|
206
|
+
const { taskId, args, meta, sendNotification } = params;
|
|
207
|
+
try {
|
|
208
|
+
const controller = new AbortController();
|
|
209
|
+
const relatedMeta = buildRelatedTaskMeta(taskId, meta);
|
|
210
|
+
const result = await fetchUrlToolHandler(args, {
|
|
211
|
+
signal: controller.signal,
|
|
212
|
+
requestId: taskId, // Correlation
|
|
213
|
+
_meta: relatedMeta,
|
|
214
|
+
...(sendNotification ? { sendNotification } : {}),
|
|
215
|
+
});
|
|
216
|
+
const isToolError = typeof result.isError === 'boolean'
|
|
217
|
+
? result.isError
|
|
218
|
+
: false;
|
|
219
|
+
taskManager.updateTask(taskId, {
|
|
220
|
+
status: isToolError ? 'failed' : 'completed',
|
|
221
|
+
...(isToolError
|
|
222
|
+
? {
|
|
223
|
+
statusMessage: result
|
|
224
|
+
.structuredContent?.error ?? 'Tool execution failed',
|
|
124
225
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
},
|
|
137
|
-
};
|
|
138
|
-
return response;
|
|
139
|
-
}
|
|
140
|
-
if (extendedParams.name === FETCH_URL_TOOL_NAME) {
|
|
141
|
-
const args = extendedParams.arguments;
|
|
142
|
-
if (!isObject(args) ||
|
|
143
|
-
typeof args.url !== 'string') {
|
|
144
|
-
throw new Error('Invalid arguments for fetch-url');
|
|
226
|
+
: {}),
|
|
227
|
+
result,
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
catch (error) {
|
|
231
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
232
|
+
const errorPayload = error instanceof McpError
|
|
233
|
+
? {
|
|
234
|
+
code: error.code,
|
|
235
|
+
message: errorMessage,
|
|
236
|
+
data: error.data,
|
|
145
237
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
238
|
+
: {
|
|
239
|
+
code: ErrorCode.InternalError,
|
|
240
|
+
message: errorMessage,
|
|
241
|
+
};
|
|
242
|
+
taskManager.updateTask(taskId, {
|
|
243
|
+
status: 'failed',
|
|
244
|
+
statusMessage: errorMessage,
|
|
245
|
+
error: errorPayload,
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
function handleTaskToolCall(params, context) {
|
|
250
|
+
requireFetchUrlToolName(params.name);
|
|
251
|
+
const validArgs = requireFetchUrlArgs(params.arguments);
|
|
252
|
+
const task = taskManager.createTask(params.task?.ttl !== undefined ? { ttl: params.task.ttl } : undefined, 'Task started', context.ownerKey);
|
|
253
|
+
const executionParams = {
|
|
254
|
+
taskId: task.taskId,
|
|
255
|
+
args: validArgs,
|
|
256
|
+
...(params._meta ? { meta: params._meta } : {}),
|
|
257
|
+
...(context.sendNotification
|
|
258
|
+
? { sendNotification: context.sendNotification }
|
|
259
|
+
: {}),
|
|
260
|
+
};
|
|
261
|
+
void runFetchTaskExecution(executionParams);
|
|
262
|
+
return buildCreateTaskResult({
|
|
263
|
+
taskId: task.taskId,
|
|
264
|
+
status: task.status,
|
|
265
|
+
...(task.statusMessage ? { statusMessage: task.statusMessage } : {}),
|
|
266
|
+
createdAt: task.createdAt,
|
|
267
|
+
lastUpdatedAt: task.lastUpdatedAt,
|
|
268
|
+
ttl: task.ttl,
|
|
269
|
+
pollInterval: task.pollInterval,
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
async function handleDirectToolCall(params, context) {
|
|
273
|
+
const args = requireFetchUrlArgs(params.arguments);
|
|
274
|
+
return fetchUrlToolHandler({ url: args.url }, {
|
|
275
|
+
...(context.signal ? { signal: context.signal } : {}),
|
|
276
|
+
...(context.requestId ? { requestId: context.requestId } : {}),
|
|
277
|
+
...(context.sendNotification
|
|
278
|
+
? { sendNotification: context.sendNotification }
|
|
279
|
+
: {}),
|
|
280
|
+
...(params._meta ? { _meta: params._meta } : {}),
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
async function handleToolCallRequest(request, context) {
|
|
284
|
+
const { params } = request;
|
|
285
|
+
if (params.task) {
|
|
286
|
+
return handleTaskToolCall(params, context);
|
|
287
|
+
}
|
|
288
|
+
if (params.name === FETCH_URL_TOOL_NAME) {
|
|
289
|
+
return handleDirectToolCall(params, context);
|
|
290
|
+
}
|
|
291
|
+
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${params.name}`);
|
|
292
|
+
}
|
|
293
|
+
function registerTaskHandlers(server) {
|
|
294
|
+
server.server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
|
|
295
|
+
const context = resolveToolCallContext(extra);
|
|
296
|
+
if (!isExtendedCallToolRequest(request)) {
|
|
297
|
+
throw new McpError(ErrorCode.InvalidParams, 'Invalid tool request');
|
|
149
298
|
}
|
|
150
|
-
|
|
299
|
+
const result = await handleToolCallRequest(request, context);
|
|
300
|
+
return result;
|
|
151
301
|
});
|
|
152
|
-
server.server.setRequestHandler(TaskGetSchema, async (request) => {
|
|
302
|
+
server.server.setRequestHandler(TaskGetSchema, async (request, extra) => {
|
|
153
303
|
const { taskId } = request.params;
|
|
154
|
-
const
|
|
304
|
+
const ownerKey = resolveTaskOwnerKey(extra);
|
|
305
|
+
const task = taskManager.getTask(taskId, ownerKey);
|
|
155
306
|
if (!task) {
|
|
156
|
-
|
|
307
|
+
throwTaskNotFound();
|
|
157
308
|
}
|
|
158
309
|
return Promise.resolve({
|
|
159
310
|
taskId: task.taskId,
|
|
@@ -165,20 +316,37 @@ function registerTaskHandlers(server) {
|
|
|
165
316
|
pollInterval: task.pollInterval,
|
|
166
317
|
});
|
|
167
318
|
});
|
|
168
|
-
server.server.setRequestHandler(TaskResultSchema, async (request) => {
|
|
319
|
+
server.server.setRequestHandler(TaskResultSchema, async (request, extra) => {
|
|
169
320
|
const { taskId } = request.params;
|
|
170
|
-
const
|
|
321
|
+
const ownerKey = resolveTaskOwnerKey(extra);
|
|
322
|
+
const task = await taskManager.waitForTerminalTask(taskId, ownerKey, extra?.signal);
|
|
171
323
|
if (!task) {
|
|
172
|
-
|
|
173
|
-
}
|
|
174
|
-
if (task.status === 'working' || task.status === 'input_required') {
|
|
175
|
-
throw new Error('Task execution in progress');
|
|
324
|
+
throwTaskNotFound();
|
|
176
325
|
}
|
|
177
326
|
if (task.status === 'failed') {
|
|
178
|
-
|
|
327
|
+
if (task.error) {
|
|
328
|
+
throw new McpError(task.error.code, task.error.message, task.error.data);
|
|
329
|
+
}
|
|
330
|
+
const failedResult = (task.result ?? null);
|
|
331
|
+
const fallback = failedResult ?? {
|
|
332
|
+
content: [
|
|
333
|
+
{
|
|
334
|
+
type: 'text',
|
|
335
|
+
text: task.statusMessage ?? 'Task execution failed',
|
|
336
|
+
},
|
|
337
|
+
],
|
|
338
|
+
isError: true,
|
|
339
|
+
};
|
|
340
|
+
return Promise.resolve({
|
|
341
|
+
...fallback,
|
|
342
|
+
_meta: {
|
|
343
|
+
...fallback._meta,
|
|
344
|
+
'io.modelcontextprotocol/related-task': { taskId: task.taskId },
|
|
345
|
+
},
|
|
346
|
+
});
|
|
179
347
|
}
|
|
180
348
|
if (task.status === 'cancelled') {
|
|
181
|
-
throw new
|
|
349
|
+
throw new McpError(ErrorCode.InvalidRequest, 'Task was cancelled');
|
|
182
350
|
}
|
|
183
351
|
const result = (task.result ?? { content: [] });
|
|
184
352
|
return Promise.resolve({
|
|
@@ -189,8 +357,10 @@ function registerTaskHandlers(server) {
|
|
|
189
357
|
},
|
|
190
358
|
});
|
|
191
359
|
});
|
|
192
|
-
server.server.setRequestHandler(TaskListSchema, async () => {
|
|
193
|
-
const
|
|
360
|
+
server.server.setRequestHandler(TaskListSchema, async (request, extra) => {
|
|
361
|
+
const ownerKey = resolveTaskOwnerKey(extra);
|
|
362
|
+
const cursor = request.params?.cursor;
|
|
363
|
+
const { tasks, nextCursor } = taskManager.listTasks(cursor === undefined ? { ownerKey } : { ownerKey, cursor });
|
|
194
364
|
return Promise.resolve({
|
|
195
365
|
tasks: tasks.map((t) => ({
|
|
196
366
|
taskId: t.taskId,
|
|
@@ -200,14 +370,15 @@ function registerTaskHandlers(server) {
|
|
|
200
370
|
ttl: t.ttl,
|
|
201
371
|
pollInterval: t.pollInterval,
|
|
202
372
|
})),
|
|
203
|
-
nextCursor
|
|
373
|
+
nextCursor,
|
|
204
374
|
});
|
|
205
375
|
});
|
|
206
|
-
server.server.setRequestHandler(TaskCancelSchema, async (request) => {
|
|
376
|
+
server.server.setRequestHandler(TaskCancelSchema, async (request, extra) => {
|
|
207
377
|
const { taskId } = request.params;
|
|
208
|
-
const
|
|
378
|
+
const ownerKey = resolveTaskOwnerKey(extra);
|
|
379
|
+
const task = taskManager.cancelTask(taskId, ownerKey);
|
|
209
380
|
if (!task) {
|
|
210
|
-
|
|
381
|
+
throwTaskNotFound();
|
|
211
382
|
}
|
|
212
383
|
return Promise.resolve({
|
|
213
384
|
taskId: task.taskId,
|
|
@@ -220,19 +391,41 @@ function registerTaskHandlers(server) {
|
|
|
220
391
|
});
|
|
221
392
|
});
|
|
222
393
|
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
394
|
+
function registerPrompts(server) {
|
|
395
|
+
if (config.tools.enabled.includes(FETCH_URL_TOOL_NAME)) {
|
|
396
|
+
server.registerPrompt('summarize-webpage', {
|
|
397
|
+
description: 'Summarize the content of a webpage given its URL.',
|
|
398
|
+
argsSchema: {
|
|
399
|
+
url: z.string().describe('The URL to summarize'),
|
|
400
|
+
},
|
|
401
|
+
}, (args) => ({
|
|
402
|
+
messages: [
|
|
403
|
+
{
|
|
404
|
+
role: 'user',
|
|
405
|
+
content: {
|
|
406
|
+
type: 'text',
|
|
407
|
+
text: `Please summarize the content of the webpage at the following URL: ${args.url}`,
|
|
408
|
+
},
|
|
409
|
+
},
|
|
410
|
+
],
|
|
411
|
+
}));
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
export async function createMcpServer() {
|
|
415
|
+
const instructions = await createServerInstructions(config.server.version);
|
|
416
|
+
const serverInfo = await createServerInfo();
|
|
417
|
+
const server = new McpServer(serverInfo, {
|
|
226
418
|
capabilities: createServerCapabilities(),
|
|
227
419
|
instructions,
|
|
228
420
|
});
|
|
229
421
|
setMcpServer(server);
|
|
230
|
-
const localIcons = getLocalIcons();
|
|
231
|
-
registerTools(server
|
|
422
|
+
const localIcons = await getLocalIcons();
|
|
423
|
+
registerTools(server);
|
|
232
424
|
registerCachedContentResource(server, localIcons);
|
|
233
425
|
registerInstructionsResource(server, instructions);
|
|
234
426
|
registerConfigResource(server);
|
|
235
427
|
registerTaskHandlers(server);
|
|
428
|
+
registerPrompts(server);
|
|
236
429
|
return server;
|
|
237
430
|
}
|
|
238
431
|
function attachServerErrorHandler(server) {
|
|
@@ -290,7 +483,7 @@ async function connectStdioServer(server, transport) {
|
|
|
290
483
|
}
|
|
291
484
|
}
|
|
292
485
|
export async function startStdioServer() {
|
|
293
|
-
const server = createMcpServer();
|
|
486
|
+
const server = await createMcpServer();
|
|
294
487
|
const transport = new StdioServerTransport();
|
|
295
488
|
attachServerErrorHandler(server);
|
|
296
489
|
registerSignalHandlers(createShutdownHandler(server));
|
package/dist/observability.js
CHANGED
|
@@ -65,11 +65,12 @@ function writeLog(level, message, meta) {
|
|
|
65
65
|
return;
|
|
66
66
|
process.stderr.write(`${formatLogEntry(level, message, meta)}\n`);
|
|
67
67
|
if (mcpServer) {
|
|
68
|
+
const sessionId = getSessionId();
|
|
68
69
|
mcpServer.server
|
|
69
70
|
.sendLoggingMessage({
|
|
70
71
|
level: mapToMcpLevel(level),
|
|
71
72
|
data: meta ? { message, ...meta } : message,
|
|
72
|
-
})
|
|
73
|
+
}, sessionId)
|
|
73
74
|
.catch(() => { });
|
|
74
75
|
}
|
|
75
76
|
}
|
package/dist/tasks.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
export type TaskStatus = 'working' | 'input_required' | 'completed' | 'failed' | 'cancelled';
|
|
2
|
+
export interface TaskError {
|
|
3
|
+
code: number;
|
|
4
|
+
message: string;
|
|
5
|
+
data?: unknown;
|
|
6
|
+
}
|
|
2
7
|
export interface TaskState {
|
|
3
8
|
taskId: string;
|
|
9
|
+
ownerKey: string;
|
|
4
10
|
status: TaskStatus;
|
|
5
11
|
statusMessage?: string;
|
|
6
12
|
createdAt: string;
|
|
@@ -8,7 +14,7 @@ export interface TaskState {
|
|
|
8
14
|
ttl: number;
|
|
9
15
|
pollInterval: number;
|
|
10
16
|
result?: unknown;
|
|
11
|
-
error?:
|
|
17
|
+
error?: TaskError;
|
|
12
18
|
}
|
|
13
19
|
export interface CreateTaskOptions {
|
|
14
20
|
ttl?: number;
|
|
@@ -27,11 +33,24 @@ export interface CreateTaskResult {
|
|
|
27
33
|
}
|
|
28
34
|
export declare class TaskManager {
|
|
29
35
|
private tasks;
|
|
30
|
-
|
|
31
|
-
|
|
36
|
+
private waiters;
|
|
37
|
+
createTask(options?: CreateTaskOptions, statusMessage?: string, ownerKey?: string): TaskState;
|
|
38
|
+
getTask(taskId: string, ownerKey?: string): TaskState | undefined;
|
|
32
39
|
updateTask(taskId: string, updates: Partial<Omit<TaskState, 'taskId' | 'createdAt'>>): void;
|
|
33
|
-
cancelTask(taskId: string): TaskState | undefined;
|
|
34
|
-
listTasks(
|
|
40
|
+
cancelTask(taskId: string, ownerKey?: string): TaskState | undefined;
|
|
41
|
+
listTasks(options: {
|
|
42
|
+
ownerKey: string;
|
|
43
|
+
cursor?: string;
|
|
44
|
+
limit?: number;
|
|
45
|
+
}): {
|
|
46
|
+
tasks: TaskState[];
|
|
47
|
+
nextCursor?: string;
|
|
48
|
+
};
|
|
35
49
|
cleanupExpiredTasks(): number;
|
|
50
|
+
waitForTerminalTask(taskId: string, ownerKey: string, signal?: AbortSignal): Promise<TaskState | undefined>;
|
|
51
|
+
private notifyWaiters;
|
|
52
|
+
private isExpired;
|
|
53
|
+
private encodeCursor;
|
|
54
|
+
private decodeCursor;
|
|
36
55
|
}
|
|
37
56
|
export declare const taskManager: TaskManager;
|