mcp-probe-kit 3.2.0 → 3.6.0

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 (180) hide show
  1. package/README.md +25 -7
  2. package/build/index.js +45 -79
  3. package/build/lib/__tests__/agents-md-template.unit.test.js +1 -0
  4. package/build/lib/__tests__/dev-workflow.unit.test.js +22 -0
  5. package/build/lib/__tests__/handles.unit.test.js +19 -0
  6. package/build/lib/__tests__/mcp-apps.unit.test.d.ts +1 -0
  7. package/build/lib/__tests__/mcp-apps.unit.test.js +52 -0
  8. package/build/lib/__tests__/mcp-tool-skill-registry.unit.test.d.ts +1 -0
  9. package/build/lib/__tests__/mcp-tool-skill-registry.unit.test.js +18 -0
  10. package/build/lib/__tests__/memory-client.unit.test.js +105 -0
  11. package/build/lib/__tests__/memory-orchestration.unit.test.d.ts +1 -0
  12. package/build/lib/__tests__/memory-orchestration.unit.test.js +88 -0
  13. package/build/lib/__tests__/memory-payload.unit.test.d.ts +1 -0
  14. package/build/lib/__tests__/memory-payload.unit.test.js +35 -0
  15. package/build/lib/__tests__/quality-constraints.unit.test.d.ts +1 -0
  16. package/build/lib/__tests__/quality-constraints.unit.test.js +54 -0
  17. package/build/lib/__tests__/spec-gate.unit.test.d.ts +1 -0
  18. package/build/lib/__tests__/spec-gate.unit.test.js +54 -0
  19. package/build/lib/__tests__/spec-validator.unit.test.js +106 -74
  20. package/build/lib/__tests__/task-defaults.unit.test.d.ts +1 -0
  21. package/build/lib/__tests__/task-defaults.unit.test.js +27 -0
  22. package/build/lib/__tests__/workflow-skill-installer.unit.test.d.ts +1 -0
  23. package/build/lib/__tests__/workflow-skill-installer.unit.test.js +110 -0
  24. package/build/lib/agents-md-template.js +40 -32
  25. package/build/lib/cursor-history-client.d.ts +54 -0
  26. package/build/lib/cursor-history-client.js +240 -0
  27. package/build/lib/dev-workflow.d.ts +36 -0
  28. package/build/lib/dev-workflow.js +497 -0
  29. package/build/lib/handles.d.ts +31 -0
  30. package/build/lib/handles.js +36 -0
  31. package/build/lib/mcp-apps.d.ts +14 -0
  32. package/build/lib/mcp-apps.js +234 -0
  33. package/build/lib/mcp-tool-skill-registry.d.ts +46 -0
  34. package/build/lib/mcp-tool-skill-registry.js +256 -0
  35. package/build/lib/memory-client.d.ts +19 -0
  36. package/build/lib/memory-client.js +69 -0
  37. package/build/lib/memory-orchestration.d.ts +5 -0
  38. package/build/lib/memory-orchestration.js +20 -0
  39. package/build/lib/merge-agents-md.d.ts +2 -2
  40. package/build/lib/merge-agents-md.js +7 -4
  41. package/build/lib/output-schema-registry.d.ts +11 -0
  42. package/build/lib/output-schema-registry.js +80 -0
  43. package/build/lib/quality-constraints.d.ts +54 -0
  44. package/build/lib/quality-constraints.js +155 -0
  45. package/build/lib/skill-bridge.js +12 -12
  46. package/build/lib/spec-gate.d.ts +32 -0
  47. package/build/lib/spec-gate.js +83 -0
  48. package/build/lib/spec-validator.js +16 -3
  49. package/build/lib/task-defaults.d.ts +6 -0
  50. package/build/lib/task-defaults.js +20 -0
  51. package/build/lib/template-loader.js +83 -23
  52. package/build/lib/tool-annotations.js +3 -0
  53. package/build/lib/toolset-manager.js +2 -0
  54. package/build/lib/workflow-skill-installer.d.ts +38 -0
  55. package/build/lib/workflow-skill-installer.js +158 -0
  56. package/build/lib/workflow-skill-template.d.ts +9 -0
  57. package/build/lib/workflow-skill-template.js +85 -0
  58. package/build/lib/workflow-skill-version.d.ts +15 -0
  59. package/build/lib/workflow-skill-version.js +68 -0
  60. package/build/resources/ui-ux-data/guidelines/vercel-web-interface.json +1632 -1632
  61. package/build/resources/ui-ux-data/metadata.json +30 -30
  62. package/build/resources/ui-ux-data/shadcn/blocks.json +2541 -2541
  63. package/build/resources/ui-ux-data/shadcn/components.json +997 -997
  64. package/build/resources/ui-ux-data/themes/presets.json +483 -483
  65. package/build/schemas/index.d.ts +110 -0
  66. package/build/schemas/index.js +1 -0
  67. package/build/schemas/memory-tools.d.ts +83 -0
  68. package/build/schemas/memory-tools.js +43 -0
  69. package/build/schemas/orchestration-tools.d.ts +8 -0
  70. package/build/schemas/orchestration-tools.js +8 -0
  71. package/build/schemas/output/code-insight-tools.d.ts +65 -0
  72. package/build/schemas/output/code-insight-tools.js +42 -0
  73. package/build/schemas/output/memory-tools.d.ts +576 -0
  74. package/build/schemas/output/memory-tools.js +148 -0
  75. package/build/schemas/project-tools.d.ts +19 -0
  76. package/build/schemas/project-tools.js +20 -0
  77. package/build/tools/__tests__/cursor-history.unit.test.d.ts +1 -0
  78. package/build/tools/__tests__/cursor-history.unit.test.js +38 -0
  79. package/build/tools/__tests__/delete_memory_asset.unit.test.d.ts +1 -0
  80. package/build/tools/__tests__/delete_memory_asset.unit.test.js +87 -0
  81. package/build/tools/__tests__/search_memory.unit.test.js +1 -0
  82. package/build/tools/__tests__/start_bugfix.unit.test.js +34 -1
  83. package/build/tools/__tests__/update_memory_asset.unit.test.d.ts +1 -0
  84. package/build/tools/__tests__/update_memory_asset.unit.test.js +82 -0
  85. package/build/tools/__tests__/workflow.unit.test.d.ts +1 -0
  86. package/build/tools/__tests__/workflow.unit.test.js +24 -0
  87. package/build/tools/check_spec.js +16 -16
  88. package/build/tools/code_insight.js +46 -42
  89. package/build/tools/code_review.js +11 -4
  90. package/build/tools/cursor_read_conversation.d.ts +7 -0
  91. package/build/tools/cursor_read_conversation.js +36 -0
  92. package/build/tools/delete_memory_asset.d.ts +7 -0
  93. package/build/tools/delete_memory_asset.js +57 -0
  94. package/build/tools/fix_bug.js +161 -161
  95. package/build/tools/gencommit.js +60 -60
  96. package/build/tools/index.d.ts +3 -0
  97. package/build/tools/index.js +3 -0
  98. package/build/tools/init_project_context.js +432 -432
  99. package/build/tools/search_memory.js +5 -2
  100. package/build/tools/start_bugfix.js +37 -4
  101. package/build/tools/start_feature.js +4 -3
  102. package/build/tools/start_product.js +1 -1
  103. package/build/tools/start_ui.js +22 -4
  104. package/build/tools/ui-ux-tools.d.ts +3 -0
  105. package/build/tools/ui-ux-tools.js +302 -290
  106. package/build/tools/update_memory_asset.d.ts +7 -0
  107. package/build/tools/update_memory_asset.js +98 -0
  108. package/build/tools/workflow.d.ts +13 -0
  109. package/build/tools/workflow.js +69 -0
  110. package/build/utils/__tests__/vercel-guidelines-sync.unit.test.js +12 -12
  111. package/build/utils/design-reasoning-engine.d.ts +2 -0
  112. package/build/utils/design-reasoning-engine.js +3 -0
  113. package/build/utils/themes-sync.js +8 -8
  114. package/package.json +6 -3
  115. package/build/resources/index.d.ts +0 -4
  116. package/build/resources/index.js +0 -4
  117. package/build/resources/tool-params-guide.d.ts +0 -571
  118. package/build/resources/tool-params-guide.js +0 -488
  119. package/build/tools/analyze_project.d.ts +0 -1
  120. package/build/tools/analyze_project.js +0 -527
  121. package/build/tools/check_deps.d.ts +0 -13
  122. package/build/tools/check_deps.js +0 -204
  123. package/build/tools/convert.d.ts +0 -13
  124. package/build/tools/convert.js +0 -599
  125. package/build/tools/css_order.d.ts +0 -13
  126. package/build/tools/css_order.js +0 -81
  127. package/build/tools/debug.d.ts +0 -13
  128. package/build/tools/debug.js +0 -131
  129. package/build/tools/design2code.d.ts +0 -20
  130. package/build/tools/design2code.js +0 -426
  131. package/build/tools/detect_shell.d.ts +0 -6
  132. package/build/tools/detect_shell.js +0 -151
  133. package/build/tools/explain.d.ts +0 -13
  134. package/build/tools/explain.js +0 -390
  135. package/build/tools/fix.d.ts +0 -13
  136. package/build/tools/fix.js +0 -303
  137. package/build/tools/gen_mock.d.ts +0 -22
  138. package/build/tools/gen_mock.js +0 -269
  139. package/build/tools/gen_skill.d.ts +0 -13
  140. package/build/tools/gen_skill.js +0 -560
  141. package/build/tools/genapi.d.ts +0 -13
  142. package/build/tools/genapi.js +0 -174
  143. package/build/tools/genchangelog.d.ts +0 -13
  144. package/build/tools/genchangelog.js +0 -250
  145. package/build/tools/gendoc.d.ts +0 -13
  146. package/build/tools/gendoc.js +0 -232
  147. package/build/tools/genpr.d.ts +0 -13
  148. package/build/tools/genpr.js +0 -194
  149. package/build/tools/genreadme.d.ts +0 -13
  150. package/build/tools/genreadme.js +0 -626
  151. package/build/tools/gensql.d.ts +0 -13
  152. package/build/tools/gensql.js +0 -320
  153. package/build/tools/genui.d.ts +0 -13
  154. package/build/tools/genui.js +0 -803
  155. package/build/tools/init_component_catalog.d.ts +0 -22
  156. package/build/tools/init_component_catalog.js +0 -809
  157. package/build/tools/init_setting.d.ts +0 -13
  158. package/build/tools/init_setting.js +0 -47
  159. package/build/tools/perf.d.ts +0 -13
  160. package/build/tools/perf.js +0 -409
  161. package/build/tools/render_ui.d.ts +0 -22
  162. package/build/tools/render_ui.js +0 -384
  163. package/build/tools/resolve_conflict.d.ts +0 -13
  164. package/build/tools/resolve_conflict.js +0 -349
  165. package/build/tools/security_scan.d.ts +0 -22
  166. package/build/tools/security_scan.js +0 -323
  167. package/build/tools/split.d.ts +0 -13
  168. package/build/tools/split.js +0 -599
  169. package/build/tools/start_api.d.ts +0 -13
  170. package/build/tools/start_api.js +0 -193
  171. package/build/tools/start_doc.d.ts +0 -13
  172. package/build/tools/start_doc.js +0 -207
  173. package/build/tools/start_refactor.d.ts +0 -13
  174. package/build/tools/start_refactor.js +0 -188
  175. package/build/tools/start_release.d.ts +0 -13
  176. package/build/tools/start_release.js +0 -167
  177. package/build/tools/start_review.d.ts +0 -13
  178. package/build/tools/start_review.js +0 -175
  179. /package/build/{utils/design-docs-generator.d.ts → lib/__tests__/dev-workflow.unit.test.d.ts} +0 -0
  180. /package/build/{utils/design-docs-generator.js → lib/__tests__/handles.unit.test.d.ts} +0 -0
