mcp-probe-kit 3.0.3 → 3.0.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.
Files changed (60) hide show
  1. package/README.md +457 -423
  2. package/build/index.js +434 -140
  3. package/build/lib/template-loader.js +317 -317
  4. package/build/lib/tool-execution-context.d.ts +8 -0
  5. package/build/lib/tool-execution-context.js +20 -0
  6. package/build/schemas/git-tools.js +16 -16
  7. package/build/tools/__tests__/start_bugfix.unit.test.js +14 -14
  8. package/build/tools/__tests__/start_ui.unit.test.js +11 -11
  9. package/build/tools/add_feature.js +79 -79
  10. package/build/tools/ask_user.js +5 -5
  11. package/build/tools/interview.js +9 -9
  12. package/build/tools/start_bugfix.d.ts +2 -1
  13. package/build/tools/start_bugfix.js +131 -122
  14. package/build/tools/start_feature.d.ts +2 -1
  15. package/build/tools/start_feature.js +113 -104
  16. package/build/tools/start_onboard.d.ts +2 -1
  17. package/build/tools/start_onboard.js +57 -51
  18. package/build/tools/start_product.d.ts +2 -1
  19. package/build/tools/start_product.js +9 -1
  20. package/build/tools/start_ralph.d.ts +2 -1
  21. package/build/tools/start_ralph.js +9 -3
  22. package/build/tools/start_ui.d.ts +2 -1
  23. package/build/tools/start_ui.js +102 -88
  24. package/build/tools/ui-ux-tools.d.ts +2 -1
  25. package/build/tools/ui-ux-tools.js +19 -3
  26. package/build/utils/ui-sync.d.ts +6 -2
  27. package/build/utils/ui-sync.js +125 -29
  28. package/docs/assets/font/MaterialSymbolsOutlined.codepoints +4102 -0
  29. package/docs/assets/font/MaterialSymbolsOutlined.ttf +0 -0
  30. package/docs/assets/font/noto-sans-sc-400.ttf +0 -0
  31. package/docs/assets/font/noto-sans-sc-700.ttf +0 -0
  32. package/docs/assets/font/noto-sans-sc-900.ttf +0 -0
  33. package/docs/assets/js/i18n.js +375 -0
  34. package/docs/assets/js/tailwind.js +83 -83
  35. package/docs/assets/logo-zh.png +0 -0
  36. package/docs/assets/logo.png +0 -0
  37. package/docs/data/tools.js +21 -21
  38. package/docs/debug-i18n.html +163 -0
  39. package/docs/i18n/all-tools/en.json +157 -0
  40. package/docs/i18n/all-tools/ja.json +157 -0
  41. package/docs/i18n/all-tools/ko.json +157 -0
  42. package/docs/i18n/all-tools/zh-CN.json +157 -0
  43. package/docs/i18n/en.json +518 -0
  44. package/docs/i18n/ja.json +518 -0
  45. package/docs/i18n/ko.json +518 -0
  46. package/docs/i18n/zh-CN.json +518 -0
  47. package/docs/index.html +43 -32
  48. package/docs/pages/all-tools.html +514 -330
  49. package/docs/pages/examples.html +689 -673
  50. package/docs/pages/getting-started.html +589 -577
  51. package/docs/pages/migration.html +298 -283
  52. package/package.json +6 -6
  53. package/docs/project-context/architecture.md +0 -0
  54. package/docs/project-context/how-to-develop.md +0 -313
  55. package/docs/project-context/how-to-test.md +0 -457
  56. package/docs/project-context/tech-stack.md +0 -96
  57. package/docs/project-context.md +0 -53
  58. package/docs/specs/git-work-report/design.md +0 -568
  59. package/docs/specs/git-work-report/requirements.md +0 -131
  60. package/docs/specs/git-work-report/tasks.md +0 -197
package/build/index.js CHANGED
@@ -1,20 +1,199 @@
1
1
  #!/usr/bin/env node
