@synth-coder/memhub 0.2.2 → 0.2.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.
Files changed (116) hide show
  1. package/.factory/commands/opsx-apply.md +150 -0
  2. package/.factory/commands/opsx-archive.md +155 -0
  3. package/.factory/commands/opsx-explore.md +171 -0
  4. package/.factory/commands/opsx-propose.md +104 -0
  5. package/.factory/skills/openspec-apply-change/SKILL.md +156 -0
  6. package/.factory/skills/openspec-archive-change/SKILL.md +114 -0
  7. package/.factory/skills/openspec-explore/SKILL.md +288 -0
  8. package/.factory/skills/openspec-propose/SKILL.md +110 -0
  9. package/.github/workflows/ci.yml +48 -12
  10. package/.github/workflows/release.yml +67 -0
  11. package/AGENTS.md +158 -17
  12. package/README.md +147 -66
  13. package/README.zh-CN.md +75 -23
  14. package/dist/src/cli/agents/claude-code.d.ts +5 -0
  15. package/dist/src/cli/agents/claude-code.d.ts.map +1 -0
  16. package/dist/src/cli/agents/claude-code.js +14 -0
  17. package/dist/src/cli/agents/claude-code.js.map +1 -0
  18. package/dist/src/cli/agents/cline.d.ts +5 -0
  19. package/dist/src/cli/agents/cline.d.ts.map +1 -0
  20. package/dist/src/cli/agents/cline.js +14 -0
  21. package/dist/src/cli/agents/cline.js.map +1 -0
  22. package/dist/src/cli/agents/codex.d.ts +5 -0
  23. package/dist/src/cli/agents/codex.d.ts.map +1 -0
  24. package/dist/src/cli/agents/codex.js +14 -0
  25. package/dist/src/cli/agents/codex.js.map +1 -0
  26. package/dist/src/cli/agents/cursor.d.ts +5 -0
  27. package/dist/src/cli/agents/cursor.d.ts.map +1 -0
  28. package/dist/src/cli/agents/cursor.js +14 -0
  29. package/dist/src/cli/agents/cursor.js.map +1 -0
  30. package/dist/src/cli/agents/factory-droid.d.ts +5 -0
  31. package/dist/src/cli/agents/factory-droid.d.ts.map +1 -0
  32. package/dist/src/cli/agents/factory-droid.js +14 -0
  33. package/dist/src/cli/agents/factory-droid.js.map +1 -0
  34. package/dist/src/cli/agents/gemini-cli.d.ts +5 -0
  35. package/dist/src/cli/agents/gemini-cli.d.ts.map +1 -0
  36. package/dist/src/cli/agents/gemini-cli.js +14 -0
  37. package/dist/src/cli/agents/gemini-cli.js.map +1 -0
  38. package/dist/src/cli/agents/index.d.ts +14 -0
  39. package/dist/src/cli/agents/index.d.ts.map +1 -0
  40. package/dist/src/cli/agents/index.js +30 -0
  41. package/dist/src/cli/agents/index.js.map +1 -0
  42. package/dist/src/cli/agents/windsurf.d.ts +5 -0
  43. package/dist/src/cli/agents/windsurf.d.ts.map +1 -0
  44. package/dist/src/cli/agents/windsurf.js +14 -0
  45. package/dist/src/cli/agents/windsurf.js.map +1 -0
  46. package/dist/src/cli/index.d.ts +8 -0
  47. package/dist/src/cli/index.d.ts.map +1 -0
  48. package/dist/src/cli/index.js +168 -0
  49. package/dist/src/cli/index.js.map +1 -0
  50. package/dist/src/cli/init.d.ts +34 -0
  51. package/dist/src/cli/init.d.ts.map +1 -0
  52. package/dist/src/cli/init.js +160 -0
  53. package/dist/src/cli/init.js.map +1 -0
  54. package/dist/src/cli/instructions.d.ts +29 -0
  55. package/dist/src/cli/instructions.d.ts.map +1 -0
  56. package/dist/src/cli/instructions.js +141 -0
  57. package/dist/src/cli/instructions.js.map +1 -0
  58. package/dist/src/cli/types.d.ts +22 -0
  59. package/dist/src/cli/types.d.ts.map +1 -0
  60. package/dist/src/cli/types.js +86 -0
  61. package/dist/src/cli/types.js.map +1 -0
  62. package/dist/src/contracts/schemas.js.map +1 -1
  63. package/dist/src/server/mcp-server.d.ts +8 -0
  64. package/dist/src/server/mcp-server.d.ts.map +1 -1
  65. package/dist/src/server/mcp-server.js +30 -16
  66. package/dist/src/server/mcp-server.js.map +1 -1
  67. package/dist/src/services/embedding-service.d.ts.map +1 -1
  68. package/dist/src/services/embedding-service.js +1 -1
  69. package/dist/src/services/embedding-service.js.map +1 -1
  70. package/dist/src/services/memory-service.d.ts +1 -0
  71. package/dist/src/services/memory-service.d.ts.map +1 -1
  72. package/dist/src/services/memory-service.js +125 -82
  73. package/dist/src/services/memory-service.js.map +1 -1
  74. package/dist/src/storage/markdown-storage.d.ts.map +1 -1
  75. package/dist/src/storage/markdown-storage.js +1 -1
  76. package/dist/src/storage/markdown-storage.js.map +1 -1
  77. package/dist/src/storage/vector-index.d.ts.map +1 -1
  78. package/dist/src/storage/vector-index.js +4 -5
  79. package/dist/src/storage/vector-index.js.map +1 -1
  80. package/docs/README.md +21 -0
  81. package/docs/mcp-tools.md +136 -0
  82. package/docs/user-guide.md +182 -0
  83. package/package.json +22 -19
  84. package/src/cli/agents/claude-code.ts +14 -0
  85. package/src/cli/agents/cline.ts +14 -0
  86. package/src/cli/agents/codex.ts +14 -0
  87. package/src/cli/agents/cursor.ts +14 -0
  88. package/src/cli/agents/factory-droid.ts +14 -0
  89. package/src/cli/agents/gemini-cli.ts +14 -0
  90. package/src/cli/agents/index.ts +36 -0
  91. package/src/cli/agents/windsurf.ts +14 -0
  92. package/src/cli/index.ts +192 -0
  93. package/src/cli/init.ts +218 -0
  94. package/src/cli/instructions.ts +156 -0
  95. package/src/cli/types.ts +112 -0
  96. package/src/contracts/mcp.ts +1 -1
  97. package/src/contracts/schemas.ts +4 -4
  98. package/src/contracts/types.ts +4 -4
  99. package/src/server/mcp-server.ts +36 -29
  100. package/src/services/embedding-service.ts +80 -80
  101. package/src/services/memory-service.ts +142 -107
  102. package/src/storage/markdown-storage.ts +1 -9
  103. package/src/storage/vector-index.ts +117 -118
  104. package/test/cli/init.test.ts +380 -0
  105. package/test/server/mcp-server.test.ts +45 -3
  106. package/test/services/memory-service.test.ts +16 -4
  107. package/test/storage/frontmatter-parser.test.ts +1 -1
  108. package/test/storage/markdown-storage.test.ts +19 -10
  109. package/test/storage/vector-index.test.ts +129 -133
  110. package/test/utils/slugify.test.ts +5 -1
  111. package/docs/architecture.md +0 -349
  112. package/docs/contracts.md +0 -119
  113. package/docs/prompt-template.md +0 -79
  114. package/docs/proposals/mcp-typescript-sdk-refactor.md +0 -568
  115. package/docs/proposals/proposal-close-gates.md +0 -58
  116. package/docs/tool-calling-policy.md +0 -107