package/README.md CHANGED
@@ -15,7 +15,7 @@
15
15
 
16
16
  > **Talk is cheap, show me the Context.**
17
17
  >
18
- > mcp-probe-kit is a protocol-level toolkit designed for developers who want AI to truly understand their project's intent. It's not just a collection of 27 tools—it's a context-aware system that helps AI agents grasp what you're building.
18
+ > mcp-probe-kit is a protocol-level toolkit designed for developers who want AI to truly understand their project's intent. It's not just a collection of 30 tools—it's a context-aware system that helps AI agents grasp what you're building.
19
19
 
20
20
  **Languages**: [English](README.md) | [简体中文](i18n/README.zh-CN.md) | [日本語](i18n/README.ja-JP.md) | [한국어](i18n/README.ko-KR.md) | [Español](i18n/README.es-ES.md) | [Français](i18n/README.fr-FR.md) | [Deutsch](i18n/README.de-DE.md) | [Português (BR)](i18n/README.pt-BR.md)
21
21
 
@@ -26,7 +26,7 @@
26
26
 
27
27
  > 🚀 AI-Powered Complete Development Toolkit - Covering the Entire Development Lifecycle
28
28
 
29
- A powerful MCP (Model Context Protocol) server providing **27 tools** covering the complete workflow from product analysis to final release (Requirements → Design → Development → Quality → Release), all tools support **structured output**.
29
+ A powerful MCP (Model Context Protocol) server providing **30 tools** covering the complete workflow from product analysis to final release (Requirements → Design → Development → Quality → Release), all tools support **structured output**.
30
30
 
