@ppdocs/mcp 3.10.0 → 3.13.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 +7 -3
- package/dist/cli.js +27 -2
- package/dist/index.js +48 -1
- package/dist/storage/httpClient.d.ts +22 -1
- package/dist/storage/httpClient.js +50 -0
- package/dist/storage/types.d.ts +62 -0
- package/dist/tools/analyzer.d.ts +1 -4
- package/dist/tools/analyzer.js +4 -7
- package/dist/tools/flowchart.js +1 -3
- package/dist/tools/index.d.ts +8 -9
- package/dist/tools/index.js +8 -27
- package/dist/tools/init.js +1 -1
- package/dist/tools/kg_status.d.ts +1 -1
- package/dist/tools/kg_status.js +4 -6
- package/dist/tools/refs.js +77 -71
- package/dist/tools/tasks.d.ts +1 -2
- package/dist/tools/tasks.js +32 -46
- package/dist/tools/workflow.js +2 -3
- package/package.json +1 -1
- package/dist/tools/discussion.d.ts +0 -15
- package/dist/tools/discussion.js +0 -264
- package/dist/tools/doc_query.d.ts +0 -10
- package/dist/tools/doc_query.js +0 -185
- package/dist/tools/files.d.ts +0 -6
- package/dist/tools/files.js +0 -107
- package/dist/tools/meeting.d.ts +0 -7
- package/dist/tools/meeting.js +0 -97
- package/dist/tools/projects.d.ts +0 -7
- package/dist/tools/projects.js +0 -19
package/README.md
CHANGED
|
@@ -116,9 +116,7 @@ npx @ppdocs/mcp init -p <projectId> -k <key> --codex
|
|
|
116
116
|
| `kg_flowchart` | 统一的知识图谱入口,负责查询、更新、关系分析 |
|
|
117
117
|
| `kg_workflow` | Markdown 文档工作流管理 |
|
|
118
118
|
| `kg_task` | 任务管理 |
|
|
119
|
-
| `
|
|
120
|
-
| `kg_discuss` | 讨论区 |
|
|
121
|
-
| `kg_meeting` | 多 AI 协作会议 |
|
|
119
|
+
| `kg_ref` | 外部参考资料(URL拉取、查看、删除) |
|
|
122
120
|
| `code_scan` | 代码扫描 |
|
|
123
121
|
| `code_smart_context` | 获取符号的智能上下文 |
|
|
124
122
|
| `code_full_path` | 获取两个符号之间的全路径 |
|
|
@@ -207,6 +205,12 @@ kg_flowchart(action:"update_node", chartId:"main", nodeId:"n_storage",
|
|
|
207
205
|
|
|
208
206
|
## 更新日志
|
|
209
207
|
|
|
208
|
+
### v3.3.0
|
|
209
|
+
- 移除 6 个低使用率工具: `kg_doc`, `kg_discuss`, `kg_meeting`, `kg_files`, `kg_projects`, `kg_pitfall`
|
|
210
|
+
- `kg_ref` 精简为 4 个 action: `list|get|fetch|delete`
|
|
211
|
+
- 所有工具描述精简,减少 token 开销
|
|
212
|
+
- 移除前端孤立组件: FloatingDiscussion, PitfallRecord, ImpactGraph
|
|
213
|
+
|
|
210
214
|
### v3.2.36
|
|
211
215
|
- 统一为 `flowchart-first` MCP 接口模型
|
|
212
216
|
- `kg_flowchart` 新增 `search` / `get_relations` / `find_path`
|
package/dist/cli.js
CHANGED
|
@@ -90,7 +90,7 @@ function showHelp() {
|
|
|
90
90
|
ppdocs MCP CLI
|
|
91
91
|
|
|
92
92
|
Commands:
|
|
93
|
-
init Full setup: .ppdocs + templates + MCP registration
|
|
93
|
+
init Full setup: .ppdocs + templates + MCP registration (Claude/Codex/OpenCode/Gemini)
|
|
94
94
|
bind Lightweight: only create .ppdocs (for adding projects to existing MCP)
|
|
95
95
|
|
|
96
96
|
Usage:
|
|
@@ -270,6 +270,13 @@ function autoRegisterMcp(cwd, apiUrl, user, skipGemini = false) {
|
|
|
270
270
|
for (const pair of envPairs) {
|
|
271
271
|
args.push(envFlag, pair);
|
|
272
272
|
}
|
|
273
|
+
// macOS/Linux: 必须注入 PATH,否则 Claude Code 启动 MCP 时可能找不到 npx/node
|
|
274
|
+
// (Claude Code 进程的 PATH 通常不含 /opt/homebrew/bin 等 Homebrew/nvm 路径)
|
|
275
|
+
if (process.platform !== 'win32') {
|
|
276
|
+
const macExtraPaths = '/usr/local/bin:/opt/homebrew/bin:/home/linuxbrew/.linuxbrew/bin';
|
|
277
|
+
const fullPath = `${process.env.PATH || '/usr/bin:/bin'}:${macExtraPaths}`;
|
|
278
|
+
args.push(envFlag, `PATH=${fullPath}`);
|
|
279
|
+
}
|
|
273
280
|
args.push(serverName, '--', 'npx', '-y', '@ppdocs/mcp@latest');
|
|
274
281
|
const result = spawnSync(cli, args, { stdio: 'inherit', shell: true });
|
|
275
282
|
if (result.status !== 0)
|
|
@@ -303,6 +310,24 @@ function autoRegisterMcp(cwd, apiUrl, user, skipGemini = false) {
|
|
|
303
310
|
console.log(`⚠️ Codex MCP registration failed`);
|
|
304
311
|
}
|
|
305
312
|
}
|
|
313
|
+
// OpenCode CLI (opencode mcp add 支持 -e 环境变量注入)
|
|
314
|
+
if (commandExists('opencode')) {
|
|
315
|
+
detected.push('OpenCode');
|
|
316
|
+
try {
|
|
317
|
+
execSilent(`opencode mcp remove ${serverName}`);
|
|
318
|
+
mcpAdd('opencode', '-e');
|
|
319
|
+
}
|
|
320
|
+
catch {
|
|
321
|
+
// fallback: 写入 ~/.opencode/mcp.json
|
|
322
|
+
try {
|
|
323
|
+
const opencodeConfig = path.join(os.homedir(), '.opencode', 'mcp.json');
|
|
324
|
+
createMcpConfigAt(opencodeConfig, apiUrl, { user, projectRoot: cwd });
|
|
325
|
+
}
|
|
326
|
+
catch {
|
|
327
|
+
console.log(`⚠️ OpenCode MCP registration failed`);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
306
331
|
// Gemini CLI (gemini mcp add 不支持 --env,直接写 settings.json)
|
|
307
332
|
if (commandExists('gemini') && !skipGemini) {
|
|
308
333
|
detected.push('Gemini');
|
|
@@ -315,7 +340,7 @@ function autoRegisterMcp(cwd, apiUrl, user, skipGemini = false) {
|
|
|
315
340
|
}
|
|
316
341
|
}
|
|
317
342
|
if (detected.length === 0) {
|
|
318
|
-
console.log(`ℹ️ No AI CLI detected (claude/codex/gemini), creating .mcp.json for manual config`);
|
|
343
|
+
console.log(`ℹ️ No AI CLI detected (claude/codex/opencode/gemini), creating .mcp.json for manual config`);
|
|
319
344
|
return false;
|
|
320
345
|
}
|
|
321
346
|
console.log(`✅ Registered MCP for: ${detected.join(', ')}`);
|
package/dist/index.js
CHANGED
|
@@ -19,6 +19,51 @@ import { loadConfig, generateAgentId } from './config.js';
|
|
|
19
19
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
20
20
|
const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf-8'));
|
|
21
21
|
const VERSION = pkg.version;
|
|
22
|
+
/** 启动时连通性检查 — 非阻塞,3秒超时,结果输出到 stderr 供调试 */
|
|
23
|
+
async function checkConnectivity(apiUrl) {
|
|
24
|
+
// Node.js 18+ 内置 fetch; 旧版本跳过检查
|
|
25
|
+
if (typeof globalThis.fetch !== 'function') {
|
|
26
|
+
console.error(`[connectivity] ⏭️ fetch unavailable (Node.js < 18), skipping connectivity check`);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const controller = new AbortController();
|
|
30
|
+
const timer = setTimeout(() => controller.abort(), 3000);
|
|
31
|
+
try {
|
|
32
|
+
const response = await fetch(apiUrl, { signal: controller.signal });
|
|
33
|
+
if (response.ok) {
|
|
34
|
+
console.error(`[connectivity] ✅ ppdocs server reachable`);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
console.error(`[connectivity] ⚠️ ppdocs server responded HTTP ${response.status} — check API key/project ID`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
const apiHost = apiUrl.replace(/\/api\/.*$/, '');
|
|
42
|
+
if (err instanceof Error && err.name === 'AbortError') {
|
|
43
|
+
console.error(`[connectivity] ❌ Connection TIMEOUT (3s) to ${apiHost}`);
|
|
44
|
+
console.error(`[connectivity] Possible causes:`);
|
|
45
|
+
console.error(`[connectivity] 1. ppdocs desktop app is not running on the target machine`);
|
|
46
|
+
console.error(`[connectivity] 2. Firewall blocking port (check Windows Firewall inbound rules)`);
|
|
47
|
+
console.error(`[connectivity] 3. IP address changed (re-run init with correct --api)`);
|
|
48
|
+
console.error(`[connectivity] 4. Not on the same network`);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
52
|
+
if (msg.includes('ECONNREFUSED')) {
|
|
53
|
+
console.error(`[connectivity] ❌ Connection REFUSED to ${apiHost}`);
|
|
54
|
+
console.error(`[connectivity] ppdocs desktop app is not running, or port is wrong`);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
console.error(`[connectivity] ❌ Cannot reach ${apiHost}: ${msg}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
console.error(`[connectivity] API URL: ${apiUrl}`);
|
|
61
|
+
console.error(`[connectivity] MCP will still start — tools will fail until server is reachable`);
|
|
62
|
+
}
|
|
63
|
+
finally {
|
|
64
|
+
clearTimeout(timer);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
22
67
|
// 检查是否为 CLI 命令
|
|
23
68
|
const args = process.argv.slice(2);
|
|
24
69
|
if (args.length > 0) {
|
|
@@ -32,7 +77,9 @@ async function main() {
|
|
|
32
77
|
// 有配置 → 自动初始化 (环境变量 / .ppdocs)
|
|
33
78
|
if (config) {
|
|
34
79
|
initClient(config.apiUrl);
|
|
35
|
-
console.error(`ppdocs MCP v${VERSION} | project: ${config.projectId} | user: ${config.user}`);
|
|
80
|
+
console.error(`ppdocs MCP v${VERSION} | project: ${config.projectId} | user: ${config.user} | source: ${config.source}`);
|
|
81
|
+
// 启动时连通性检查 (非阻塞, 3秒超时)
|
|
82
|
+
checkConnectivity(config.apiUrl).catch(() => { });
|
|
36
83
|
}
|
|
37
84
|
else {
|
|
38
85
|
console.error(`ppdocs MCP v${VERSION} | ⏳ 等待 kg_init 初始化项目上下文...`);
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* API URL 格式: http://localhost:20099/api/:projectId/:password/...
|
|
6
6
|
*/
|
|
7
|
-
import type { Task, TaskSummary, TaskLogType, TaskExperience, FileInfo, WorkflowSummary, WorkflowDoc, WorkflowSelector, Reference } from './types.js';
|
|
7
|
+
import type { Task, TaskSummary, TaskLogType, TaskExperience, FileInfo, WorkflowSummary, WorkflowDoc, WorkflowSelector, Reference, FetchResult, FileImportResult, Pitfall, PitfallSummary } from './types.js';
|
|
8
8
|
export declare class PpdocsApiClient {
|
|
9
9
|
private baseUrl;
|
|
10
10
|
private serverUrl;
|
|
@@ -31,6 +31,27 @@ export declare class PpdocsApiClient {
|
|
|
31
31
|
readReferenceFile(path: string): Promise<string>;
|
|
32
32
|
/** 复制本地文件到参考文件库, 返回相对路径列表 */
|
|
33
33
|
copyReferenceFiles(paths: string[], targetDir?: string): Promise<string[]>;
|
|
34
|
+
/** 从 URL 拉取文档内容并保存为参考 */
|
|
35
|
+
fetchRefUrl(url: string, refId?: string): Promise<FetchResult>;
|
|
36
|
+
/** 导入本地文件内容到参考系统 */
|
|
37
|
+
importLocalFile(refId: string, sourcePath: string): Promise<FileImportResult>;
|
|
38
|
+
listPitfalls(): Promise<PitfallSummary[]>;
|
|
39
|
+
getPitfall(pitfallId: string): Promise<Pitfall | null>;
|
|
40
|
+
createPitfall(input: {
|
|
41
|
+
title: string;
|
|
42
|
+
category?: string;
|
|
43
|
+
symptom?: string;
|
|
44
|
+
root_cause?: string;
|
|
45
|
+
solution?: string;
|
|
46
|
+
prevention?: string;
|
|
47
|
+
severity?: string;
|
|
48
|
+
related_nodes?: string[];
|
|
49
|
+
source_task?: string;
|
|
50
|
+
tags?: string[];
|
|
51
|
+
}): Promise<Pitfall>;
|
|
52
|
+
savePitfall(pitfall: Pitfall): Promise<boolean>;
|
|
53
|
+
deletePitfall(pitfallId: string): Promise<boolean>;
|
|
54
|
+
searchPitfalls(query: string, status?: string, category?: string): Promise<PitfallSummary[]>;
|
|
34
55
|
listTasks(status?: 'active' | 'archived'): Promise<TaskSummary[]>;
|
|
35
56
|
getTask(taskId: string, mode?: 'smart' | 'full'): Promise<Task | null>;
|
|
36
57
|
createTask(task: {
|
|
@@ -168,6 +168,56 @@ export class PpdocsApiClient {
|
|
|
168
168
|
body: JSON.stringify({ paths, target_dir: targetDir }),
|
|
169
169
|
});
|
|
170
170
|
}
|
|
171
|
+
/** 从 URL 拉取文档内容并保存为参考 */
|
|
172
|
+
async fetchRefUrl(url, refId) {
|
|
173
|
+
return this.request('/refs/fetch-url', {
|
|
174
|
+
method: 'POST',
|
|
175
|
+
body: JSON.stringify({ url, ref_id: refId }),
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
/** 导入本地文件内容到参考系统 */
|
|
179
|
+
async importLocalFile(refId, sourcePath) {
|
|
180
|
+
return this.request('/refs/import-file', {
|
|
181
|
+
method: 'POST',
|
|
182
|
+
body: JSON.stringify({ ref_id: refId, source_path: sourcePath }),
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
// ============ 踩坑经验 API ============
|
|
186
|
+
async listPitfalls() {
|
|
187
|
+
return this.request('/pitfalls');
|
|
188
|
+
}
|
|
189
|
+
async getPitfall(pitfallId) {
|
|
190
|
+
try {
|
|
191
|
+
return await this.request(`/pitfalls/${encodeURIComponent(pitfallId)}`);
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
async createPitfall(input) {
|
|
198
|
+
return this.request('/pitfalls', {
|
|
199
|
+
method: 'POST',
|
|
200
|
+
body: JSON.stringify(input),
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
async savePitfall(pitfall) {
|
|
204
|
+
await this.request(`/pitfalls/${encodeURIComponent(pitfall.id)}`, {
|
|
205
|
+
method: 'PUT',
|
|
206
|
+
body: JSON.stringify(pitfall),
|
|
207
|
+
});
|
|
208
|
+
return true;
|
|
209
|
+
}
|
|
210
|
+
async deletePitfall(pitfallId) {
|
|
211
|
+
return this.request(`/pitfalls/${encodeURIComponent(pitfallId)}`, {
|
|
212
|
+
method: 'DELETE',
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
async searchPitfalls(query, status, category) {
|
|
216
|
+
return this.request('/pitfalls/search', {
|
|
217
|
+
method: 'POST',
|
|
218
|
+
body: JSON.stringify({ query, status, category }),
|
|
219
|
+
});
|
|
220
|
+
}
|
|
171
221
|
// ============ 任务管理 ============
|
|
172
222
|
async listTasks(status) {
|
|
173
223
|
const query = status ? `?status=${status}` : '';
|
package/dist/storage/types.d.ts
CHANGED
|
@@ -45,6 +45,41 @@ export interface Reference {
|
|
|
45
45
|
adoptedBy: AdoptedNode[];
|
|
46
46
|
createdAt: string;
|
|
47
47
|
updatedAt: string;
|
|
48
|
+
sourceUrl?: string;
|
|
49
|
+
fetchHistory?: FetchRecord[];
|
|
50
|
+
fileImportHistory?: FileImportRecord[];
|
|
51
|
+
}
|
|
52
|
+
export interface FetchRecord {
|
|
53
|
+
fetchedAt: string;
|
|
54
|
+
url: string;
|
|
55
|
+
title: string;
|
|
56
|
+
contentFile: string;
|
|
57
|
+
contentLength: number;
|
|
58
|
+
contentPreview: string;
|
|
59
|
+
}
|
|
60
|
+
export interface FetchResult {
|
|
61
|
+
refId: string;
|
|
62
|
+
title: string;
|
|
63
|
+
contentFile: string;
|
|
64
|
+
contentLength: number;
|
|
65
|
+
contentPreview: string;
|
|
66
|
+
fetchCount: number;
|
|
67
|
+
}
|
|
68
|
+
export interface FileImportRecord {
|
|
69
|
+
importedAt: string;
|
|
70
|
+
sourcePath: string;
|
|
71
|
+
storedFile: string;
|
|
72
|
+
contentLength: number;
|
|
73
|
+
contentPreview: string;
|
|
74
|
+
fileType: string;
|
|
75
|
+
}
|
|
76
|
+
export interface FileImportResult {
|
|
77
|
+
refId: string;
|
|
78
|
+
sourcePath: string;
|
|
79
|
+
storedFile: string;
|
|
80
|
+
contentLength: number;
|
|
81
|
+
contentPreview: string;
|
|
82
|
+
importCount: number;
|
|
48
83
|
}
|
|
49
84
|
export interface FileInfo {
|
|
50
85
|
name: string;
|
|
@@ -95,3 +130,30 @@ export interface TaskSummary {
|
|
|
95
130
|
updated_at: string;
|
|
96
131
|
last_log?: string;
|
|
97
132
|
}
|
|
133
|
+
export interface Pitfall {
|
|
134
|
+
id: string;
|
|
135
|
+
title: string;
|
|
136
|
+
category: string;
|
|
137
|
+
symptom: string;
|
|
138
|
+
root_cause: string;
|
|
139
|
+
solution: string;
|
|
140
|
+
prevention: string;
|
|
141
|
+
related_nodes: string[];
|
|
142
|
+
source_task?: string;
|
|
143
|
+
severity: string;
|
|
144
|
+
status: string;
|
|
145
|
+
tags: string[];
|
|
146
|
+
created_at: string;
|
|
147
|
+
updated_at: string;
|
|
148
|
+
resolved_at?: string;
|
|
149
|
+
}
|
|
150
|
+
export interface PitfallSummary {
|
|
151
|
+
id: string;
|
|
152
|
+
title: string;
|
|
153
|
+
category: string;
|
|
154
|
+
severity: string;
|
|
155
|
+
status: string;
|
|
156
|
+
tags: string[];
|
|
157
|
+
created_at: string;
|
|
158
|
+
updated_at: string;
|
|
159
|
+
}
|
package/dist/tools/analyzer.d.ts
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 代码分析引擎工具
|
|
2
|
+
* 代码分析引擎工具
|
|
3
3
|
* code_scan, code_smart_context, code_full_path
|
|
4
|
-
*
|
|
5
|
-
* code_smart_context: 代码+KG文档/工作流全关联 (含影响范围)
|
|
6
|
-
* code_full_path: 两点间代码链路+共享KG文档
|
|
7
4
|
*/
|
|
8
5
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
9
6
|
import { type McpContext } from './shared.js';
|
package/dist/tools/analyzer.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 代码分析引擎工具
|
|
2
|
+
* 代码分析引擎工具
|
|
3
3
|
* code_scan, code_smart_context, code_full_path
|
|
4
|
-
*
|
|
5
|
-
* code_smart_context: 代码+KG文档/工作流全关联 (含影响范围)
|
|
6
|
-
* code_full_path: 两点间代码链路+共享KG文档
|
|
7
4
|
*/
|
|
8
5
|
import { z } from 'zod';
|
|
9
6
|
import { getClient } from '../storage/httpClient.js';
|
|
@@ -17,7 +14,7 @@ const SYMBOL_ICONS = {
|
|
|
17
14
|
export function registerAnalyzerTools(server, ctx) {
|
|
18
15
|
const client = () => getClient();
|
|
19
16
|
// ===== code_scan: 扫描项目代码 =====
|
|
20
|
-
server.tool('code_scan', '
|
|
17
|
+
server.tool('code_scan', '扫描项目代码并构建索引。返回文件数、符号数、语言统计。首次使用 code_smart_context/code_full_path 前需先执行', {
|
|
21
18
|
projectPath: z.string().optional().describe('项目源码的绝对路径(如"D:/projects/myapp")。不传则自动从Beacon同步目录或项目配置解析'),
|
|
22
19
|
force: z.boolean().optional().describe('是否强制全量重建(默认false, 增量更新)'),
|
|
23
20
|
}, async (args) => safeTool(async () => {
|
|
@@ -33,7 +30,7 @@ export function registerAnalyzerTools(server, ctx) {
|
|
|
33
30
|
].join('\n'));
|
|
34
31
|
}));
|
|
35
32
|
// ===== code_smart_context: 代码+文档全关联上下文 =====
|
|
36
|
-
server.tool('code_smart_context', '
|
|
33
|
+
server.tool('code_smart_context', '代码+文档全关联上下文。输入函数名,返回代码依赖、关联文档、匹配工作流、活跃任务、影响范围。需先运行 code_scan', {
|
|
37
34
|
projectPath: z.string().optional().describe('项目源码的绝对路径(不传则自动解析)'),
|
|
38
35
|
symbolName: z.string().describe('要查询的符号名称(如"handleLogin", "AuthService")'),
|
|
39
36
|
}, async (args) => safeTool(async () => {
|
|
@@ -94,7 +91,7 @@ export function registerAnalyzerTools(server, ctx) {
|
|
|
94
91
|
return wrap(lines.join('\n'));
|
|
95
92
|
}));
|
|
96
93
|
// ===== code_full_path: 全关联路径 =====
|
|
97
|
-
server.tool('code_full_path', '
|
|
94
|
+
server.tool('code_full_path', '全关联路径。查找两个符号之间的代码引用链路、共享KG文档、共同导入。需先运行 code_scan', {
|
|
98
95
|
projectPath: z.string().optional().describe('项目源码的绝对路径(不传则自动解析)'),
|
|
99
96
|
symbolA: z.string().describe('起点符号名(如 "handleLogin")'),
|
|
100
97
|
symbolB: z.string().describe('终点符号名(如 "AuthService")'),
|
package/dist/tools/flowchart.js
CHANGED
|
@@ -317,9 +317,7 @@ function findDirectedPath(chart, fromId, toId) {
|
|
|
317
317
|
}
|
|
318
318
|
export function registerFlowchartTools(server, _ctx) {
|
|
319
319
|
const client = () => getClient();
|
|
320
|
-
server.tool('kg_flowchart', '
|
|
321
|
-
'⚡ 开始任何任务前必须先查图谱:search 搜关键词 → get_node 看详情 → 有 subFlowchart 则递归下探。\n' +
|
|
322
|
-
'📝 完成修改后必须回写:bind 绑定文件 → update_node 更新描述和文档 → 新模块用 batch_add。\n' +
|
|
320
|
+
server.tool('kg_flowchart', '知识图谱核心。查询/更新流程图节点、关系、绑定文件和内嵌文档。' +
|
|
323
321
|
'actions: list|get|search|get_relations|find_path|get_node|update_node|delete_node|batch_add|bind|unbind|orphans|health|create_chart|delete_chart', {
|
|
324
322
|
action: z
|
|
325
323
|
.enum(['list', 'get', 'search', 'get_relations', 'find_path', 'get_node', 'update_node', 'delete_node', 'batch_add', 'bind', 'unbind', 'orphans', 'health', 'create_chart', 'delete_chart'])
|
package/dist/tools/index.d.ts
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MCP 工具注册入口
|
|
3
|
-
*
|
|
3
|
+
* 7 个工具, 6 个子模块
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* 🏛️ 协作: kg_meeting (1个)
|
|
5
|
+
* kg_init — 项目初始化
|
|
6
|
+
* kg_status — 仪表盘
|
|
7
|
+
* kg_flowchart — 知识图谱核心
|
|
8
|
+
* kg_workflow — AI 工作流
|
|
9
|
+
* kg_task — 任务管理
|
|
10
|
+
* kg_ref — 外部参考 (fetch/list/get/delete)
|
|
11
|
+
* code_scan/code_smart_context/code_full_path — 代码分析 (可选)
|
|
13
12
|
*/
|
|
14
13
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
15
14
|
export declare function registerTools(server: McpServer, projectId: string, user: string, agentId: string, onProjectChange?: (newProjectId: string, newApiUrl: string) => void): void;
|
package/dist/tools/index.js
CHANGED
|
@@ -1,49 +1,30 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MCP 工具注册入口
|
|
3
|
-
*
|
|
3
|
+
* 7 个工具, 6 个子模块
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* 🏛️ 协作: kg_meeting (1个)
|
|
5
|
+
* kg_init — 项目初始化
|
|
6
|
+
* kg_status — 仪表盘
|
|
7
|
+
* kg_flowchart — 知识图谱核心
|
|
8
|
+
* kg_workflow — AI 工作流
|
|
9
|
+
* kg_task — 任务管理
|
|
10
|
+
* kg_ref — 外部参考 (fetch/list/get/delete)
|
|
11
|
+
* code_scan/code_smart_context/code_full_path — 代码分析 (可选)
|
|
13
12
|
*/
|
|
14
13
|
import { createContext } from './shared.js';
|
|
15
14
|
import { registerInitTool } from './init.js';
|
|
16
15
|
import { registerStatusTool } from './kg_status.js';
|
|
17
|
-
import { registerProjectTools } from './projects.js';
|
|
18
16
|
import { registerWorkflowTools } from './workflow.js';
|
|
19
17
|
import { registerTaskTools } from './tasks.js';
|
|
20
|
-
import { registerFileTools } from './files.js';
|
|
21
|
-
import { registerDiscussionTools } from './discussion.js';
|
|
22
18
|
import { registerReferenceTools } from './refs.js';
|
|
23
19
|
import { registerAnalyzerTools } from './analyzer.js';
|
|
24
|
-
import { registerMeetingTools } from './meeting.js';
|
|
25
20
|
import { registerFlowchartTools } from './flowchart.js';
|
|
26
|
-
import { registerDocQueryTools } from './doc_query.js';
|
|
27
21
|
export function registerTools(server, projectId, user, agentId, onProjectChange) {
|
|
28
22
|
const ctx = createContext(projectId, user, agentId);
|
|
29
|
-
// 🔗 初始化
|
|
30
23
|
registerInitTool(server, ctx, onProjectChange || (() => { }));
|
|
31
|
-
// 📊 导航
|
|
32
24
|
registerStatusTool(server, ctx);
|
|
33
|
-
// 📚 知识
|
|
34
|
-
registerProjectTools(server, ctx);
|
|
35
25
|
registerWorkflowTools(server, ctx);
|
|
36
|
-
// 📝 工作流
|
|
37
26
|
registerTaskTools(server, ctx);
|
|
38
|
-
registerFileTools(server);
|
|
39
|
-
registerDiscussionTools(server, ctx);
|
|
40
27
|
registerReferenceTools(server);
|
|
41
|
-
// 🔬 代码分析
|
|
42
28
|
registerAnalyzerTools(server, ctx);
|
|
43
|
-
// 🏛️ 多AI协作
|
|
44
|
-
registerMeetingTools(server, ctx);
|
|
45
|
-
// 🔀 流程图
|
|
46
29
|
registerFlowchartTools(server, ctx);
|
|
47
|
-
// 📘 文档查询
|
|
48
|
-
registerDocQueryTools(server, ctx);
|
|
49
30
|
}
|
package/dist/tools/init.js
CHANGED
|
@@ -49,7 +49,7 @@ function readPpdocsFrom(dir) {
|
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
export function registerInitTool(server, ctx, onProjectChange) {
|
|
52
|
-
server.tool('kg_init', '
|
|
52
|
+
server.tool('kg_init', '项目上下文初始化。读取指定目录的 .ppdocs 配置,切换 MCP 连接到对应项目。首次对话必须调用。不传 projectPath 则使用当前工作目录', {
|
|
53
53
|
projectPath: z.string().optional().describe('项目根目录的绝对路径(含 .ppdocs 文件),不传则使用 cwd'),
|
|
54
54
|
}, async ({ projectPath }) => safeTool(async () => {
|
|
55
55
|
const targetDir = projectPath || process.cwd();
|
package/dist/tools/kg_status.js
CHANGED
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* kg_status — 项目速览仪表盘
|
|
3
3
|
* 一次调用返回项目全貌:摘要、核心模块、活跃任务、快速导航
|
|
4
4
|
*/
|
|
5
5
|
import { getClient } from '../storage/httpClient.js';
|
|
6
6
|
import { wrap, safeTool } from './shared.js';
|
|
7
7
|
export function registerStatusTool(server, ctx) {
|
|
8
8
|
const client = () => getClient();
|
|
9
|
-
server.tool('kg_status', '
|
|
10
|
-
const [charts, activeTasks,
|
|
9
|
+
server.tool('kg_status', '项目速览仪表盘。返回流程图节点数、活跃任务数、最近变更。每次对话开始建议首先调用', {}, async () => safeTool(async () => {
|
|
10
|
+
const [charts, activeTasks, mainChart] = await Promise.all([
|
|
11
11
|
client().listFlowcharts(),
|
|
12
12
|
client().listTasks('active'),
|
|
13
|
-
client().discussionList().catch(() => []),
|
|
14
13
|
client().getFlowchart('main').catch(() => null),
|
|
15
14
|
]);
|
|
16
15
|
const nodeCount = charts.reduce((sum, c) => sum + (c.nodeCount || 0), 0);
|
|
17
|
-
const activeDiscussions = discussions.filter((d) => d.status === 'active');
|
|
18
16
|
const lines = [
|
|
19
17
|
`# 项目速览 [${ctx.projectId}]`,
|
|
20
18
|
`身份: ${ctx.user}:${ctx.agentId}`,
|
|
@@ -42,7 +40,7 @@ export function registerStatusTool(server, ctx) {
|
|
|
42
40
|
}
|
|
43
41
|
}
|
|
44
42
|
// --- 当前状态 ---
|
|
45
|
-
lines.push('', '## 当前状态', `- 流程图: ${charts.length} 张 | 节点: ${nodeCount} 个`, `- 活跃任务: ${activeTasks.length}
|
|
43
|
+
lines.push('', '## 当前状态', `- 流程图: ${charts.length} 张 | 节点: ${nodeCount} 个`, `- 活跃任务: ${activeTasks.length} 个`);
|
|
46
44
|
if (activeTasks.length > 0) {
|
|
47
45
|
lines.push('', '### 进行中的任务');
|
|
48
46
|
for (const t of activeTasks.slice(0, 5)) {
|