@@ -1,568 +0,0 @@
1
- # 提案:使用 @modelcontextprotocol/sdk 重构 MCP 实现
2
-
3
- > 状态:草案
4
- > 创建日期:2026-03-03
5
- > 作者:iFlow CLI
6
-
7
- ## 1. 执行摘要
8
-
9
- 本提案旨在使用官方 `@modelcontextprotocol/sdk` 重构 memhub 的 MCP 服务器实现,以消除重复造轮子,降低维护成本,并获得官方 SDK 提供的协议兼容性、错误处理和生命周期管理等功能。
10
-
11
- ## 2. 当前问题与重复实现清单
12
-
13
- ### 2.1 当前架构分析
14
-
15
- memhub 目前自行实现了完整的 MCP 协议栈,包括:
16
-
17
- | 组件 | 当前实现 | SDK 提供 | 重复程度 |
18
- |------|----------|----------|----------|
19
- | JSON-RPC 协议处理 | `src/server/mcp-server.ts` 中手动解析/序列化 | ✅ 内置 | 完全重复 |
20
- | 请求/响应类型定义 | `src/contracts/mcp.ts` 中自定义 | ✅ 内置 | 完全重复 |
21
- | 错误码定义 | `ERROR_CODES` 常量 | ✅ 内置 | 完全重复 |
22
- | 生命周期管理 | 手动处理 `initialize`/`shutdown`/`exit` | ✅ 内置 | 完全重复 |
23
- | 工具注册与分发 | 手动实现 `TOOLS_LIST`/`TOOLS_CALL` | ✅ `server.registerTool()` | 完全重复 |
24
- | stdio 传输层 | 手动读写 `process.stdin`/`stdout` | ✅ `StdioServerTransport` | 完全重复 |
25
- | 消息缓冲处理 | 手动按行分割处理 | ✅ 内置 | 完全重复 |
26
- | 通知处理 | 手动处理 `notifications/initialized` | ✅ 内置 | 完全重复 |
27
-
28
- ### 2.2 重复实现代码清单
29
-
30
- #### 2.2.1 JSON-RPC 协议层(约 150 行)
31
-
32
- **文件**: `src/server/mcp-server.ts:85-180`
33
-
34
- ```typescript
35
- // 当前自行实现的 JSON-RPC 处理
36
- private async handleMessage(message: string): Promise<void> {
37
- let request: JsonRpcRequest | null = null;
38
- try {
39
- request = JSON.parse(message) as JsonRpcRequest;
40
- } catch {
41
- this.sendError(null, ERROR_CODES.PARSE_ERROR, 'Parse error: Invalid JSON');
42
- return;
43
- }
44
- // 验证、路由、响应... 全部手动实现
45
- }
46
- ```
47
-
48
- **SDK 替代方案**:
49
- ```typescript
50
- // SDK 自动处理
51
- const transport = new StdioServerTransport();
52
- await server.connect(transport); // 自动处理所有 JSON-RPC 协议细节
53
- ```
54
-
55
- #### 2.2.2 类型定义(约 200 行)
56
-
57
- **文件**: `src/contracts/mcp.ts`
58
-
59
- 当前自定义的类型:
60
- - `JsonRpcRequest` / `JsonRpcResponse` / `JsonRpcError`
61
- - `InitializeParams` / `InitializeResult`
62
- - `Tool` / `ToolInputSchema` / `ToolCallRequest` / `ToolCallResult`
63
- - `TextContent` / `ImageContent`
64
- - `ERROR_CODES` 常量
65
-
66
- **SDK 提供**: `@modelcontextprotocol/sdk` 已导出所有这些类型。
67
-
68
- #### 2.2.3 工具注册系统(约 80 行)
69
-
70
- **文件**: `src/server/mcp-server.ts:180-250`
71
-
72
- 当前手动实现工具路由:
73
- ```typescript
74
- private async handleToolCall(request: ToolCallRequest): Promise<ToolCallResult> {
75
- const { name, arguments: args } = request;
76
- switch (name) {
77
- case 'memory_load': /* ... */
78
- case 'memory_update': /* ... */
79
- default: throw new ServiceError(`Unknown tool: ${name}`, ErrorCode.METHOD_NOT_FOUND);
80
- }
81
- }
82
- ```
83
-
84
- **SDK 替代方案**:
85
- ```typescript
86
- server.registerTool(
87
- "memory_load",
88
- { description: "...", inputSchema: { /* zod schema */ } },
89
- async (args) => { /* handler */ }
90
- );
91
- ```
92
-
93
- #### 2.2.4 stdio 传输层(约 60 行)
94
-
95
- **文件**: `src/server/mcp-server.ts:55-85`
96
-
97
- 当前手动处理:
98
- ```typescript
99
- process.stdin.setEncoding('utf-8');
100
- let buffer = '';
101
- process.stdin.on('data', (chunk: string) => {
102
- buffer += chunk;
103
- const lines = buffer.split('\n');
104
- buffer = lines.pop() || '';
105
- for (const line of lines) {
106
- if (line.trim()) void this.handleMessage(line.trim());
107
- }
108
- });
109
- ```
110
-
111
- **SDK 替代方案**:
112
- ```typescript
113
- const transport = new StdioServerTransport();
114
- await server.connect(transport);
115
- ```
116
-
117
- ### 2.3 维护风险
118
-
119
- 1. **协议兼容性风险**: MCP 协议版本更新时,需手动同步所有类型定义和逻辑
120
- 2. **错误处理不完整**: 当前实现可能遗漏边缘情况的错误处理
121
- 3. **缺少高级特性**: 如进度通知、取消请求、分页等 MCP 高级特性需自行实现
122
- 4. **测试负担**: 需自行测试协议合规性,而非依赖 SDK 的测试覆盖
123
-
124
- ## 3. 基于 @modelcontextprotocol/sdk 的目标架构
125
-
126
- ### 3.1 SDK 核心 API 概览
127
-
128
- ```typescript
129
- import { Server } from "@modelcontextprotocol/sdk/server/index.js";
130
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
131
-
132
- // 1. 创建服务器实例
133
- const server = new Server({
134
- name: "memhub",
135
- version: "1.0.0"
136
- }, {
137
- capabilities: {
138
- tools: { listChanged: false },
139
- logging: {}
140
- }
141
- });
142
-
143
- // 2. 注册工具
144
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
145
- // 工具调用处理
146
- });
147
-
148
- server.setRequestHandler(ListToolsRequestSchema, async () => {
149
- // 返回工具列表
150
- });
151
-
152
- // 3. 连接传输层
153
- const transport = new StdioServerTransport();
154
- await server.connect(transport);
155
- ```
156
-
157
- ### 3.2 目标架构图
158
-
159
- ```
160
- ┌─────────────────────────────────────────────────────────────┐
161
- │ MCP Client │
162
- └─────────────────────────────────────────────────────────────┘
163
-
164
- │ stdio (JSON-RPC)
165
-
166
- ┌─────────────────────────────────────────────────────────────┐
167
- │ @modelcontextprotocol/sdk │
168
- │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
169
- │ │ Server │ │ Stdio │ │ Request Handlers │ │
170
- │ │ Class │◄─┤ Transport │◄─┤ (tools/resources) │ │
171
- │ └─────────────┘ └─────────────┘ └─────────────────────┘ │
172
- └─────────────────────────────────────────────────────────────┘
173
-
174
-
175
- ┌─────────────────────────────────────────────────────────────┐
176
- │ memhub 业务层 │
177
- │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
178
- │ │ Memory │ │ Memory │ │ Tool Handlers │ │
179
- │ │ Service │ │ Storage │ │ (load/update) │ │
180
- │ └─────────────┘ └─────────────┘ └─────────────────────┘ │
181
- └─────────────────────────────────────────────────────────────┘
182
- ```
183
-
184
- ### 3.3 保留的自定义实现
185
-
186
- 以下组件将继续保留,因为它们属于业务逻辑而非协议层:
187
-
188
- | 组件 | 保留原因 |
189
- |------|----------|
190
- | `MemoryService` | 业务逻辑层,处理内存的加载/更新 |
191
- | `MarkdownStorage` | 存储层,处理 Markdown 文件读写 |
192
- | `FrontmatterParser` | 数据解析层,处理 YAML Front Matter |
193
- | Zod Schemas | 输入验证,与 SDK 的 Zod 依赖兼容 |
194
- | `types.ts` 中的业务类型 | `Memory`, `MemoryEntryType` 等 |
195
-
196
- ## 4. 分阶段迁移步骤
197
-
198
- ### 阶段 1:准备与依赖(第 1 周)
199
-
200
- **目标**: 添加 SDK 依赖,保持现有代码不变
201
-
202
- **任务清单**:
203
- - [ ] 安装 `@modelcontextprotocol/sdk` 依赖
204
- - [ ] 验证 Zod 版本兼容性(SDK 需要 Zod v3.25+)
205
- - [ ] 创建新的 `src/server/mcp-server-new.ts` 作为重构目标
206
- - [ ] 编写 SDK 版本的 Server 初始化代码
207
-
208
- **代码变更**:
209
- ```bash
210
- npm install @modelcontextprotocol/sdk
211
- ```
212
-
213
- ```typescript
214
- // src/server/mcp-server-new.ts (新建)
215
- import { Server } from "@modelcontextprotocol/sdk/server/index.js";
216
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
217
- import {
218
- CallToolRequestSchema,
219
- ListToolsRequestSchema,
220
- } from "@modelcontextprotocol/sdk/types.js";
221
- ```
222
-
223
- ### 阶段 2:工具迁移(第 2 周)
224
-
225
- **目标**: 将工具注册迁移到 SDK API
226
-
227
- **任务清单**:
228
- - [ ] 实现 `ListToolsRequestSchema` 处理器
229
- - [ ] 实现 `CallToolRequestSchema` 处理器
230
- - [ ] 将 `memory_load` 工具逻辑封装为 handler
231
- - [ ] 将 `memory_update` 工具逻辑封装为 handler
232
- - [ ] 复用现有的 Zod schema 进行输入验证
233
-
234
- **代码对比**:
235
-
236
- **当前方式**:
237
- ```typescript
238
- // src/server/mcp-server.ts
239
- private async handleToolCall(request: ToolCallRequest): Promise<ToolCallResult> {
240
- const { name, arguments: args } = request;
241
- switch (name) {
242
- case 'memory_load': {
243
- const input = MemoryLoadInputSchema.parse(args ?? {});
244
- result = await this.memoryService.memoryLoad(input);
245
- break;
246
- }
247
- // ...
248
- }
249
- }
250
- ```
251
-
252
- **SDK 方式**:
253
- ```typescript
254
- // src/server/mcp-server-new.ts
255
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
256
- const { name, arguments: args } = request.params;
257
-
258
- switch (name) {
259
- case 'memory_load': {
260
- const input = MemoryLoadInputSchema.parse(args ?? {});
261
- const result = await memoryService.memoryLoad(input);
262
- return {
263
- content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
264
- };
265
- }
266
- // ...
267
- }
268
- });
269
- ```
270
-
271
- ### 阶段 3:测试与验证(第 3 周)
272
-
273
- **目标**: 确保功能一致性
274
-
275
- **任务清单**:
276
- - [ ] 更新单元测试以支持新的 server 实例化方式
277
- - [ ] 运行集成测试验证工具调用流程
278
- - [ ] 验证错误处理行为一致
279
- - [ ] 验证日志输出格式
280
- - [ ] 性能对比测试(如有必要)
281
-
282
- **测试策略**:
283
- ```typescript
284
- // test/server/mcp-server-sdk.test.ts (新建)
285
- import { Server } from "@modelcontextprotocol/sdk/server/index.js";
286
- import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js"; // 如有提供
287
-
288
- describe('McpServer with SDK', () => {
289
- it('should handle initialize request', async () => {
290
- // 测试初始化流程
291
- });
292
-
293
- it('should list tools', async () => {
294
- // 测试工具列表
295
- });
296
-
297
- it('should call memory_load tool', async () => {
298
- // 测试工具调用
299
- });
300
- });
301
- ```
302
-
303
- ### 阶段 4:切换与清理(第 4 周)
304
-
305
- **目标**: 正式切换到 SDK 实现,清理旧代码
306
-
307
- **任务清单**:
308
- - [ ] 将 `mcp-server-new.ts` 重命名为 `mcp-server.ts`
309
- - [ ] 删除 `src/contracts/mcp.ts` 中的协议类型(保留业务类型)
310
- - [ ] 更新入口文件 `src/server/index.ts`
311
- - [ ] 更新 `src/index.ts` 导出
312
- - [ ] 删除旧的测试文件或更新为新的测试方式
313
- - [ ] 运行完整质量门禁
314
-
315
- **文件变更清单**:
316
- ```
317
- 修改:
318
- - src/server/mcp-server.ts (完全重写)
319
- - src/server/index.ts (更新导出)
320
- - src/contracts/mcp.ts (删除协议类型,保留工具定义)
321
- - package.json (添加依赖)
322
-
323
- 删除:
324
- - (可选) src/contracts/mcp.ts 中的部分类型定义
325
- ```
326
-
327
- ## 5. 风险与回滚策略
328
-
329
- ### 5.1 风险识别
330
-
331
- | 风险 | 可能性 | 影响 | 缓解措施 |
332
- |------|--------|------|----------|
333
- | SDK API 与现有实现行为不一致 | 中 | 高 | 阶段 3 全面测试,保留旧代码分支 |
334
- | Zod 版本冲突 | 低 | 中 | 验证 Zod v3.25+ 兼容性 |
335
- | 性能退化 | 低 | 中 | 阶段 3 性能基准测试 |
336
- | SDK 依赖增加包体积 | 低 | 低 | 评估 tree-shaking 效果 |
337
- | 协议版本不匹配 | 低 | 高 | 验证 SDK 支持的协议版本 |
338
-
339
- ### 5.2 回滚策略
340
-
341
- **预发布验证**:
342
- 1. 在 `beta` 分支完成所有迁移工作
343
- 2. 发布 `v0.2.0-beta.1` 版本进行内部测试
344
- 3. 验证通过后再合并到 `main`
345
-
346
- **紧急回滚**:
347
- ```bash
348
- # 如发现问题,立即回滚到上一版本
349
- git revert <migration-commit>
350
- npm run quality # 验证回滚后状态
351
- npm version patch
352
- npm publish
353
- ```
354
-
355
- **代码保留**:
356
- - 阶段 1-3 期间保留旧的 `mcp-server.ts` 为 `mcp-server-legacy.ts`
357
- - 仅在阶段 4 确认稳定后才删除旧代码
358
-
359
- ## 6. 测试与验收标准
360
-
361
- ### 6.1 功能测试矩阵
362
-
363
- | 测试场景 | 测试方法 | 验收标准 |
364
- |----------|----------|----------|
365
- | 服务器初始化 | 单元测试 | 正确响应 `initialize` 请求 |
366
- | 工具列表 | 单元测试 | 返回 `memory_load` 和 `memory_update` |
367
- | memory_load 调用 | 集成测试 | 正确加载内存数据 |
368
- | memory_update 调用 | 集成测试 | 正确创建/更新内存 |
369
- | 错误处理 | 单元测试 | 返回标准 JSON-RPC 错误格式 |
370
- | 无效工具名 | 单元测试 | 返回 `METHOD_NOT_FOUND` |
371
- | 参数验证失败 | 单元测试 | 返回 `INVALID_PARAMS` |
372
- | 服务器关闭 | 单元测试 | 正确处理 `shutdown`/`exit` |
373
- | 通知消息 | 单元测试 | 正确处理 `notifications/initialized` |
374
-
375
- ### 6.2 兼容性测试
376
-
377
- - [ ] 与 Claude Desktop 集成测试
378
- - [ ] 与 Cursor 集成测试
379
- - [ ] 与其他 MCP 客户端集成测试
380
-
381
- ### 6.3 质量门禁
382
-
383
- 所有以下检查必须通过:
384
-
385
- ```bash
386
- npm run lint # ESLint 无错误
387
- npm run typecheck # TypeScript 类型检查通过
388
- npm run test # 所有测试通过
389
- npm run test:coverage # 覆盖率 >= 80%
390
- ```
391
-
392
- ### 6.4 验收检查清单
393
-
394
- - [ ] 所有现有测试用例通过(无需修改测试断言)
395
- - [ ] 新的测试覆盖 SDK 集成点
396
- - [ ] 代码覆盖率不低于重构前
397
- - [ ] 手动验证与 Claude Desktop 的集成
398
- - [ ] README 文档更新(如需要)
399
-
400
- ## 7. 预计受影响文件列表
401
-
402
- ### 7.1 核心文件变更
403
-
404
- | 文件路径 | 变更类型 | 变更说明 |
405
- |----------|----------|----------|
406
- | `package.json` | 修改 | 添加 `@modelcontextprotocol/sdk` 依赖 |
407
- | `package-lock.json` | 修改 | 依赖锁定文件更新 |
408
- | `src/server/mcp-server.ts` | 重写 | 使用 SDK 的 Server 类重写 |
409
- | `src/server/index.ts` | 修改 | 更新导出(如有必要) |
410
- | `src/contracts/mcp.ts` | 修改 | 删除协议相关类型定义,保留工具定义 |
411
-
412
- ### 7.2 测试文件变更
413
-
414
- | 文件路径 | 变更类型 | 变更说明 |
415
- |----------|----------|----------|
416
- | `test/server/mcp-server.test.ts` | 修改 | 适配新的 Server 类结构 |
417
- | `test/server/mcp-server-internals.test.ts` | 删除/重写 | SDK 封装了内部方法,需重写测试 |
418
-
419
- ### 7.3 不受影响文件(业务逻辑层)
420
-
421
- 以下文件完全不受影响:
422
-
423
- - `src/services/memory-service.ts`
424
- - `src/storage/markdown-storage.ts`
425
- - `src/storage/frontmatter-parser.ts`
426
- - `src/contracts/schemas.ts`
427
- - `src/contracts/types.ts`
428
- - `src/utils/slugify.ts`
429
- - `test/services/*.test.ts`
430
- - `test/storage/*.test.ts`
431
-
432
- ## 8. 附录
433
-
434
- ### 8.1 SDK 参考资源
435
-
436
- - **NPM 包**: `@modelcontextprotocol/sdk`
437
- - **GitHub**: https://github.com/modelcontextprotocol/typescript-sdk
438
- - **文档**: https://modelcontextprotocol.io/docs/develop/build-server
439
- - **v1.x 分支**: https://github.com/modelcontextprotocol/typescript-sdk/tree/v1.x
440
-
441
- ### 8.2 SDK 关键 API 示例
442
-
443
- #### 8.2.1 完整的 SDK 服务器示例
444
-
445
- ```typescript
446
- #!/usr/bin/env node
447
- import { Server } from "@modelcontextprotocol/sdk/server/index.js";
448
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
449
- import {
450
- CallToolRequestSchema,
451
- ListToolsRequestSchema,
452
- } from "@modelcontextprotocol/sdk/types.js";
453
- import { z } from "zod";
454
-
455
- // 创建服务器
456
- const server = new Server(
457
- {
458
- name: "memhub",
459
- version: "1.0.0",
460
- },
461
- {
462
- capabilities: {
463
- tools: {},
464
- },
465
- }
466
- );
467
-
468
- // 工具定义
469
- const TOOLS = [
470
- {
471
- name: "memory_load",
472
- description: "STM first step. Call at the first turn...",
473
- inputSchema: {
474
- type: "object" as const,
475
- properties: {
476
- id: { type: "string" },
477
- sessionId: { type: "string" },
478
- // ...
479
- },
480
- },
481
- },
482
- {
483
- name: "memory_update",
484
- description: "STM write-back step...",
485
- inputSchema: {
486
- type: "object" as const,
487
- properties: {
488
- content: { type: "string" },
489
- // ...
490
- },
491
- required: ["content"],
492
- },
493
- },
494
- ];
495
-
496
- // 注册处理器
497
- server.setRequestHandler(ListToolsRequestSchema, async () => {
498
- return { tools: TOOLS };
499
- });
500
-
501
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
502
- const { name, arguments: args } = request.params;
503
-
504
- switch (name) {
505
- case "memory_load": {
506
- // 调用 MemoryService
507
- const result = await memoryService.memoryLoad(args as MemoryLoadInput);
508
- return {
509
- content: [
510
- {
511
- type: "text",
512
- text: JSON.stringify(result, null, 2),
513
- },
514
- ],
515
- };
516
- }
517
- case "memory_update": {
518
- // 调用 MemoryService
519
- const result = await memoryService.memoryUpdate(args as MemoryUpdateInput);
520
- return {
521
- content: [
522
- {
523
- type: "text",
524
- text: JSON.stringify(result, null, 2),
525
- },
526
- ],
527
- };
528
- }
529
- default:
530
- throw new Error(`Unknown tool: ${name}`);
531
- }
532
- });
533
-
534
- // 启动服务器
535
- async function main() {
536
- const transport = new StdioServerTransport();
537
- await server.connect(transport);
538
- console.error("MemHub MCP Server running on stdio");
539
- }
540
-
541
- main().catch((error) => {
542
- console.error("Fatal error:", error);
543
- process.exit(1);
544
- });
545
- ```
546
-
547
- ### 8.3 变更估算
548
-
549
- | 指标 | 估算 |
550
- |------|------|
551
- | 预计删除代码行数 | ~350 行(协议层实现) |
552
- | 预计新增代码行数 | ~150 行(SDK 集成) |
553
- | 净减少代码行数 | ~200 行 |
554
- | 预计开发时间 | 4 周(按阶段) |
555
- | 测试覆盖率要求 | >= 80% |
556
-
557
- ---
558
-
559
- ## 9. 结论
560
-
561
- 使用 `@modelcontextprotocol/sdk` 重构 memhub 的 MCP 实现将带来以下收益:
562
-
563
- 1. **减少维护负担**: 消除 ~350 行协议层代码,由官方 SDK 维护
564
- 2. **提高可靠性**: 利用 SDK 的测试覆盖和协议合规性
565
- 3. **易于扩展**: SDK 提供的高级特性(进度通知、取消等)可直接使用
566
- 4. **未来兼容**: SDK 会跟随 MCP 协议更新,无需手动同步
567
-
568
- 建议按阶段执行此重构,确保每个阶段的质量门禁通过后再进入下一阶段。
@@ -1,58 +0,0 @@
1
- # Proposal: Close Remaining Quality Gates (Phase 2)
2
-
3
- ## Context
4
- Current implementation already has broad functionality and passing test suites, but quality gates are still blocked by:
5
-
6
- 1. ESLint configuration/type-aware parsing issues on test files
7
- 2. TypeScript typecheck errors in server and storage/service imports
8
- 3. Coverage gate failure on function coverage (<80%)
9
- 4. Project path inconsistency (`workspace/workspace/memhub`)
10
-
11
- ## Root Causes
12
- - ESLint `parserOptions.project` only pointed to `tsconfig.json`, while test files are not included there.
13
- - Some implementation details introduced strict-mode lint/type mismatches (`any` usage, fallthrough, readonly/no-unused issues).
14
- - Existing server tests focus on constants/contracts but not internal execution paths, leaving many functions uncovered.
15
- - Project was scaffolded under a nested directory.
16
-
17
- ## Plan of Record
18
-
19
- ### Step 1 — Fix static quality gates
20
- - Update ESLint type-aware project references to include test TS config.
21
- - Update `tsconfig.test.json` include set.
22
- - Fix strict lint/type issues in server/service/storage/utils modules.
23
-
24
- ### Step 2 — Raise function coverage to >=80%
25
- - Add focused tests for MCP server runtime paths:
26
- - JSON parsing failure path
27
- - invalid request path
28
- - method dispatch (`initialize`, `tools/list`, `tools/call`, unknown method)
29
- - error handling (`ServiceError`, validation-like error, generic error)
30
- - response/error serialization
31
- - log filtering behavior
32
- - Preserve existing passing behavior and avoid over-mocking core service logic.
33
-
34
- ### Step 3 — Validate full gate
35
- Run and require pass for:
36
- - `npm run lint`
37
- - `npm run typecheck`
38
- - `npm run test`
39
- - `npm run test:coverage` (global lines/functions/branches/statements >= 80)
40
-
41
- ### Step 4 — Normalize repository location
42
- - Move project to `C:\Users\cloud_user\.openclaw\workspace\memhub` (if missing).
43
- - Verify scripts still run from new root.
44
-
45
- ## Acceptance Criteria
46
- - No lint errors
47
- - No typecheck errors
48
- - All tests pass
49
- - Coverage thresholds all >= 80%
50
- - Repository available at normalized path
51
-
52
- ## Risks and Mitigations
53
- - **Risk:** Private method tests become brittle.
54
- - **Mitigation:** Test externally visible behavior and error contracts where possible; keep internals tests focused and minimal.
55
- - **Risk:** Path migration may break references.
56
- - **Mitigation:** Move whole directory atomically and rerun full gate.
57
- - **Risk:** Coverage improvements skew test value.
58
- - **Mitigation:** Prefer behavior-driven tests over shallow line-hitting.