2
2
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
3
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
- import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
4
+ import { InMemoryTaskMessageQueue, InMemoryTaskStore, } from "@modelcontextprotocol/sdk/experimental/index.js";
5
+ import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ProgressNotificationSchema, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
5
6
  import { initProject, gencommit, codeReview, gentest, refactor, initProjectContext, addFeature, fixBug, estimate, startFeature, startBugfix, startOnboard, startRalph, interview, askUser, uiDesignSystem, uiSearch, syncUiData, startUi, startProduct, gitWorkReport } from "./tools/index.js";
6
7
  import { VERSION, NAME } from "./version.js";
7
8
  import { allToolSchemas } from "./schemas/index.js";
8
9
  import { filterTools, getToolsetFromEnv } from "./lib/toolset-manager.js";
10
+ import { isAbortError, } from "./lib/tool-execution-context.js";
11
+ const EXTENSIONS_CAPABILITY_KEY = "io.github.mybolide/extensions";
12
+ const MAX_UI_APP_RESOURCES = 30;
13
+ const uiAppResources = new Map();
14
+ const uiAppResourceOrder = [];
15
+ function isEnvEnabled(name, fallback = false) {
16
+ const raw = process.env[name];
17
+ if (raw === undefined) {
18
+ return fallback;
19
+ }
20
+ return /^(1|true|yes|on)$/i.test(raw.trim());
21
+ }
22
+ const extensionsCapabilityEnabled = isEnvEnabled("MCP_ENABLE_EXTENSIONS_CAPABILITY", false);
23
+ const uiAppsEnabled = isEnvEnabled("MCP_ENABLE_UI_APPS", false);
24
+ const traceMetaKey = process.env.MCP_TRACE_META_KEY || "trace";
25
+ const serverCapabilities = {
26
+ tools: {},
27
+ resources: {},
28
+ tasks: {
29
+ list: {},
30
+ cancel: {},
31
+ requests: {
32
+ tools: {
33
+ call: {},
34
+ },
35
+ },
36
+ },
37
+ };
38
+ if (extensionsCapabilityEnabled) {
39
+ serverCapabilities.experimental = {
40
+ [EXTENSIONS_CAPABILITY_KEY]: {
41
+ traceMetaPassthrough: true,
42
+ traceMetaKey,
43
+ uiApps: uiAppsEnabled,
44
+ uiAppsMetaKey: "ui.resourceUri",
45
+ },
46
+ };
47
+ }
48
+ function getTraceMeta(meta) {
49
+ if (!meta || typeof meta !== "object") {
50
+ return undefined;
51
+ }
52
+ const metaRecord = meta;
53
+ if (traceMetaKey in metaRecord) {
54
+ return metaRecord[traceMetaKey];
55
+ }
56
+ return metaRecord.trace;
57
+ }
58
+ function withTraceMeta(result, traceMeta) {
59
+ if (traceMeta === undefined) {
60
+ return result;
61
+ }
62
+ return {
63
+ ...result,
64
+ _meta: {
65
+ ...(result._meta ?? {}),
66
+ [traceMetaKey]: traceMeta,
67
+ },
68
+ };
69
+ }
70
+ function escapeHtml(value) {
71
+ return value
72
+ .replace(/&/g, "&")
73
+ .replace(/</g, "&lt;")
74
+ .replace(/>/g, "&gt;")
75
+ .replace(/"/g, "&quot;")
76
+ .replace(/'/g, "&#39;");
77
+ }
78
+ function isUiTool(name) {
79
+ return [
80
+ "ui_design_system",
81
+ "ui_search",
82
+ "sync_ui_data",
83
+ "start_ui",
84
+ "start_product",
85
+ ].includes(name);
86
+ }
87
+ function buildUiResourceHtml(name, args, result) {
88
+ const structured = result.structuredContent
89
+ ? JSON.stringify(result.structuredContent, null, 2)
90
+ : "{}";
91
+ const argJson = JSON.stringify(args ?? {}, null, 2);
92
+ const textBlocks = Array.isArray(result.content)
93
+ ? result.content
94
+ .map((item) => {
95
+ if (!item || typeof item !== "object") {
96
+ return "";
97
+ }
98
+ const text = item.text;
99
+ return typeof text === "string" ? text : "";
100
+ })
101
+ .filter(Boolean)
102
+ .join("\n\n")
103
+ : "";
104
+ const now = new Date().toISOString();
105
+ return `<!doctype html>
106
+ <html lang="zh-CN">
107
+ <head>
108
+ <meta charset="utf-8">
109
+ <meta name="viewport" content="width=device-width, initial-scale=1">
110
+ <title>${escapeHtml(name)} · MCP Apps</title>
111
+ <style>
112
+ :root { color-scheme: light; }
113
+ body { font-family: "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif; margin: 0; background: #f4f7fb; color: #1e2a35; }
114
+ .wrap { max-width: 960px; margin: 0 auto; padding: 24px; }
115
+ .card { background: #fff; border-radius: 14px; padding: 18px; box-shadow: 0 4px 18px rgba(30,42,53,.08); margin-bottom: 16px; }
116
+ h1 { margin: 0 0 8px; font-size: 24px; }
117
+ h2 { margin: 0 0 10px; font-size: 16px; color: #2f4a65; }
118
+ pre { white-space: pre-wrap; word-break: break-word; background: #0f1720; color: #d9e7f7; border-radius: 10px; padding: 12px; font-size: 12px; line-height: 1.45; }
119
+ .meta { color: #4f6880; font-size: 12px; }
120
+ </style>
121
+ </head>
122
+ <body>
123
+ <div class="wrap">
124
+ <div class="card">
125
+ <h1>${escapeHtml(name)}</h1>
126
+ <div class="meta">Generated at ${escapeHtml(now)} · MCP Apps preview</div>
127
+ </div>
128
+ <div class="card">
129
+ <h2>Text Output</h2>
130
+ <pre>${escapeHtml(textBlocks || "(no text output)")}</pre>
131
+ </div>
132
+ <div class="card">
133
+ <h2>Structured Content</h2>
134
+ <pre>${escapeHtml(structured)}</pre>
135
+ </div>
136
+ <div class="card">
137
+ <h2>Arguments</h2>
138
+ <pre>${escapeHtml(argJson)}</pre>
139
+ </div>
140
+ </div>
141
+ </body>
142
+ </html>`;
143
+ }
144
+ function putUiAppResource(toolName, args, result) {
145
+ const uid = `${Date.now()}-${Math.random().toString(16).slice(2, 10)}`;
146
+ const uri = `ui://mcp-probe-kit/${toolName}/${uid}`;
147
+ const entry = {
148
+ uri,
149
+ name: `UI Preview · ${toolName}`,
150
+ description: `MCP Apps preview generated by ${toolName}`,
151
+ mimeType: "text/html",
152
+ text: buildUiResourceHtml(toolName, args, result),
153
+ createdAt: new Date().toISOString(),
154
+ };
155
+ uiAppResources.set(uri, entry);
156
+ uiAppResourceOrder.push(uri);
157
+ while (uiAppResourceOrder.length > MAX_UI_APP_RESOURCES) {
158
+ const oldest = uiAppResourceOrder.shift();
159
+ if (oldest) {
160
+ uiAppResources.delete(oldest);
161
+ }
162
+ }
163
+ return uri;
164
+ }
165
+ function withUiResourceMeta(result, resourceUri) {
166
+ const currentUi = result._meta?.ui;
167
+ const currentUiRecord = currentUi && typeof currentUi === "object"
168
+ ? currentUi
169
+ : {};
170
+ return {
171
+ ...result,
172
+ _meta: {
173
+ ...(result._meta ?? {}),
174
+ ui: {
175
+ ...currentUiRecord,
176
+ resourceUri,
177
+ },
178
+ },
179
+ };
180
+ }
181
+ function decorateResult(toolName, args, raw, traceMeta) {
182
+ let result = withTraceMeta(raw, traceMeta);
183
+ if (uiAppsEnabled && isUiTool(toolName) && !result.isError) {
184
+ const resourceUri = putUiAppResource(toolName, args, result);
185
+ result = withUiResourceMeta(result, resourceUri);
186
+ }
187
+ return result;
188
+ }
9
189
  // 创建MCP服务器实例
10
190
  const server = new Server({
11
191
  name: NAME,
12
192
  version: VERSION,
13
193
  }, {
14
- capabilities: {
15
- tools: {},
16
- resources: {},
17
- },
194
+ capabilities: serverCapabilities,
195
+ taskStore: new InMemoryTaskStore(),
196
+ taskMessageQueue: new InMemoryTaskMessageQueue(),
18
197
  });
19
198
  // 定义工具列表 - 从 schemas 导入,并根据工具集过滤
20
199
  server.setRequestHandler(ListToolsRequestSchema, async () => {
@@ -25,86 +204,243 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
25
204
  tools: filteredTools,
26
205
  };
27
206
  });
207
+ async function executeTool(name, args, context) {
208
+ switch (name) {
209
+ case "init_project":
210
+ return await initProject(args);
211
+ case "gencommit":
212
+ return await gencommit(args);
213
+ case "code_review":
214
+ return await codeReview(args);
215
+ case "gentest":
216
+ return await gentest(args);
217
+ case "refactor":
218
+ return await refactor(args);
219
+ case "init_project_context":
220
+ return await initProjectContext(args);
221
+ case "add_feature":
222
+ return await addFeature(args);
223
+ case "fix_bug":
224
+ return await fixBug(args);
225
+ case "estimate":
226
+ return await estimate(args);
227
+ case "start_feature":
228
+ return await startFeature(args, context);
229
+ case "start_bugfix":
230
+ return await startBugfix(args, context);
231
+ case "start_onboard":
232
+ return await startOnboard(args, context);
233
+ case "start_ralph":
234
+ return await startRalph(args, context);
235
+ case "interview":
236
+ return await interview(args);
237
+ case "ask_user":
238
+ return await askUser(args);
239
+ case "ui_design_system":
240
+ return await uiDesignSystem(args);
241
+ case "ui_search":
242
+ return await uiSearch(args);
243
+ case "sync_ui_data":
244
+ return await syncUiData(args, context);
245
+ case "start_ui":
246
+ return await startUi(args, context);
247
+ case "start_product":
248
+ return await startProduct((args ?? {}), context);
249
+ case "git_work_report":
250
+ return await gitWorkReport(args);
251
+ default:
252
+ throw new Error(`未知工具: ${name}`);
253
+ }
254
+ }
255
+ function makeToolError(errorMessage) {
256
+ return {
257
+ content: [
258
+ {
259
+ type: "text",
260
+ text: `错误: ${errorMessage}`,
261
+ },
262
+ ],
263
+ isError: true,
264
+ };
265
+ }
266
+ function isTerminalTaskStatus(status) {
267
+ return status === "completed" || status === "failed" || status === "cancelled";
268
+ }
28
269
  // 处理工具调用
29
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
270
+ server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
30
271
  const { name, arguments: args } = request.params;
272
+ const taskRequest = request.params.task;
273
+ const traceMeta = getTraceMeta(extra._meta);
274
+ const emitProgress = async (progress, message) => {
275
+ const progressToken = extra._meta?.progressToken;
276
+ if (progressToken === undefined) {
277
+ return;
278
+ }
279
+ try {
280
+ await extra.sendNotification(ProgressNotificationSchema.parse({
281
+ method: "notifications/progress",
282
+ params: {
283
+ progressToken,
284
+ progress,
285
+ total: 100,
286
+ message,
287
+ ...(traceMeta === undefined
288
+ ? {}
289
+ : {
290
+ _meta: {
291
+ [traceMetaKey]: traceMeta,
292
+ },
293
+ }),
294
+ },
295
+ }));
296
+ }
297
+ catch (error) {
298
+ const err = error instanceof Error ? error.message : String(error);
299
+ console.error(`[MCP Probe Kit] progress notification failed: ${err}`);
300
+ }
301
+ };
302
+ if (taskRequest) {
303
+ if (!extra.taskStore) {
304
+ return withTraceMeta(makeToolError("服务器未启用任务存储,无法创建任务"), traceMeta);
305
+ }
306
+ const task = await extra.taskStore.createTask({
307
+ ttl: extra.taskRequestedTtl ?? taskRequest.ttl,
308
+ });
309
+ const taskAbortController = new AbortController();
310
+ const cancelWatcher = setInterval(() => {
311
+ void (async () => {
312
+ try {
313
+ const latestTask = await extra.taskStore?.getTask(task.taskId);
314
+ if (latestTask?.status === "cancelled" && !taskAbortController.signal.aborted) {
315
+ taskAbortController.abort();
316
+ }
317
+ }
318
+ catch {
319
+ // ignore watcher errors
320
+ }
321
+ })();
322
+ }, 400);
323
+ const onRequestAbort = () => taskAbortController.abort();
324
+ extra.signal.addEventListener("abort", onRequestAbort, { once: true });
325
+ const taskContext = {
326
+ signal: taskAbortController.signal,
327
+ traceMeta,
328
+ reportProgress: async (progress, message) => {
329
+ const normalized = Math.max(0, Math.min(100, Math.round(progress)));
330
+ await emitProgress(normalized, message);
331
+ try {
332
+ await extra.taskStore?.updateTaskStatus(task.taskId, "working", `[${normalized}%] ${message}`);
333
+ }
334
+ catch {
335
+ // task may have already reached terminal status
336
+ }
337
+ },
338
+ };
339
+ // 后台执行任务,不阻塞当前请求,立即返回 taskId 给客户端轮询。
340
+ void (async () => {
341
+ try {
342
+ await taskContext.reportProgress?.(5, `开始执行工具: ${name}`);
343
+ const rawResult = await executeTool(name, args, taskContext);
344
+ if (!rawResult || typeof rawResult !== "object") {
345
+ throw new Error(`工具 ${name} 返回了无效响应`);
346
+ }
347
+ const result = decorateResult(name, args, rawResult, traceMeta);
348
+ const latestTask = await extra.taskStore?.getTask(task.taskId);
349
+ if (!latestTask || isTerminalTaskStatus(latestTask.status)) {
350
+ return;
351
+ }
352
+ const status = result && typeof result === "object" && "isError" in result && result.isError
353
+ ? "failed"
354
+ : "completed";
355
+ await extra.taskStore?.storeTaskResult(task.taskId, status, result);
356
+ }
357
+ catch (error) {
358
+ if (isAbortError(error)) {
359
+ const latestTask = await extra.taskStore?.getTask(task.taskId);
360
+ if (!latestTask || isTerminalTaskStatus(latestTask.status)) {
361
+ return;
362
+ }
363
+ await extra.taskStore?.storeTaskResult(task.taskId, "failed", withTraceMeta(makeToolError(`工具执行已取消: ${name}`), traceMeta));
364
+ return;
365
+ }
366
+ const errorMessage = error instanceof Error ? error.message : String(error);
367
+ const latestTask = await extra.taskStore?.getTask(task.taskId);
368
+ if (!latestTask || isTerminalTaskStatus(latestTask.status)) {
369
+ return;
370
+ }
371
+ await extra.taskStore?.storeTaskResult(task.taskId, "failed", withTraceMeta(makeToolError(errorMessage), traceMeta));
372
+ }
373
+ })().catch((error) => {
374
+ const err = error instanceof Error ? error.message : String(error);
375
+ console.error(`[MCP Probe Kit] task execution failed: ${err}`);
376
+ }).finally(() => {
377
+ clearInterval(cancelWatcher);
378
+ extra.signal.removeEventListener("abort", onRequestAbort);
379
+ });
380
+ return withTraceMeta({ task }, traceMeta);
381
+ }
382
+ const ensureNotAborted = () => {
383
+ if (extra.signal.aborted) {
384
+ throw new Error(`工具执行已取消: ${name}`);
385
+ }
386
+ };
387
+ const toolContext = {
388
+ signal: extra.signal,
389
+ traceMeta,
390
+ reportProgress: async (progress, message) => {
391
+ const normalized = Math.max(0, Math.min(100, Math.round(progress)));
392
+ await emitProgress(normalized, message);
393
+ },
394
+ };
31
395
  try {
32
- switch (name) {
33
- case "init_project":
34
- return await initProject(args);
35
- case "gencommit":
36
- return await gencommit(args);
37
- case "code_review":
38
- return await codeReview(args);
39
- case "gentest":
40
- return await gentest(args);
41
- case "refactor":
42
- return await refactor(args);
43
- case "init_project_context":
44
- return await initProjectContext(args);
45
- case "add_feature":
46
- return await addFeature(args);
47
- case "fix_bug":
48
- return await fixBug(args);
49
- case "estimate":
50
- return await estimate(args);
51
- // 智能编排工具
52
- case "start_feature":
53
- return await startFeature(args);
54
- case "start_bugfix":
55
- return await startBugfix(args);
56
- case "start_onboard":
57
- return await startOnboard(args);
58
- case "start_ralph":
59
- return await startRalph(args);
60
- // 访谈工具
61
- case "interview":
62
- return await interview(args);
63
- case "ask_user":
64
- return await askUser(args);
65
- // UI/UX Pro Max 工具
66
- case "ui_design_system":
67
- return await uiDesignSystem(args);
68
- case "ui_search":
69
- return await uiSearch(args);
70
- case "sync_ui_data":
71
- return await syncUiData(args);
72
- case "start_ui":
73
- return await startUi(args);
74
- // 产品设计工作流
75
- case "start_product":
76
- return await startProduct(args || {});
77
- // Git 工具
78
- case "git_work_report":
79
- return await gitWorkReport(args);
80
- default:
81
- throw new Error(`未知工具: ${name}`);
396
+ ensureNotAborted();
397
+ await emitProgress(5, `开始执行工具: ${name}`);
398
+ const rawResult = await executeTool(name, args, toolContext);
399
+ if (!rawResult || typeof rawResult !== "object") {
400
+ throw new Error(`工具 ${name} 返回了无效响应`);
82
401
  }
402
+ ensureNotAborted();
403
+ const result = decorateResult(name, args, rawResult, traceMeta);
404
+ await emitProgress(100, `工具执行完成: ${name}`);
405
+ return result;
83
406
  }
84
407
  catch (error) {
408
+ if (extra.signal.aborted) {
409
+ await emitProgress(100, `工具执行已取消: ${name}`);
410
+ }
411
+ else {
412
+ await emitProgress(100, `工具执行失败: ${name}`);
413
+ }
85
414
  const errorMessage = error instanceof Error ? error.message : String(error);
86
- return {
87
- content: [
88
- {
89
- type: "text",
90
- text: `错误: ${errorMessage}`,
91
- },
92
- ],
93
- isError: true,
94
- };
415
+ return withTraceMeta(makeToolError(errorMessage), traceMeta);
95
416
  }
96
417
  });