31
31
  **🎉 v3.0 Major Update**: Streamlined tool count, focus on core competencies, eliminate choice paralysis, let AI do more native work
32
32
 
@@ -42,7 +42,7 @@ A powerful MCP (Model Context Protocol) server providing **27 tools** covering t
42
42
 
43
43
  - [Quick Start](https://mcp-probe-kit.bytezonex.com/pages/getting-started.html) - Setup in 5 minutes
44
44
  - [Local Memory Stack (Qdrant + Nomic Embed)](docs/memory-local-setup.md) - Docker Compose, ports `50008` / `50012`, MCP env
45
- - [All Tools](https://mcp-probe-kit.bytezonex.com/pages/all-tools.html) - Complete list of 27 tools
45
+ - [All Tools](https://mcp-probe-kit.bytezonex.com/pages/all-tools.html) - Complete list of 29 tools
46
46
  - [Best Practices](https://mcp-probe-kit.bytezonex.com/pages/examples.html) - Full development workflow guide
47
47
  - [v3.0 Migration Guide](https://mcp-probe-kit.bytezonex.com/pages/migration.html) - Upgrade from v2.x to v3.0
48
48
 
@@ -50,7 +50,7 @@ A powerful MCP (Model Context Protocol) server providing **27 tools** covering t
50
50
 
51
51
  ## ✨ Core Features
52
52
 
53
- ### 📦 27 Tools
53
+ ### 📦 29 Tools
54
54
 
55
55
  - **🔄 Workflow Orchestration** (6 tools) - One-click complex development workflows
56
56
  - `start_feature`, `start_bugfix`, `start_onboard`, `start_ui`, `start_product`, `start_ralph`
@@ -64,8 +64,18 @@ A powerful MCP (Model Context Protocol) server providing **27 tools** covering t
64
64
  - `init_project`, `init_project_context`, `add_feature`, `check_spec`, `estimate`, `interview`, `ask_user`
65
65
  - **🎨 UI/UX Utilities** (3 tools) - Design systems and UI data synchronization
66
66
  - `ui_design_system`, `ui_search`, `sync_ui_data`
67
- - **🧠 Memory** (4 tools) - Reusable asset memory
68
- - `search_memory`, `read_memory_asset`, `memorize_asset`, `scan_and_extract_patterns`
67
+ - **🧠 Memory** (6 tools) - Reusable asset memory
68
+ - `search_memory`, `read_memory_asset`, `memorize_asset`, `update_memory_asset`, `delete_memory_asset`, `scan_and_extract_patterns`
69
+
70
+ ### 🛡️ Quality Constraints (single source of truth)
71
+
72
+ All hard quality rules live in one module (`src/lib/quality-constraints.ts`) and are injected into `code_review`, the `add_feature` task templates, and the UI tools. Change once, apply everywhere — inspired by [taste-skill](https://github.com/Leonxlnx/taste-skill) and [impeccable](https://github.com/pbakaus/impeccable).
73
+
74
+ - **Code limits**: single file ≤ 500 lines (split into modules/components when exceeded), function ≤ 50 lines, nesting ≤ 4, parameters ≤ 3.
75
+ - **Completeness blacklist**: `code_review` flags placeholder/elision patterns (`// ...`, `// TODO`, `// rest of code`, bare `...`) as CRITICAL — "a partial output is a broken output".
76
+ - **Anti-laziness task templates**: `add_feature` tasks now carry a Scope-lock deliverable count, a mandatory evidence block (read code before writing), a per-file line budget, and a binary zero-tolerance rule for placeholders. `check_spec` validates these (missing Scope-lock = error, thin task without evidence = warning).
77
+ - **UI hard red lines**: numeric, machine-checkable rules — 4pt spacing scale, WCAG contrast (4.5/3/3), type scale ≥ 1.25, hero font ≤ 6rem, OKLCH, eight interaction states, cognitive load ≤ 4, motion 150-300ms.
78
+ - **UI banned list + Pre-Flight checklist**: match-and-refuse blacklist for AI slop (default Inter/Roboto, AI purple-blue gradients, gradient text, cookie-cutter card grids, em-dash, cream/beige body backgrounds, nested cards) plus a delivery-gate self-check matrix.
69
79
 
70
80
  ### 🧠 Code Graph Bridge (GitNexus)
71
81
 
@@ -98,6 +108,8 @@ A powerful MCP (Model Context Protocol) server providing **27 tools** covering t
98
108
  - `search_memory` - Semantic search across the shared memory pool (optionally prefer `type` / `tags`); text output includes `id`, `score`, summary, description, and a `--- content ---` body (default up to 1500 chars via `MEMORY_SEARCH_CONTENT_MAX_CHARS`)
99
109
  - `memorize_asset` - Persist reusable code/spec/pattern assets into vector memory
100
110
  - `read_memory_asset` - Read full asset content by `asset_id` (text output includes the full `content` body)
111
+ - `update_memory_asset` - Update an existing asset by `asset_id` (preserves ID; `content` changes re-embed)
112
+ - `delete_memory_asset` - Delete an asset by `asset_id` from the shared pool
101
113
  - `scan_and_extract_patterns` - Extract reusable patterns from code/file/directory before deciding whether to persist
102
114
 
103
115
  **Cross-repo memory pools:** do not rely on `source_project` / `source_path` for shared retrieval; put file paths in `content` instead. Search injection hides foreign `sourcePath` unless `MEMORY_REPO_ID` matches or `MEMORY_SEARCH_SHOW_SOURCE=true`.
@@ -468,7 +480,13 @@ Use in config file:
468
480
 
469
481
  ### Optional Memory System Setup
470
482
 
471
- If you want to use `memorize_asset`, `read_memory_asset`, and `scan_and_extract_patterns`, you need both:
483
+ If you want to use `memorize_asset`, `update_memory_asset`, `read_memory_asset`, `delete_memory_asset`, and `scan_and_extract_patterns`, configure as follows:
484
+
485
+ - **Qdrant only** (`MEMORY_QDRANT_URL`): `read_memory_asset`, `delete_memory_asset`
486
+ - **Qdrant + embedding** (all three `MEMORY_*` write/search vars): `search_memory`, `memorize_asset`, `update_memory_asset`
487
+ - **No memory backend**: `scan_and_extract_patterns` (local scan only; persist via `memorize_asset` when ready)
488
+
489
+ For full write/search you need both:
472
490
 
473
491
  1. A **Qdrant** vector database
474
492
  2. An **embedding service** in either `ollama` or `openai-compatible` mode
package/build/index.js CHANGED
@@ -5,11 +5,16 @@ import { InMemoryTaskMessageQueue, InMemoryTaskStore, } from "@modelcontextproto
5
5
  import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ProgressNotificationSchema, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
6
6
  import * as fs from "node:fs";
7
7
  import * as path from "node:path";
8
- import { initProject, gencommit, codeReview, codeInsight, gentest, refactor, initProjectContext, addFeature, fixBug, estimate, checkSpec, startFeature, startBugfix, startOnboard, startRalph, interview, askUser, uiDesignSystem, uiSearch, syncUiData, startUi, startProduct, gitWorkReport, searchMemory, readMemoryAsset, memorizeAsset, scanAndExtractPatterns } from "./tools/index.js";
8
+ import { initProject, gencommit, codeReview, codeInsight, gentest, refactor, initProjectContext, addFeature, fixBug, estimate, checkSpec, workflow, startFeature, startBugfix, startOnboard, startRalph, interview, askUser, uiDesignSystem, uiSearch, syncUiData, startUi, startProduct, gitWorkReport, searchMemory, readMemoryAsset, memorizeAsset, deleteMemoryAsset, updateMemoryAsset, scanAndExtractPatterns } from "./tools/index.js";
9
9
  import { VERSION, NAME } from "./version.js";
10
10
  import { allToolSchemas } from "./schemas/index.js";
11
11
  import { filterTools, getToolsetFromEnv } from "./lib/toolset-manager.js";
12
12
  import { withToolAnnotations } from "./lib/tool-annotations.js";
13
+ import { withOutputSchema } from "./lib/output-schema-registry.js";
14
+ import { shouldAutoEscalateToTask } from "./lib/task-defaults.js";
15
+ import { attachHandles } from "./lib/handles.js";
16
+ import { buildMcpAppHtml, isMcpUiAppTool } from "./lib/mcp-apps.js";
17
+ import { ensureMcpProbeKitBootstrapForToolCall } from "./lib/workflow-skill-installer.js";
13
18
  import { isAbortError, } from "./lib/tool-execution-context.js";
14
19
  const EXTENSIONS_CAPABILITY_KEY = "io.github.mybolide/extensions";
15
20
  const MAX_UI_APP_RESOURCES = 30;
@@ -82,80 +87,6 @@ function withTraceMeta(result, traceMeta) {
82
87
  },
83
88
  };
84
89
  }
85
- function escapeHtml(value) {
86
- return value
87
- .replace(/&/g, "&")
88
- .replace(/</g, "&lt;")
89
- .replace(/>/g, "&gt;")
90
- .replace(/"/g, "&quot;")
91
- .replace(/'/g, "&#39;");
92
- }
93
- function isUiTool(name) {
94
- return [
95
- "ui_design_system",
96
- "ui_search",
97
- "sync_ui_data",
98
- "start_ui",
99
- "start_product",
100
- ].includes(name);
101
- }
102
- function buildUiResourceHtml(name, args, result) {
103
- const structured = result.structuredContent
104
- ? JSON.stringify(result.structuredContent, null, 2)
105
- : "{}";
106
- const argJson = JSON.stringify(args ?? {}, null, 2);
107
- const textBlocks = Array.isArray(result.content)
108
- ? result.content
109
- .map((item) => {
110
- if (!item || typeof item !== "object") {
111
- return "";
112
- }
113
- const text = item.text;
114
- return typeof text === "string" ? text : "";
115
- })
116
- .filter(Boolean)
117
- .join("\n\n")
118
- : "";
119
- const now = new Date().toISOString();
120
- return `<!doctype html>
121
- <html lang="zh-CN">
122
- <head>
123
- <meta charset="utf-8">
124
- <meta name="viewport" content="width=device-width, initial-scale=1">
125
- <title>${escapeHtml(name)} · MCP Apps</title>
126
- <style>
127
- :root { color-scheme: light; }
128
- body { font-family: "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif; margin: 0; background: #f4f7fb; color: #1e2a35; }
129
- .wrap { max-width: 960px; margin: 0 auto; padding: 24px; }
130
- .card { background: #fff; border-radius: 14px; padding: 18px; box-shadow: 0 4px 18px rgba(30,42,53,.08); margin-bottom: 16px; }
131
- h1 { margin: 0 0 8px; font-size: 24px; }
132
- h2 { margin: 0 0 10px; font-size: 16px; color: #2f4a65; }
133
- 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; }
134
- .meta { color: #4f6880; font-size: 12px; }
135
- </style>
136
- </head>
137
- <body>
138
- <div class="wrap">
139
- <div class="card">
140
- <h1>${escapeHtml(name)}</h1>
141
- <div class="meta">Generated at ${escapeHtml(now)} · MCP Apps preview</div>
142
- </div>
143
- <div class="card">
144
- <h2>Text Output</h2>
145
- <pre>${escapeHtml(textBlocks || "(no text output)")}</pre>
146
- </div>
147
- <div class="card">
148
- <h2>Structured Content</h2>
149
- <pre>${escapeHtml(structured)}</pre>
150
- </div>
151
- <div class="card">
152
- <h2>Arguments</h2>
153
- <pre>${escapeHtml(argJson)}</pre>
154
- </div>
155
- </div>
156
- </body>
157
- </html>`;
158
- }
159
90
  function putUiAppResource(toolName, args, result) {
160
91
  const uid = `${Date.now()}-${Math.random().toString(16).slice(2, 10)}`;
161
92
  const uri = `ui://mcp-probe-kit/${toolName}/${uid}`;
@@ -164,7 +95,7 @@ function putUiAppResource(toolName, args, result) {
164
95
  name: `UI Preview · ${toolName}`,
165
96
  description: `MCP Apps preview generated by ${toolName}`,
166
97
  mimeType: "text/html",
167
- text: buildUiResourceHtml(toolName, args, result),
98
+ text: buildMcpAppHtml(toolName, args, result),
168
99
  createdAt: new Date().toISOString(),
169
100
  };
170
101
  uiAppResources.set(uri, entry);
@@ -384,13 +315,26 @@ function rememberGraphSnapshot(toolName, result) {
384
315
  }
385
316
  return snapshot;
386
317
  }
318
+ function withStructuredHandles(result, handles) {
319
+ if (!result.structuredContent || typeof result.structuredContent !== "object" || Array.isArray(result.structuredContent)) {
320
+ return result;
321
+ }
322
+ return {
323
+ ...result,
324
+ structuredContent: attachHandles(result.structuredContent, handles),
325
+ };
326
+ }
387
327
  function decorateResult(toolName, args, raw, traceMeta) {
388
328
  let result = withTraceMeta(raw, traceMeta);
389
329
  const snapshot = rememberGraphSnapshot(toolName, result);
390
330
  if (snapshot) {
391
331
  result = withGraphSnapshotMeta(result, snapshot);
332
+ result = withStructuredHandles(result, {
333
+ graph_snapshot: snapshot.uri,
334
+ graph_resource: snapshot.uri,
335
+ });
392
336
  }
393
- if (uiAppsEnabled && isUiTool(toolName) && !result.isError) {
337
+ if (uiAppsEnabled && isMcpUiAppTool(toolName) && !result.isError) {
394
338
  const resourceUri = putUiAppResource(toolName, args, result);
395
339
  result = withUiResourceMeta(result, resourceUri);
396
340
  }
@@ -411,10 +355,23 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
411
355
  const filteredTools = filterTools(allToolSchemas, toolset);
412
356
  console.error(`[MCP Probe Kit] 当前工具集: ${toolset} (${filteredTools.length}/${allToolSchemas.length} 个工具)`);
413
357
  return {
414
- tools: filteredTools.map(withToolAnnotations),
358
+ tools: filteredTools.map((tool) => withOutputSchema(withToolAnnotations(tool))),
415
359
  };
416
360
  });
417
361
  async function executeTool(name, args, context) {
362
+ const bootstrap = ensureMcpProbeKitBootstrapForToolCall(name, args);
363
+ if (bootstrap?.skill.created) {
364
+ console.error(`[MCP Probe Kit] 已创建 MCP Skill: ${bootstrap.skill.skillRelPath} (v${bootstrap.skill.version})`);
365
+ }
366
+ else if (bootstrap?.skill.updated) {
367
+ console.error(`[MCP Probe Kit] 已升级 MCP Skill: ${bootstrap.skill.skillRelPath} ${bootstrap.skill.previousVersion ?? "?"} → v${bootstrap.skill.version}`);
368
+ }
369
+ if (bootstrap?.agentsMd.created) {
370
+ console.error(`[MCP Probe Kit] 已创建 AGENTS.md(含 Skill 引用): ${bootstrap.agentsMd.path}`);
371
+ }
372
+ else if (bootstrap?.agentsMd.updated) {
373
+ console.error(`[MCP Probe Kit] 已更新 AGENTS.md(添加 Skill 引用): ${bootstrap.agentsMd.path}`);
374
+ }
418
375
  switch (name) {
419
376
  case "init_project":
420
377
  return await initProject(args);
@@ -430,6 +387,8 @@ async function executeTool(name, args, context) {
430
387
  return await refactor(args);
431
388
  case "init_project_context":
432
389
  return await initProjectContext(args);
390
+ case "workflow":
391
+ return await workflow(args);
433
392
  case "add_feature":
434
393
  return await addFeature(args);
435
394
  case "check_spec":
@@ -468,6 +427,10 @@ async function executeTool(name, args, context) {
468
427
  return await readMemoryAsset(args);
469
428
  case "memorize_asset":
470
429
  return await memorizeAsset(args);
430
+ case "delete_memory_asset":
431
+ return await deleteMemoryAsset(args);
432
+ case "update_memory_asset":
433
+ return await updateMemoryAsset(args);
471
434
  case "scan_and_extract_patterns":
472
435
  return await scanAndExtractPatterns(args);
473
436
  default:
@@ -491,8 +454,11 @@ function isTerminalTaskStatus(status) {
491
454
  // 处理工具调用
492
455
  server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
493
456
  const { name, arguments: args } = request.params;
494
- const taskRequest = request.params.task;
457
+ let taskRequest = request.params.task;
495
458
  const traceMeta = getTraceMeta(extra._meta);
459
+ if (shouldAutoEscalateToTask(name, Boolean(taskRequest))) {
460
+ taskRequest = taskRequest ?? {};
461
+ }
496
462
  const emitProgress = async (progress, message) => {
497
463
  const progressToken = extra._meta?.progressToken;
498
464
  if (progressToken === undefined) {
@@ -20,6 +20,7 @@ describe('generateAgentsMdInner', () => {
20
20
  expect(md).toContain('记忆');
21
21
  expect(md).toContain('start_bugfix');
22
22
  expect(md).toContain('memorize_asset');
23
+ expect(md).toContain('mcp-probe-kit/SKILL.md');
23
24
  expect(md).toContain('bugfix');
24
25
  expect(md).toContain('search_memory');
25
26
  expect(md).toContain('自动注入');
@@ -0,0 +1,22 @@
1
+ import { describe, expect, test } from 'vitest';
2
+ import { buildDevWorkflow, detectWorkflowScenario } from '../dev-workflow.js';
3
+ describe('dev-workflow', () => {
4
+ test('识别 bugfix 场景', () => {
5
+ const result = detectWorkflowScenario('登录报错 NullReference 需要排查修复');
6
+ expect(result.scenario).toBe('bugfix');
7
+ });
8
+ test('识别 feature 场景', () => {
9
+ const result = detectWorkflowScenario('开发用户认证新功能');
10
+ expect(result.scenario).toBe('feature');
11
+ });
12
+ test('bugfix 计划首工具为 start_bugfix', () => {
13
+ const plan = buildDevWorkflow('TypeError in checkout');
14
+ expect(plan.firstTool).toBe('start_bugfix');
15
+ expect(plan.phases.some((p) => p.steps.some((s) => s.tool === 'start_bugfix'))).toBe(true);
16
+ });
17
+ test('显式 scenario 覆盖推断', () => {
18
+ const plan = buildDevWorkflow('随便', { scenario: 'ui' });
19
+ expect(plan.scenario).toBe('ui');
20
+ expect(plan.firstTool).toBe('start_ui');
21
+ });
22
+ });
@@ -0,0 +1,19 @@
1
+ import { describe, expect, test } from 'vitest';
2
+ import { attachHandles, buildMemoryAssetHandles, mergeHandles, } from '../../lib/handles.js';
3
+ describe('handles', () => {
4
+ test('buildMemoryAssetHandles 生成 read 默认工具名', () => {
5
+ const handles = buildMemoryAssetHandles([{ id: 'a-1', name: 'demo' }]);
6
+ expect(handles).toEqual([{ id: 'a-1', name: 'demo', tool: 'read_memory_asset' }]);
7
+ });
8
+ test('attachHandles 合并已有 handles', () => {
9
+ const result = attachHandles({ handles: { graph_resource: 'probe://graph/latest' } }, { memory_assets: buildMemoryAssetHandles([{ id: 'x' }]) });
10
+ expect(result.handles.graph_resource).toBe('probe://graph/latest');
11
+ expect(result.handles.memory_assets).toHaveLength(1);
12
+ });
13
+ test('mergeHandles 后者覆盖 graph 字段', () => {
14
+ expect(mergeHandles({ graph_resource: 'a' }, { graph_resource: 'b', graph_snapshot: 'probe://graph/s1' })).toEqual({
15
+ graph_resource: 'b',
16
+ graph_snapshot: 'probe://graph/s1',
17
+ });
18
+ });
19
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,52 @@
1
+ import { describe, expect, test } from 'vitest';
2
+ import { buildCodeInsightAppHtml, buildSearchMemoryAppHtml, isMcpUiAppTool, } from '../mcp-apps.js';
3
+ describe('mcp-apps', () => {
4
+ test('search_memory 与 code_insight 属于 UI App 工具', () => {
5
+ expect(isMcpUiAppTool('search_memory')).toBe(true);
6
+ expect(isMcpUiAppTool('code_insight')).toBe(true);
7
+ expect(isMcpUiAppTool('gencommit')).toBe(false);
8
+ });
9
+ test('search_memory App 渲染命中卡片与 handles', () => {
10
+ const html = buildSearchMemoryAppHtml({ query: 'proxy bug' }, {
11
+ structuredContent: {
12
+ query: 'proxy bug',
13
+ count: 1,
14
+ results: [
15
+ {
16
+ id: 'asset-1',
17
+ name: 'feishu-proxy',
18
+ type: 'bugfix',
19
+ score: 0.88,
20
+ summary: 'proxy mismatch',
21
+ content: '【修复】done',
22
+ tags: ['bugfix'],
23
+ },
24
+ ],
25
+ handles: {
26
+ memory_assets: [{ id: 'asset-1', tool: 'read_memory_asset' }],
27
+ },
28
+ },
29
+ });
30
+ expect(html).toContain('search_memory');
31
+ expect(html).toContain('feishu-proxy');
32
+ expect(html).toContain('asset-1');
33
+ expect(html).toContain('read_memory_asset');
34
+ expect(html).toContain('proxy mismatch');
35
+ });
36
+ test('code_insight App 渲染状态与执行表', () => {
37
+ const html = buildCodeInsightAppHtml({ mode: 'auto' }, {
38
+ structuredContent: {
39
+ status: 'ok',
40
+ provider: 'gitnexus',
41
+ summary: 'login flow analyzed',
42
+ mode: { requested: 'auto', resolved: 'query' },
43
+ executions: [{ tool: 'query', ok: true, text: 'found login handler' }],
44
+ handles: { graph_resource: 'probe://graph/latest' },
45
+ },
46
+ });
47
+ expect(html).toContain('code_insight');
48
+ expect(html).toContain('login flow analyzed');
49
+ expect(html).toContain('probe://graph/latest');
50
+ expect(html).toContain('found login handler');
51
+ });
52
+ });
@@ -0,0 +1,18 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { allToolSchemas } from "../../schemas/index.js";
3
+ import { formatSkillRegistryMismatchMessage, listMcpToolSkillRegistryNames, validateMcpToolSkillRegistry, } from "../mcp-tool-skill-registry.js";
4
+ import { generateWorkflowSkillContent } from "../workflow-skill-template.js";
5
+ describe("mcp-tool-skill-registry", () => {
6
+ it("与 allToolSchemas 工具名一一对应", () => {
7
+ const registered = allToolSchemas.map((tool) => tool.name).sort();
8
+ const result = validateMcpToolSkillRegistry(registered);
9
+ expect(result.ok, formatSkillRegistryMismatchMessage(result)).toBe(true);
10
+ expect(listMcpToolSkillRegistryNames().length).toBe(registered.length);
11
+ });
12
+ it("生成的 Skill 正文包含每个注册工具", () => {
13
+ const content = generateWorkflowSkillContent("0.0.0-test");
14
+ for (const name of listMcpToolSkillRegistryNames()) {
15
+ expect(content).toContain(`\`${name}\``);
16
+ }
17
+ });
18
+ });
@@ -80,4 +80,109 @@ describe('memory-client 去重逻辑', () => {
80
80
  expect(result.normalizedContentHash).toBe(existingAsset.normalizedContentHash);
81
81
  expect(fetchMock.mock.calls.some(([url]) => String(url).includes('/points?wait=true'))).toBe(false);
82
82
  });
83
+ test('deleteAsset 删除已存在资产并返回快照', async () => {
84
+ vi.stubEnv('MEMORY_QDRANT_URL', 'http://127.0.0.1:50008');
85
+ const asset = {
86
+ id: 'asset-to-delete',
87
+ name: 'ObsoletePattern',
88
+ type: 'pattern',
89
+ description: '过时模式',
90
+ summary: '不再使用',
91
+ content: 'old snippet',
92
+ tags: ['pattern'],
93
+ confidence: 0.7,
94
+ createdAt: '2026-01-01T00:00:00.000Z',
95
+ updatedAt: '2026-01-01T00:00:00.000Z',
96
+ };
97
+ const fetchMock = vi.fn(async (input, init) => {
98
+ const url = String(input);
99
+ if (url.includes(`/points/${asset.id}`) && init?.method !== 'POST' && init?.method !== 'PUT') {
100
+ return new Response(JSON.stringify({ result: { payload: asset } }), {
101
+ status: 200,
102
+ headers: { 'Content-Type': 'application/json' },
103
+ });
104
+ }
105
+ if (url.includes('/points/delete')) {
106
+ return new Response(JSON.stringify({ status: 'ok' }), {
107
+ status: 200,
108
+ headers: { 'Content-Type': 'application/json' },
109
+ });
110
+ }
111
+ throw new Error(`unexpected fetch: ${url}`);
112
+ });
113
+ globalThis.fetch = fetchMock;
114
+ const client = new MemoryClient();
115
+ const result = await client.deleteAsset(asset.id);
116
+ expect(result.deleted).toBe(true);
117
+ expect(result.asset?.name).toBe('ObsoletePattern');
118
+ expect(fetchMock.mock.calls.some(([url, init]) => String(url).includes('/points/delete') && init?.method === 'POST')).toBe(true);
119
+ });
120
+ test('deleteAsset 对不存在的资产返回 deleted=false', async () => {
121
+ vi.stubEnv('MEMORY_QDRANT_URL', 'http://127.0.0.1:50008');
122
+ const fetchMock = vi.fn(async (input) => {
123
+ const url = String(input);
124
+ if (url.includes('/points/missing-id')) {
125
+ return new Response(JSON.stringify({ result: null }), {
126
+ status: 200,
127
+ headers: { 'Content-Type': 'application/json' },
128
+ });
129
+ }
130
+ throw new Error(`unexpected fetch: ${url}`);
131
+ });
132
+ globalThis.fetch = fetchMock;
133
+ const client = new MemoryClient();
134
+ const result = await client.deleteAsset('missing-id');
135
+ expect(result.deleted).toBe(false);
136
+ expect(result.asset).toBeNull();
137
+ });
138
+ test('updateAsset 更新已存在资产并保留 createdAt', async () => {
139
+ vi.stubEnv('MEMORY_QDRANT_URL', 'http://127.0.0.1:50008');
140
+ vi.stubEnv('MEMORY_EMBEDDING_URL', 'http://127.0.0.1:11434/api/embeddings');
141
+ vi.stubEnv('MEMORY_EMBEDDING_MODEL', 'nomic-embed-text');
142
+ const asset = {
143
+ id: 'asset-to-update',
144
+ name: 'PatternA',
145
+ type: 'pattern',
146
+ description: '旧描述',
147
+ summary: '旧摘要',
148
+ content: 'old snippet',
149
+ tags: ['pattern'],
150
+ confidence: 0.7,
151
+ createdAt: '2026-01-01T00:00:00.000Z',
152
+ updatedAt: '2026-01-01T00:00:00.000Z',
153
+ };
154
+ const fetchMock = vi.fn(async (input, init) => {
155
+ const url = String(input);
156
+ if (url.endsWith('/api/embeddings')) {
157
+ return new Response(JSON.stringify({ embedding: [0.1, 0.2, 0.3] }), {
158
+ status: 200,
159
+ headers: { 'Content-Type': 'application/json' },
160
+ });
161
+ }
162
+ if (url.includes(`/points/${asset.id}`) && init?.method !== 'POST' && init?.method !== 'PUT') {
163
+ return new Response(JSON.stringify({ result: { payload: asset } }), {
164
+ status: 200,
165
+ headers: { 'Content-Type': 'application/json' },
166
+ });
167
+ }
168
+ if (url.endsWith('/collections/mcp_probe_memory') && !init?.method) {
169
+ return new Response('', { status: 200 });
170
+ }
171
+ if (url.includes('/points?wait=true') && init?.method === 'PUT') {
172
+ return new Response(JSON.stringify({ status: 'ok' }), {
173
+ status: 200,
174
+ headers: { 'Content-Type': 'application/json' },
175
+ });
176
+ }
177
+ throw new Error(`unexpected fetch: ${url}`);
178
+ });
179
+ globalThis.fetch = fetchMock;
180
+ const client = new MemoryClient();
181
+ const result = await client.updateAsset(asset.id, { summary: '新摘要' });
182
+ expect(result.updated).toBe(true);
183
+ expect(result.asset?.summary).toBe('新摘要');
184
+ expect(result.asset?.createdAt).toBe(asset.createdAt);
185
+ expect(result.asset?.id).toBe(asset.id);
186
+ expect(fetchMock.mock.calls.some(([url, init]) => String(url).includes('/points?wait=true') && init?.method === 'PUT')).toBe(true);
187
+ });
83
188
  });
@@ -0,0 +1,88 @@
1
+ import { afterEach, describe, expect, test, vi } from 'vitest';
2
+ import { renderMemoryGuideSection, shouldShowSourceInSearch, } from '../memory-orchestration.js';
3
+ afterEach(() => {
4
+ vi.unstubAllEnvs();
5
+ });
6
+ describe('memory-orchestration', () => {
7
+ test('does not show source path by default', () => {
8
+ vi.stubEnv('MEMORY_SEARCH_SHOW_SOURCE', '');
9
+ vi.stubEnv('MEMORY_REPO_ID', '');
10
+ const section = renderMemoryGuideSection({
11
+ enabled: true,
12
+ available: true,
13
+ degraded: false,
14
+ query: '404 submit',
15
+ results: [
16
+ {
17
+ id: '1',
18
+ score: 0.91,
19
+ name: 'purchase-create-submit-404',
20
+ type: 'bugfix',
21
+ description: 'desc',
22
+ summary: 'summary',
23
+ content: '',
24
+ tags: ['bugfix'],
25
+ sourceProject: 'zhixing/gongyingshang',
26
+ sourcePath: 'admin-api/app.js',
27
+ },
28
+ ],
29
+ assetsById: {},
30
+ });
31
+ expect(section).toContain('purchase-create-submit-404');
32
+ expect(section).not.toContain('admin-api/app.js');
33
+ expect(section).not.toContain('来源:');
34
+ });
35
+ test('shows source path when MEMORY_REPO_ID matches', () => {
36
+ vi.stubEnv('MEMORY_SEARCH_SHOW_SOURCE', '');
37
+ vi.stubEnv('MEMORY_REPO_ID', 'zhixing/gongyingshang');
38
+ expect(shouldShowSourceInSearch({
39
+ id: '1',
40
+ score: 0.9,
41
+ name: 'x',
42
+ type: 'bugfix',
43
+ description: '',
44
+ summary: '',
45
+ content: '',
46
+ tags: [],
47
+ sourceProject: 'zhixing/gongyingshang',
48
+ sourcePath: 'admin-api/app.js',
49
+ })).toBe(true);
50
+ expect(shouldShowSourceInSearch({
51
+ id: '2',
52
+ score: 0.9,
53
+ name: 'y',
54
+ type: 'bugfix',
55
+ description: '',
56
+ summary: '',
57
+ content: '',
58
+ tags: [],
59
+ sourceProject: 'other/repo',
60
+ sourcePath: 'src/index.ts',
61
+ })).toBe(false);
62
+ });
63
+ test('MEMORY_SEARCH_SHOW_SOURCE=true always shows source', () => {
64
+ vi.stubEnv('MEMORY_SEARCH_SHOW_SOURCE', 'true');
65
+ vi.stubEnv('MEMORY_REPO_ID', '');
66
+ const section = renderMemoryGuideSection({
67
+ enabled: true,
68
+ available: true,
69
+ degraded: false,
70
+ query: 'q',
71
+ results: [
72
+ {
73
+ id: '1',
74
+ score: 0.8,
75
+ name: 'n',
76
+ type: 'bugfix',
77
+ description: '',
78
+ summary: 's',
79
+ content: '',
80
+ tags: [],
81
+ sourcePath: 'admin-api/app.js',
82
+ },
83
+ ],
84
+ assetsById: {},
85
+ });
86
+ expect(section).toContain('来源: admin-api/app.js');
87
+ });
88
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,35 @@
1
+ import { describe, expect, test } from 'vitest';
2
+ import { normalizeMemoryPayload, payloadToMemoryFields } from '../memory-payload.js';
3
+ describe('memory-payload', () => {
4
+ test('maps legacy kind/title/source fields to current schema', () => {
5
+ const normalized = normalizeMemoryPayload({
6
+ kind: 'extracted_pattern',
7
+ title: 'Feishu submit success but sync_failed',
8
+ source: 'scan_and_extract_patterns-fallback',
9
+ content: 'Pattern: proxy mismatch',
10
+ tags: ['feishu', 'pattern'],
11
+ created_at: '2026-05-25T11:20:06.705Z',
12
+ });
13
+ expect(normalized.name).toBe('Feishu submit success but sync_failed');
14
+ expect(normalized.type).toBe('pattern');
15
+ expect(normalized.summary).toContain('Pattern');
16
+ expect(normalized.createdAt).toBe('2026-05-25T11:20:06.705Z');
17
+ });
18
+ test('payloadToMemoryFields preserves standard asset fields', () => {
19
+ const fields = payloadToMemoryFields({
20
+ id: 'asset-1',
21
+ name: 'purchase-create-submit-404',
22
+ type: 'bugfix',
23
+ description: '送审 404',
24
+ summary: 'res.data.purchase.id',
25
+ content: '【现象】404',
26
+ tags: ['bugfix'],
27
+ confidence: 0.95,
28
+ createdAt: '2026-05-27T04:28:04.684Z',
29
+ updatedAt: '2026-05-27T04:28:04.684Z',
30
+ });
31
+ expect(fields.name).toBe('purchase-create-submit-404');
32
+ expect(fields.type).toBe('bugfix');
33
+ expect(fields.tags).toEqual(['bugfix']);
34
+ });
35
+ });