@ppdocs/mcp 2.3.0 → 2.4.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.
package/README.md ADDED
@@ -0,0 +1,476 @@
1
+ # @ppdocs/mcp
2
+
3
+ > Knowledge Graph MCP Server for Claude - 让 Claude 拥有项目知识图谱记忆
4
+
5
+ [![npm version](https://badge.fury.io/js/%40ppdocs%2Fmcp.svg)](https://www.npmjs.com/package/@ppdocs/mcp)
6
+
7
+ ## 概述
8
+
9
+ ppdocs MCP 是一个 [Model Context Protocol](https://modelcontextprotocol.io/) 服务器,让 Claude 能够在对话中构建和查询项目知识图谱。
10
+
11
+ ```mermaid
12
+ graph LR
13
+ Claude[Claude AI] -->|MCP| Server[@ppdocs/mcp]
14
+ Server -->|HTTP API| Backend[ppdocs 桌面应用]
15
+ Backend -->|文件存储| Data[(知识图谱)]
16
+
17
+ style Claude fill:#7c3aed,color:#fff
18
+ style Server fill:#3b82f6,color:#fff
19
+ style Backend fill:#10b981,color:#fff
20
+ ```
21
+
22
+ ### 核心功能
23
+
24
+ | 功能 | 描述 |
25
+ |------|------|
26
+ | 📊 **知识图谱** | 创建、更新、删除、搜索节点 |
27
+ | 🔗 **依赖追踪** | 自动计算节点间的依赖关系 |
28
+ | 📝 **任务管理** | 记录开发任务、进度日志、经验总结 |
29
+ | 🔍 **智能搜索** | 多关键词搜索,按相关度排序 |
30
+ | 🛤️ **路径分析** | 查找两节点间的依赖路径 |
31
+
32
+ ---
33
+
34
+ ## 快速开始
35
+
36
+ ### 1. 安装
37
+
38
+ ```bash
39
+ npm install -g @ppdocs/mcp
40
+ ```
41
+
42
+ ### 2. 配置 Claude Desktop
43
+
44
+ 在 Claude Desktop 配置文件中添加:
45
+
46
+ **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
47
+ **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
48
+
49
+ ```json
50
+ {
51
+ "mcpServers": {
52
+ "ppdocs": {
53
+ "command": "npx",
54
+ "args": ["-y", "@ppdocs/mcp"],
55
+ "env": {
56
+ "PPDOCS_API_URL": "http://localhost:20001/api/项目ID/密码"
57
+ }
58
+ }
59
+ }
60
+ }
61
+ ```
62
+
63
+ ### 3. 获取 API URL
64
+
65
+ 1. 打开 ppdocs 桌面应用
66
+ 2. 选择一个项目 → 点击设置图标
67
+ 3. 复制 **MCP 连接地址**
68
+
69
+ ```mermaid
70
+ sequenceDiagram
71
+ participant U as 用户
72
+ participant App as ppdocs 桌面应用
73
+ participant Claude as Claude Desktop
74
+
75
+ U->>App: 1. 打开项目设置
76
+ App->>U: 2. 显示 MCP 连接地址
77
+ U->>Claude: 3. 配置 claude_desktop_config.json
78
+ Claude->>App: 4. MCP 连接成功
79
+ ```
80
+
81
+ ---
82
+
83
+ ## 工具列表
84
+
85
+ ### 知识图谱工具
86
+
87
+ ```mermaid
88
+ mindmap
89
+ root((知识图谱))
90
+ 创建
91
+ kg_create_node
92
+ 修改
93
+ kg_update_node
94
+ kg_lock_node
95
+ kg_delete_node
96
+ 查询
97
+ kg_list_nodes
98
+ kg_search
99
+ kg_find_path
100
+ kg_find_orphans
101
+ kg_get_relations
102
+ ```
103
+
104
+ #### `kg_create_node` - 创建节点
105
+
106
+ 创建一个新的知识节点。
107
+
108
+ | 参数 | 类型 | 必填 | 说明 |
109
+ |------|------|------|------|
110
+ | `title` | string | ✅ | 节点标题 |
111
+ | `type` | enum | ✅ | 节点类型: `logic`(逻辑/函数), `data`(数据结构), `intro`(概念介绍) |
112
+ | `description` | string | ✅ | Markdown 描述 (建议使用 Mermaid 图表 + 表格) |
113
+ | `signature` | string | ❌ | 唯一签名,用于依赖匹配 (默认=title) |
114
+ | `tags` | string[] | ❌ | 分类标签 |
115
+ | `dependencies` | object[] | ❌ | 依赖列表: `[{name: "目标签名", description: "依赖说明"}]` |
116
+
117
+ **示例:**
118
+ ```
119
+ Claude, 创建一个节点记录用户认证模块
120
+ ```
121
+
122
+ ---
123
+
124
+ #### `kg_update_node` - 更新节点
125
+
126
+ 更新现有节点的内容(锁定节点不可更新)。
127
+
128
+ | 参数 | 类型 | 必填 | 说明 |
129
+ |------|------|------|------|
130
+ | `nodeId` | string | ✅ | 节点 ID |
131
+ | `title` | string | ❌ | 新标题 |
132
+ | `description` | string | ❌ | 新描述 |
133
+ | `status` | enum | ❌ | 状态: `incomplete`, `complete`, `fixing`, `refactoring`, `deprecated` |
134
+ | `tags` | string[] | ❌ | 新标签 |
135
+ | `dependencies` | object[] | ❌ | 新依赖列表 |
136
+
137
+ ---
138
+
139
+ #### `kg_delete_node` - 删除节点
140
+
141
+ 删除指定节点(锁定节点和根节点不可删除)。
142
+
143
+ | 参数 | 类型 | 必填 | 说明 |
144
+ |------|------|------|------|
145
+ | `nodeId` | string | ✅ | 节点 ID |
146
+
147
+ ---
148
+
149
+ #### `kg_lock_node` - 锁定节点
150
+
151
+ 锁定节点后只能读取,不能修改或删除。
152
+
153
+ > ⚠️ **安全限制**: AI 只能锁定节点,**不能解锁**。解锁需要用户在前端手动操作。
154
+
155
+ | 参数 | 类型 | 必填 | 说明 |
156
+ |------|------|------|------|
157
+ | `nodeId` | string | ✅ | 节点 ID |
158
+
159
+ ---
160
+
161
+ #### `kg_list_nodes` - 列出所有节点
162
+
163
+ 获取项目中所有节点的概览。
164
+
165
+ 无参数。
166
+
167
+ ---
168
+
169
+ #### `kg_search` - 搜索节点
170
+
171
+ 使用关键词搜索节点,按相关度排序返回。
172
+
173
+ | 参数 | 类型 | 必填 | 说明 |
174
+ |------|------|------|------|
175
+ | `keywords` | string[] | ✅ | 关键词列表 (OR 逻辑) |
176
+ | `limit` | number | ❌ | 返回数量上限 (默认 20) |
177
+
178
+ **示例:**
179
+ ```
180
+ Claude, 搜索所有和数据库相关的节点
181
+ ```
182
+
183
+ ---
184
+
185
+ #### `kg_find_path` - 查找依赖路径
186
+
187
+ 查找两个节点之间的依赖路径。
188
+
189
+ | 参数 | 类型 | 必填 | 说明 |
190
+ |------|------|------|------|
191
+ | `startId` | string | ✅ | 起点节点 ID |
192
+ | `endId` | string | ✅ | 终点节点 ID |
193
+
194
+ ---
195
+
196
+ #### `kg_find_orphans` - 查找孤立节点
197
+
198
+ 查找没有任何连线的孤立节点,用于清理。
199
+
200
+ 无参数。
201
+
202
+ ---
203
+
204
+ #### `kg_get_relations` - 获取节点关系
205
+
206
+ 获取指定节点的上下游关系网络。
207
+
208
+ | 参数 | 类型 | 必填 | 说明 |
209
+ |------|------|------|------|
210
+ | `nodeId` | string | ✅ | 节点 ID |
211
+
212
+ **返回:**
213
+ - `outgoing`: 该节点依赖的其他节点
214
+ - `incoming`: 依赖该节点的其他节点
215
+
216
+ ---
217
+
218
+ ### 任务管理工具
219
+
220
+ ```mermaid
221
+ stateDiagram-v2
222
+ [*] --> Active: task_create
223
+ Active --> Active: task_add_log
224
+ Active --> Archived: task_complete
225
+ Archived --> [*]
226
+
227
+ state Active {
228
+ progress
229
+ issue
230
+ solution
231
+ reference
232
+ }
233
+ ```
234
+
235
+ #### `task_create` - 创建任务
236
+
237
+ 创建一个新的开发任务。
238
+
239
+ | 参数 | 类型 | 必填 | 说明 |
240
+ |------|------|------|------|
241
+ | `title` | string | ✅ | 任务标题 |
242
+ | `description` | string | ✅ | 任务描述 (Markdown) |
243
+ | `goals` | string[] | ❌ | 目标清单 |
244
+ | `related_nodes` | string[] | ❌ | 关联的知识节点 ID |
245
+
246
+ **示例:**
247
+ ```
248
+ Claude, 创建一个任务:实现用户登录功能
249
+ ```
250
+
251
+ ---
252
+
253
+ #### `task_list` - 列出任务
254
+
255
+ 列出项目中的任务。
256
+
257
+ | 参数 | 类型 | 必填 | 说明 |
258
+ |------|------|------|------|
259
+ | `status` | enum | ❌ | 筛选: `active`(进行中) 或 `archived`(已归档) |
260
+
261
+ ---
262
+
263
+ #### `task_get` - 获取任务详情
264
+
265
+ 获取任务的完整信息,包含所有日志记录。
266
+
267
+ | 参数 | 类型 | 必填 | 说明 |
268
+ |------|------|------|------|
269
+ | `taskId` | string | ✅ | 任务 ID |
270
+
271
+ ---
272
+
273
+ #### `task_add_log` - 添加日志
274
+
275
+ 为任务记录进展、问题、方案或参考资料。
276
+
277
+ | 参数 | 类型 | 必填 | 说明 |
278
+ |------|------|------|------|
279
+ | `taskId` | string | ✅ | 任务 ID |
280
+ | `log_type` | enum | ✅ | 日志类型: `progress`, `issue`, `solution`, `reference` |
281
+ | `content` | string | ✅ | 日志内容 (Markdown) |
282
+
283
+ ---
284
+
285
+ #### `task_complete` - 完成任务
286
+
287
+ 完成任务并归档,需要填写经验总结。
288
+
289
+ | 参数 | 类型 | 必填 | 说明 |
290
+ |------|------|------|------|
291
+ | `taskId` | string | ✅ | 任务 ID |
292
+ | `summary` | string | ✅ | 经验总结 (Markdown) |
293
+ | `difficulties` | string[] | ❌ | 遇到的困难 |
294
+ | `solutions` | string[] | ❌ | 解决方案 |
295
+ | `references` | object[] | ❌ | 参考资料: `[{title: "标题", url: "链接"}]` |
296
+
297
+ ---
298
+
299
+ ## 数据结构
300
+
301
+ ### 节点类型
302
+
303
+ ```mermaid
304
+ classDiagram
305
+ class NodeData {
306
+ +string id
307
+ +string title
308
+ +NodeType type
309
+ +NodeStatus status
310
+ +string signature
311
+ +string description
312
+ +string[] categories
313
+ +Dependency[] dependencies
314
+ +boolean locked
315
+ +number x, y
316
+ }
317
+
318
+ class Dependency {
319
+ +string name
320
+ +string description
321
+ }
322
+
323
+ NodeData --> Dependency
324
+ ```
325
+
326
+ | 类型 | 说明 | 适用场景 |
327
+ |------|------|----------|
328
+ | `logic` | 逻辑/函数 | 算法、处理流程、API 接口 |
329
+ | `data` | 数据结构 | 数据库表、配置、状态定义 |
330
+ | `intro` | 概念介绍 | 架构说明、设计决策、术语解释 |
331
+
332
+ ### 节点状态
333
+
334
+ | 状态 | 说明 |
335
+ |------|------|
336
+ | `incomplete` | 未完成 (默认) |
337
+ | `complete` | 已完成 |
338
+ | `fixing` | 修复中 |
339
+ | `refactoring` | 重构中 |
340
+ | `deprecated` | 已废弃 |
341
+
342
+ ---
343
+
344
+ ## 架构说明
345
+
346
+ ```mermaid
347
+ flowchart TB
348
+ subgraph Claude["Claude Desktop"]
349
+ MCP[MCP 协议]
350
+ end
351
+
352
+ subgraph Server["@ppdocs/mcp"]
353
+ Tools[工具注册]
354
+ HTTP[HTTP Client]
355
+ end
356
+
357
+ subgraph Backend["ppdocs 桌面应用"]
358
+ API[REST API]
359
+ Store[文件存储]
360
+ end
361
+
362
+ subgraph Data["数据目录 ~/.ppdocs"]
363
+ Projects[projects/]
364
+ Tasks[tasks/]
365
+ Backups[backups/]
366
+ end
367
+
368
+ MCP <-->|stdio| Tools
369
+ Tools --> HTTP
370
+ HTTP <-->|HTTP| API
371
+ API --> Store
372
+ Store --> Projects
373
+ Store --> Tasks
374
+ Store --> Backups
375
+ ```
376
+
377
+ ### 文件结构
378
+
379
+ ```
380
+ ~/.ppdocs/
381
+ ├── projects/
382
+ │ └── {project-id}/
383
+ │ ├── meta.json # 项目元数据
384
+ │ └── nodes/
385
+ │ └── {node-id}.json
386
+ ├── tasks/
387
+ │ └── {project-id}/
388
+ │ ├── active/ # 进行中的任务
389
+ │ └── archived/ # 已归档的任务
390
+ └── backups/
391
+ └── {project-id}/
392
+ └── {timestamp}/
393
+ ```
394
+
395
+ ---
396
+
397
+ ## 环境变量
398
+
399
+ | 变量 | 说明 | 示例 |
400
+ |------|------|------|
401
+ | `PPDOCS_API_URL` | API 完整地址 | `http://localhost:20001/api/myproject/abc123` |
402
+ | `PPDOCS_PROJECT` | 项目 ID (可选) | `myproject` |
403
+ | `PPDOCS_KEY` | 访问密钥 (可选) | `abc123` |
404
+ | `PPDOCS_USER` | 用户名 (可选) | `developer` |
405
+ | `PPDOCS_PORT` | API 端口 (可选) | `20001` |
406
+ | `PPDOCS_HOST` | API 主机 (可选) | `localhost` |
407
+
408
+ ### 配置文件
409
+
410
+ 也可以在项目根目录创建 `.ppdocs` 文件:
411
+
412
+ ```json
413
+ {
414
+ "project": "my-project",
415
+ "key": "abc123",
416
+ "user": "developer",
417
+ "port": 20001,
418
+ "api": "localhost"
419
+ }
420
+ ```
421
+
422
+ ---
423
+
424
+ ## 常见问题
425
+
426
+ ### Q: 连接失败怎么办?
427
+
428
+ 1. 确保 ppdocs 桌面应用正在运行
429
+ 2. 检查端口是否正确 (默认 20001)
430
+ 3. 验证 API URL 格式: `http://localhost:PORT/api/项目ID/密码`
431
+
432
+ ### Q: 节点无法删除?
433
+
434
+ 可能的原因:
435
+ - 节点被锁定 → 在 ppdocs 桌面应用中手动解锁
436
+ - 是根节点 (isOrigin=true) → 根节点不可删除
437
+
438
+ ### Q: 如何备份数据?
439
+
440
+ 1. **桌面应用**: 设置 → 数据管理 → 导出全部项目
441
+ 2. **手动备份**: 复制 `~/.ppdocs/` 目录
442
+
443
+ ---
444
+
445
+ ## 更新日志
446
+
447
+ ### v2.4.0
448
+ - 🛡️ 安全增强:`kg_lock_node` 只能锁定,解锁需前端手动操作
449
+ - ⚡ 日志系统重构:后端自动记录操作日志,无需 AI 主动调用
450
+ - 🐛 修复画布缩放闪烁问题
451
+
452
+ ### v2.3.0
453
+ - 新增任务管理功能 (task_create, task_complete 等)
454
+ - 优化搜索算法
455
+ - 添加文件锁防止并发写入
456
+
457
+ ### v2.2.0
458
+ - 从文件存储切换到 HTTP API
459
+ - 支持多用户协作
460
+
461
+ ### v2.0.0
462
+ - 初始 MCP 服务器版本
463
+
464
+ ---
465
+
466
+ ## 许可证
467
+
468
+ MIT License
469
+
470
+ ---
471
+
472
+ ## 相关链接
473
+
474
+ - [ppdocs 桌面应用](https://github.com/ppdocs/ppdocs)
475
+ - [MCP 协议文档](https://modelcontextprotocol.io/)
476
+ - [问题反馈](https://github.com/ppdocs/ppdocs/issues)
@@ -83,10 +83,3 @@ export declare function createTask(_projectId: string, task: {
83
83
  }, creator: string): Promise<Task>;
84
84
  export declare function addTaskLog(_projectId: string, taskId: string, logType: TaskLogType, content: string): Promise<Task | null>;
85
85
  export declare function completeTask(_projectId: string, taskId: string, experience: TaskExperience): Promise<Task | null>;
86
- export interface LogEntry {
87
- user: string;
88
- action: string;
89
- target: string;
90
- node_id?: string;
91
- }
92
- export declare function appendLog(_projectId: string, entry: LogEntry): Promise<void>;
@@ -14,22 +14,36 @@ export class PpdocsApiClient {
14
14
  // ============ HTTP 请求工具 ============
15
15
  async request(path, options = {}) {
16
16
  const url = `${this.baseUrl}${path}`;
17
- const response = await fetch(url, {
18
- ...options,
19
- headers: {
20
- 'Content-Type': 'application/json',
21
- ...options.headers
17
+ const controller = new AbortController();
18
+ const timeout = setTimeout(() => controller.abort(), 10000); // 10秒超时
19
+ try {
20
+ const response = await fetch(url, {
21
+ ...options,
22
+ signal: controller.signal,
23
+ headers: {
24
+ 'Content-Type': 'application/json',
25
+ ...options.headers
26
+ }
27
+ });
28
+ if (!response.ok) {
29
+ const error = await response.json().catch(() => ({ error: response.statusText }));
30
+ throw new Error(error.error || `HTTP ${response.status}`);
22
31
  }
23
- });
24
- if (!response.ok) {
25
- const error = await response.json().catch(() => ({ error: response.statusText }));
26
- throw new Error(error.error || `HTTP ${response.status}`);
32
+ const json = await response.json();
33
+ if (!json.success) {
34
+ throw new Error(json.error || 'Unknown error');
35
+ }
36
+ return json.data;
37
+ }
38
+ catch (err) {
39
+ if (err instanceof Error && err.name === 'AbortError') {
40
+ throw new Error('Request timeout (10s)');
41
+ }
42
+ throw err;
27
43
  }
28
- const json = await response.json();
29
- if (!json.success) {
30
- throw new Error(json.error || 'Unknown error');
44
+ finally {
45
+ clearTimeout(timeout);
31
46
  }
32
- return json.data;
33
47
  }
34
48
  // ============ 节点操作 ============
35
49
  async listNodes() {
@@ -272,15 +286,3 @@ export async function addTaskLog(_projectId, taskId, logType, content) {
272
286
  export async function completeTask(_projectId, taskId, experience) {
273
287
  return getClient().completeTask(taskId, experience);
274
288
  }
275
- export async function appendLog(_projectId, entry) {
276
- try {
277
- await getClient()['request']('/logs', {
278
- method: 'POST',
279
- body: JSON.stringify(entry)
280
- });
281
- console.error(`[LOG] ${entry.action}: ${entry.target}`);
282
- }
283
- catch (err) {
284
- console.error(`[LOG ERROR] Failed to append log:`, err);
285
- }
286
- }
@@ -6,7 +6,7 @@ export interface Edge {
6
6
  auto?: boolean;
7
7
  }
8
8
  export type NodeType = 'logic' | 'data' | 'intro';
9
- export type NodeStatus = 'incomplete' | 'complete' | 'fixing' | 'refactoring' | 'deprecated' | 'locked';
9
+ export type NodeStatus = 'incomplete' | 'complete' | 'fixing' | 'refactoring' | 'deprecated';
10
10
  export interface DataRef {
11
11
  type: string;
12
12
  description: string;
@@ -1,2 +1,2 @@
1
1
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
- export declare function registerTools(server: McpServer, projectId: string, user: string): void;
2
+ export declare function registerTools(server: McpServer, projectId: string, _user: string): void;
@@ -1,10 +1,6 @@
1
1
  import { z } from 'zod';
2
2
  import * as storage from '../storage/httpClient.js';
3
- export function registerTools(server, projectId, user) {
4
- // 日志辅助函数
5
- const log = (action, target, nodeId) => {
6
- storage.appendLog(projectId, { user, action, target, node_id: nodeId });
7
- };
3
+ export function registerTools(server, projectId, _user) {
8
4
  // 1. 创建节点
9
5
  server.tool('kg_create_node', '创建知识节点。type: logic=逻辑/函数, data=数据结构, intro=概念介绍', {
10
6
  title: z.string().describe('节点标题'),
@@ -29,15 +25,11 @@ export function registerTools(server, projectId, user) {
29
25
  categories: args.tags || [],
30
26
  dependencies: args.dependencies || []
31
27
  });
32
- log('create_node', args.title, node.id);
33
28
  return { content: [{ type: 'text', text: JSON.stringify(node, null, 2) }] };
34
29
  });
35
30
  // 2. 删除节点
36
31
  server.tool('kg_delete_node', '删除节点(锁定节点和根节点不可删除)', { nodeId: z.string().describe('节点ID') }, async (args) => {
37
- const node = await storage.getNode(projectId, args.nodeId);
38
32
  const success = await storage.deleteNode(projectId, args.nodeId);
39
- if (success)
40
- log('delete_node', node?.title || args.nodeId, args.nodeId);
41
33
  return { content: [{ type: 'text', text: success ? '删除成功' : '删除失败(节点不存在/已锁定/是根节点)' }] };
42
34
  });
43
35
  // 3. 更新节点
@@ -57,18 +49,13 @@ export function registerTools(server, projectId, user) {
57
49
  // API 参数 tags 转换为内部字段 categories
58
50
  const updates = tags !== undefined ? { ...rest, categories: tags } : rest;
59
51
  const node = await storage.updateNode(projectId, nodeId, updates);
60
- if (node)
61
- log('update_node', node.title, nodeId);
62
52
  return { content: [{ type: 'text', text: node ? JSON.stringify(node, null, 2) : '更新失败(节点不存在或已锁定)' }] };
63
53
  });
64
- // 4. 锁定/解锁节点
65
- server.tool('kg_lock_node', '锁定/解锁节点(锁定后只能读取)', {
66
- nodeId: z.string().describe('节点ID'),
67
- locked: z.boolean().describe('true=锁定, false=解锁')
54
+ // 4. 锁定节点 (只能锁定,解锁需用户在前端手动操作)
55
+ server.tool('kg_lock_node', '锁定节点(锁定后只能读取,解锁需用户在前端手动操作)', {
56
+ nodeId: z.string().describe('节点ID')
68
57
  }, async (args) => {
69
- const node = await storage.lockNode(projectId, args.nodeId, args.locked);
70
- if (node)
71
- log(args.locked ? 'lock_node' : 'unlock_node', node.title, args.nodeId);
58
+ const node = await storage.lockNode(projectId, args.nodeId, true); // 强制锁定
72
59
  return { content: [{ type: 'text', text: node ? JSON.stringify(node, null, 2) : '操作失败' }] };
73
60
  });
74
61
  // 5. 搜索节点
@@ -142,8 +129,7 @@ export function registerTools(server, projectId, user) {
142
129
  description: args.description,
143
130
  goals: args.goals || [],
144
131
  related_nodes: args.related_nodes
145
- }, user);
146
- log('create_task', args.title, task.id);
132
+ }, _user);
147
133
  return { content: [{ type: 'text', text: JSON.stringify(task, null, 2) }] };
148
134
  });
149
135
  // 11. 列出任务
@@ -181,7 +167,6 @@ export function registerTools(server, projectId, user) {
181
167
  if (!task) {
182
168
  return { content: [{ type: 'text', text: '添加失败(任务不存在或已归档)' }] };
183
169
  }
184
- log('add_task_log', `${args.log_type}: ${args.content.slice(0, 50)}...`, args.taskId);
185
170
  return { content: [{ type: 'text', text: `日志已添加,任务共有 ${task.logs.length} 条日志` }] };
186
171
  });
187
172
  // 14. 完成任务
@@ -204,7 +189,6 @@ export function registerTools(server, projectId, user) {
204
189
  if (!task) {
205
190
  return { content: [{ type: 'text', text: '完成失败(任务不存在或已归档)' }] };
206
191
  }
207
- log('complete_task', task.title, args.taskId);
208
192
  return { content: [{ type: 'text', text: `任务已完成归档: ${task.title}` }] };
209
193
  });
210
194
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ppdocs/mcp",
3
- "version": "2.3.0",
3
+ "version": "2.4.0",
4
4
  "description": "ppdocs MCP Server - Knowledge Graph for Claude",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",