97
418
  // 定义资源列表
98
419
  server.setRequestHandler(ListResourcesRequestSchema, async () => {
420
+ const resources = [
421
+ {
422
+ uri: "probe://status",
423
+ name: "服务器状态",
424
+ description: "MCP Probe Kit 服务器当前状态",
425
+ mimeType: "application/json",
426
+ },
427
+ ];
428
+ if (uiAppsEnabled) {
429
+ for (const uri of uiAppResourceOrder.slice().reverse()) {
430
+ const entry = uiAppResources.get(uri);
431
+ if (!entry) {
432
+ continue;
433
+ }
434
+ resources.push({
435
+ uri: entry.uri,
436
+ name: entry.name,
437
+ description: `${entry.description} (${entry.createdAt})`,
438
+ mimeType: entry.mimeType,
439
+ });
440
+ }
441
+ }
99
442
  return {
100
- resources: [
101
- {
102
- uri: "probe://status",
103
- name: "服务器状态",
104
- description: "MCP Probe Kit 服务器当前状态",
105
- mimeType: "application/json",
106
- },
107
- ],
443
+ resources,
108
444
  };
109
445
  });
110
446
  // 读取资源
@@ -124,81 +460,39 @@ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
124
460
  version: VERSION,
125
461
  description: "AI 驱动的完整研发工具集",
126
462
  },
463
+ extensions: {
464
+ enabled: extensionsCapabilityEnabled,
465
+ traceMetaKey,
466
+ uiAppsEnabled,
467
+ },
468
+ experimentalTasksStreaming: {
469
+ requestStream: typeof server.experimental.tasks.requestStream === "function",
470
+ createMessageStream: typeof server.experimental.tasks.createMessageStream === "function",
471
+ elicitInputStream: typeof server.experimental.tasks.elicitInputStream === "function",
472
+ },
127
473
  toolCount: allToolSchemas.length,
128
474
  }, null, 2),
129
475
  },
130
476
  ],
131
477
  };
132
478
  }
479
+ if (uri.startsWith("ui://")) {
480
+ const entry = uiAppResources.get(uri);
481
+ if (!entry) {
482
+ throw new Error(`未知 UI 资源: ${uri}`);
483
+ }
484
+ return {
485
+ contents: [
486
+ {
487
+ uri: entry.uri,
488
+ mimeType: entry.mimeType,
489
+ text: entry.text,
490
+ },
491
+ ],
492
+ };
493
+ }
133
494
  throw new Error(`未知资源: ${uri}`);
134
495
  });
135
- // ============================================
136
- // Tasks API 端点 - 暂时禁用,等待 MCP SDK 正式支持
137
- // ============================================
138
- // 注意:当前 MCP SDK 版本不支持自定义 method,Tasks API 功能暂时禁用
139
- // 相关 issue: https://github.com/modelcontextprotocol/sdk/issues/xxx
140
- /*
141
- // 获取任务状态
142
- server.setRequestHandler({ method: "tasks/get" } as any, async (request: any) => {
143
- try {
144
- const { taskId } = request.params;
145
- const tasksManager = getTasksManager();
146
- const task = tasksManager.getTask(taskId);
147
-
148
- return {
149
- task,
150
- };
151
- } catch (error) {
152
- const errorMessage = error instanceof Error ? error.message : String(error);
153
- throw new Error(`Failed to get task: ${errorMessage}`);
154
- }
155
- });
156
-
157
- // 获取任务结果
158
- server.setRequestHandler({ method: "tasks/result" } as any, async (request: any) => {
159
- try {
160
- const { taskId } = request.params;
161
- const tasksManager = getTasksManager();
162
- const result = tasksManager.getTaskResult(taskId);
163
-
164
- return result;
165
- } catch (error) {
166
- const errorMessage = error instanceof Error ? error.message : String(error);
167
- throw new Error(`Failed to get task result: ${errorMessage}`);
168
- }
169
- });
170
-
171
- // 取消任务
172
- server.setRequestHandler({ method: "tasks/cancel" } as any, async (request: any) => {
173
- try {
174
- const { taskId } = request.params;
175
- const tasksManager = getTasksManager();
176
- tasksManager.cancelTask(taskId);
177
-
178
- return {
179
- _meta: {},
180
- };
181
- } catch (error) {
182
- const errorMessage = error instanceof Error ? error.message : String(error);
183
- throw new Error(`Failed to cancel task: ${errorMessage}`);
184
- }
185
- });
186
-
187
- // 列出所有任务
188
- server.setRequestHandler({ method: "tasks/list" } as any, async () => {
189
- try {
190
- const tasksManager = getTasksManager();
191
- const tasks = tasksManager.listTasks();
192
-
193
- return {
194
- tasks,
195
- };
196
- } catch (error) {
197
- const errorMessage = error instanceof Error ? error.message : String(error);
198
- throw new Error(`Failed to list tasks: ${errorMessage}`);
199
- }
200
- });
201
- */
202
496
  // 启动服务器
203
497
  async function main() {
204
498
  const transport = new StdioServerTransport();