@ppdocs/mcp 3.2.17 → 3.2.19

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/dist/cli.d.ts CHANGED
@@ -4,4 +4,4 @@
4
4
  */
5
5
  export declare function runCli(args: string[]): Promise<boolean>;
6
6
  /** 安装项目模板文件 (供授权后自动配置调用) */
7
- export declare function setupProjectFiles(cwd: string, apiUrl: string): void;
7
+ export declare function setupProjectFiles(cwd: string, apiUrl: string, user?: string): void;
package/dist/cli.js CHANGED
@@ -89,10 +89,12 @@ function showHelp() {
89
89
  ppdocs MCP CLI
90
90
 
91
91
  Commands:
92
- init Initialize ppdocs config + install workflow templates
92
+ init Full setup: .ppdocs + templates + MCP registration
93
+ bind Lightweight: only create .ppdocs (for adding projects to existing MCP)
93
94
 
94
95
  Usage:
95
96
  npx @ppdocs/mcp init -p <projectId> -k <key> [options]
97
+ npx @ppdocs/mcp bind -p <projectId> -k <key> [options]
96
98
 
97
99
  Options:
98
100
  -p, --project Project ID (required)
@@ -105,51 +107,55 @@ Options:
105
107
  --sync <id> Sync knowledge base docs from a source project to ./docs/ppdocs/
106
108
 
107
109
  Example:
108
- npx @ppdocs/mcp init -p myproject -k abc123xyz
109
- npx @ppdocs/mcp init -p myproject -k abc123xyz --codex
110
- npx @ppdocs/mcp init -p myproject -k abc123xyz --from _templates
111
- npx @ppdocs/mcp init -p myproject -k abc123xyz --sync shared-rules
110
+ npx @ppdocs/mcp init -p myproject -k abc123xyz --api 192.168.1.100
111
+ npx @ppdocs/mcp bind -p myproject -k abc123xyz --api 192.168.1.100
112
112
  `);
113
113
  }
114
114
  export async function runCli(args) {
115
115
  const cmd = args[0];
116
- if (cmd === 'init') {
116
+ if (cmd === 'init' || cmd === 'bind') {
117
117
  const opts = parseArgs(args.slice(1));
118
118
  if (!opts) {
119
119
  console.error('Error: -p (project) and -k (key) are required\n');
120
120
  showHelp();
121
121
  process.exit(1);
122
122
  }
123
- await initProject(opts);
123
+ if (cmd === 'bind') {
124
+ bindProject(opts);
125
+ }
126
+ else {
127
+ await initProject(opts);
128
+ }
124
129
  return true;
125
130
  }
126
131
  if (cmd === '--help' || cmd === '-h' || cmd === 'help') {
127
132
  showHelp();
128
133
  return true;
129
134
  }
130
- return false; // Not a CLI command, run as MCP server
135
+ return false;
131
136
  }
132
- async function initProject(opts) {
133
- const cwd = process.cwd();
137
+ /** 轻量绑定: 仅创建 .ppdocs, 不注册 MCP 不安装模板 */
138
+ function bindProject(opts) {
139
+ writePpdocsConfig(process.cwd(), opts);
140
+ console.log(`\n🔗 Project bound: ${opts.project}\n AI will auto-connect via kg_init when opening this directory.\n`);
141
+ }
142
+ /** 写入 .ppdocs 配置文件 (init + bind 复用) */
143
+ function writePpdocsConfig(cwd, opts) {
134
144
  const apiUrl = `http://${opts.api}:${opts.port}/api/${opts.project}/${opts.key}`;
135
- // Create .ppdocs config
136
- const ppdocsConfig = {
137
- api: `http://${opts.api}:${opts.port}`,
138
- projectId: opts.project,
139
- key: opts.key,
140
- user: opts.user,
141
- };
142
145
  const ppdocsPath = path.join(cwd, '.ppdocs');
143
- // 检查是否存在同名目录,如果是则删除
144
- if (fs.existsSync(ppdocsPath)) {
145
- const stat = fs.statSync(ppdocsPath);
146
- if (stat.isDirectory()) {
147
- fs.rmSync(ppdocsPath, { recursive: true });
148
- console.log(`⚠️ Removed existing .ppdocs directory`);
149
- }
146
+ if (fs.existsSync(ppdocsPath) && fs.statSync(ppdocsPath).isDirectory()) {
147
+ fs.rmSync(ppdocsPath, { recursive: true });
148
+ console.log(`⚠️ Removed existing .ppdocs directory`);
150
149
  }
151
- fs.writeFileSync(ppdocsPath, JSON.stringify(ppdocsConfig, null, 2));
150
+ fs.writeFileSync(ppdocsPath, JSON.stringify({
151
+ api: `http://${opts.api}:${opts.port}`, projectId: opts.project, key: opts.key, user: opts.user,
152
+ }, null, 2));
152
153
  console.log(`✅ Created ${ppdocsPath}`);
154
+ return apiUrl;
155
+ }
156
+ async function initProject(opts) {
157
+ const cwd = process.cwd();
158
+ const apiUrl = writePpdocsConfig(cwd, opts);
153
159
  // Install workflow templates based on IDE detection
154
160
  const detectedIdes = detectIDEs(cwd);
155
161
  let hasIdeDir = false;
@@ -158,15 +164,15 @@ async function initProject(opts) {
158
164
  hasIdeDir = true;
159
165
  }
160
166
  if (detectedIdes.includes('cursor')) {
161
- installCursorTemplates(cwd, apiUrl);
167
+ installCursorTemplates(cwd, apiUrl, opts.user);
162
168
  hasIdeDir = true;
163
169
  }
164
170
  if (detectedIdes.includes('antigravity')) {
165
- installAntigravityTemplates(cwd, apiUrl);
171
+ installAntigravityTemplates(cwd, apiUrl, opts.user);
166
172
  hasIdeDir = true;
167
173
  }
168
174
  if (detectedIdes.includes('kiro')) {
169
- installKiroTemplates(cwd, apiUrl);
175
+ installKiroTemplates(cwd, apiUrl, opts.user);
170
176
  hasIdeDir = true;
171
177
  }
172
178
  // Fallback behavior: if no specific IDE config directories found
@@ -179,10 +185,10 @@ async function initProject(opts) {
179
185
  }
180
186
  }
181
187
  // 自动检测并注册 MCP (如果已写入 Antigravity 配置,跳过 gemini CLI 注册避免冲突)
182
- const registered = autoRegisterMcp(apiUrl, opts.user, detectedIdes.includes('antigravity'));
188
+ const registered = autoRegisterMcp(detectedIdes.includes('antigravity'));
183
189
  // 如果没有检测到任何 AI CLI,并且也没有检测到配置文件夹,创建 .mcp.json 作为备用
184
190
  if (!registered && !hasIdeDir) {
185
- createMcpJson(cwd, apiUrl);
191
+ createMcpJson(cwd, apiUrl, opts.user);
186
192
  }
187
193
  // --from: 从模板项目拉取 IDE 配置文件
188
194
  if (opts.from) {
@@ -276,61 +282,53 @@ function execSilent(cmd) {
276
282
  }
277
283
  catch { /* ignore */ }
278
284
  }
279
- /** 自动检测 AI CLI 并注册 MCP */
280
- function autoRegisterMcp(apiUrl, user, skipGemini = false) {
285
+ /** 自动检测 AI CLI 并注册全局 MCP (不注入 env,支持多项目通过 kg_init 切换) */
286
+ function autoRegisterMcp(skipGemini = false) {
281
287
  const detected = [];
282
288
  const serverName = 'ppdocs-kg';
283
- // 检测 Claude CLI (不传环境变量,MCP启动时读取.ppdocs)
289
+ const addCmd = `-- npx -y @ppdocs/mcp@latest`;
290
+ // Claude CLI (幂等:已注册则跳过)
284
291
  if (commandExists('claude')) {
285
292
  detected.push('Claude');
286
293
  try {
287
- console.log(`✅ Detected Claude CLI, registering MCP...`);
288
- // 先检查是否已存在
289
- const checkResult = execSync(`claude mcp list`, { encoding: 'utf-8' });
290
- if (checkResult.includes(serverName)) {
294
+ const list = execSync(`claude mcp list`, { encoding: 'utf-8' });
295
+ if (list.includes(serverName)) {
291
296
  console.log(`✅ Claude MCP already configured`);
292
297
  }
293
298
  else {
294
- const cmd = `claude mcp add ${serverName} -- npx -y @ppdocs/mcp@latest`;
295
- execSync(cmd, { stdio: 'inherit' });
299
+ execSync(`claude mcp add ${serverName} ${addCmd}`, { stdio: 'inherit' });
296
300
  }
297
301
  }
298
- catch (e) {
299
- // 如果 list 失败,尝试添加
302
+ catch {
300
303
  try {
301
304
  execSilent(`claude mcp remove ${serverName}`);
302
- const cmd = `claude mcp add ${serverName} -- npx -y @ppdocs/mcp@latest`;
303
- execSync(cmd, { stdio: 'inherit' });
305
+ execSync(`claude mcp add ${serverName} ${addCmd}`, { stdio: 'inherit' });
304
306
  }
305
307
  catch {
306
308
  console.log(`⚠️ Claude MCP registration failed`);
307
309
  }
308
310
  }
309
311
  }
310
- // 检测 Codex CLI (OpenAI)
312
+ // Codex CLI
311
313
  if (commandExists('codex')) {
312
314
  detected.push('Codex');
313
315
  try {
314
- console.log(`✅ Detected Codex CLI, registering MCP...`);
315
316
  execSilent(`codex mcp remove ${serverName}`);
316
- const cmd = `codex mcp add ${serverName} -- npx -y @ppdocs/mcp@latest`;
317
- execSync(cmd, { stdio: 'inherit' });
317
+ execSync(`codex mcp add ${serverName} ${addCmd}`, { stdio: 'inherit' });
318
318
  }
319
- catch (e) {
320
- console.log(`⚠️ Codex MCP registration failed: ${e}`);
319
+ catch {
320
+ console.log(`⚠️ Codex MCP registration failed`);
321
321
  }
322
322
  }
323
- // 检测 Gemini CLI
323
+ // Gemini CLI
324
324
  if (commandExists('gemini') && !skipGemini) {
325
325
  detected.push('Gemini');
326
326
  try {
327
- console.log(`✅ Detected Gemini CLI, registering MCP...`);
328
327
  execSilent(`gemini mcp remove ${serverName}`);
329
- const cmd = `gemini mcp add ${serverName} "npx -y @ppdocs/mcp@latest"`;
330
- execSync(cmd, { stdio: 'inherit' });
328
+ execSync(`gemini mcp add ${serverName} "npx -y @ppdocs/mcp@latest"`, { stdio: 'inherit' });
331
329
  }
332
- catch (e) {
333
- console.log(`⚠️ Gemini MCP registration failed: ${e}`);
330
+ catch {
331
+ console.log(`⚠️ Gemini MCP registration failed`);
334
332
  }
335
333
  }
336
334
  if (detected.length === 0) {
@@ -340,34 +338,33 @@ function autoRegisterMcp(apiUrl, user, skipGemini = false) {
340
338
  console.log(`✅ Registered MCP for: ${detected.join(', ')}`);
341
339
  return true;
342
340
  }
343
- /** 在指定路径创建或更新 mcp.json 配置 (不传 PPDOCS_API_URL,依赖 cwd/.ppdocs 文件) */
344
- function createMcpConfigAt(mcpPath, _apiUrl, _options) {
341
+ /** 在指定路径创建或更新 mcp.json 配置,注入 PPDOCS_API_URL 环境变量实现启动即就绪 */
342
+ function createMcpConfigAt(mcpPath, apiUrl, options) {
345
343
  let mcpConfig = {};
346
344
  if (fs.existsSync(mcpPath)) {
347
345
  try {
348
346
  mcpConfig = JSON.parse(fs.readFileSync(mcpPath, 'utf-8'));
349
347
  }
350
348
  catch {
351
- // 解析失败时中止,避免清空已有配置
352
349
  console.log(`⚠️ ${mcpPath} JSON格式无效,跳过MCP配置写入(请手动修复后重试)`);
353
350
  return;
354
351
  }
355
352
  }
356
- // Windows 需要 cmd /c 包装才能执行 npx
357
353
  const isWindows = process.platform === 'win32';
358
- // 对于 Mac/Linux,IDE 可能没有用户的完整 PATH,导致找不到 npx
359
354
  const macExtraPaths = '/usr/local/bin:/opt/homebrew/bin:/home/linuxbrew/.linuxbrew/bin';
360
355
  const actualPath = `${process.env.PATH || '/usr/bin:/bin'}:${macExtraPaths}`;
356
+ // 构建 env: 非 Windows 补 PATH + 注入项目绑定变量
357
+ const env = {};
358
+ if (!isWindows)
359
+ env.PATH = actualPath;
360
+ if (!options?.noEnv) {
361
+ env.PPDOCS_API_URL = apiUrl;
362
+ if (options?.user)
363
+ env.PPDOCS_USER = options.user;
364
+ }
361
365
  const ppdocsServer = isWindows
362
- ? {
363
- command: 'cmd',
364
- args: ['/c', 'npx', '-y', '@ppdocs/mcp@latest'],
365
- }
366
- : {
367
- command: 'npx',
368
- args: ['-y', '@ppdocs/mcp@latest'],
369
- env: { "PATH": actualPath }
370
- };
366
+ ? { command: 'cmd', args: ['/c', 'npx', '-y', '@ppdocs/mcp@latest'], ...(Object.keys(env).length > 0 && { env }) }
367
+ : { command: 'npx', args: ['-y', '@ppdocs/mcp@latest'], env };
371
368
  mcpConfig.mcpServers = {
372
369
  ...(mcpConfig.mcpServers || {}),
373
370
  "ppdocs-kg": ppdocsServer,
@@ -381,8 +378,8 @@ function createMcpConfigAt(mcpPath, _apiUrl, _options) {
381
378
  console.log(`✅ Configured MCP in ${mcpPath}`);
382
379
  }
383
380
  /** 创建 .mcp.json (手动配置备用) */
384
- function createMcpJson(cwd, apiUrl) {
385
- createMcpConfigAt(path.join(cwd, '.mcp.json'), apiUrl);
381
+ function createMcpJson(cwd, apiUrl, user) {
382
+ createMcpConfigAt(path.join(cwd, '.mcp.json'), apiUrl, { user });
386
383
  }
387
384
  /** 递归复制目录 */
388
385
  function copyDirRecursive(src, dest) {
@@ -505,9 +502,8 @@ function generateAgentsMd(cwd) {
505
502
  }
506
503
  }
507
504
  /** 安装 Cursor 模板 */
508
- function installCursorTemplates(cwd, apiUrl) {
509
- // 1. 生成 Cursor MCP 配置
510
- createMcpConfigAt(path.join(cwd, '.cursor', 'mcp.json'), apiUrl);
505
+ function installCursorTemplates(cwd, apiUrl, user) {
506
+ createMcpConfigAt(path.join(cwd, '.cursor', 'mcp.json'), apiUrl, { user });
511
507
  // 2. 生成 .cursorrules 提示词
512
508
  const srcRules = path.join(TEMPLATES_DIR, 'cursorrules.md');
513
509
  const destRules = path.join(cwd, '.cursorrules');
@@ -517,9 +513,9 @@ function installCursorTemplates(cwd, apiUrl) {
517
513
  }
518
514
  }
519
515
  /** 安装 Antigravity (Gemini IDE) 模板 */
520
- function installAntigravityTemplates(cwd, apiUrl) {
521
- // 1. 填充 .gemini/settings.json (noEnv: 依赖 .ppdocs 文件,不传 PPDOCS_API_URL 避免覆盖)
522
- createMcpConfigAt(path.join(cwd, '.gemini', 'settings.json'), apiUrl, { noEnv: true });
516
+ function installAntigravityTemplates(cwd, apiUrl, user) {
517
+ // Antigravity gemini CLI 注册 env,文件配置不注入避免冲突
518
+ createMcpConfigAt(path.join(cwd, '.gemini', 'settings.json'), apiUrl, { noEnv: true, user });
523
519
  // 2. 生成 AGENTS.md
524
520
  generateAgentsMd(cwd);
525
521
  // 3. 安装斜杠命令 → 全局目录 ~/.gemini/antigravity/global_workflows/
@@ -575,9 +571,8 @@ function installAntigravityTemplates(cwd, apiUrl) {
575
571
  }
576
572
  }
577
573
  /** 安装 Kiro 模板 */
578
- function installKiroTemplates(cwd, apiUrl) {
579
- // 1. 生成 Kiro MCP 配置
580
- createMcpConfigAt(path.join(cwd, '.kiro', 'settings', 'mcp.json'), apiUrl);
574
+ function installKiroTemplates(cwd, apiUrl, user) {
575
+ createMcpConfigAt(path.join(cwd, '.kiro', 'settings', 'mcp.json'), apiUrl, { user });
581
576
  // 2. 生成 Kiro Agent 规则
582
577
  const kiroRulesDir = path.join(cwd, '.kiro', 'rules');
583
578
  if (!fs.existsSync(kiroRulesDir)) {
@@ -604,21 +599,20 @@ function detectIDEs(cwd) {
604
599
  return ides;
605
600
  }
606
601
  /** 安装项目模板文件 (供授权后自动配置调用) */
607
- export function setupProjectFiles(cwd, apiUrl) {
602
+ export function setupProjectFiles(cwd, apiUrl, user) {
608
603
  const detectedIdes = detectIDEs(cwd);
609
604
  if (detectedIdes.includes('antigravity')) {
610
- installAntigravityTemplates(cwd, apiUrl);
605
+ installAntigravityTemplates(cwd, apiUrl, user);
611
606
  }
612
607
  if (detectedIdes.includes('cursor')) {
613
- installCursorTemplates(cwd, apiUrl);
608
+ installCursorTemplates(cwd, apiUrl, user);
614
609
  }
615
610
  if (detectedIdes.includes('kiro')) {
616
- installKiroTemplates(cwd, apiUrl);
611
+ installKiroTemplates(cwd, apiUrl, user);
617
612
  }
618
613
  if (detectedIdes.includes('claude')) {
619
614
  installClaudeTemplates(cwd);
620
615
  }
621
- // 如果没检测到任何 IDE,默认安装 Claude 模板
622
616
  if (detectedIdes.length === 0) {
623
617
  installClaudeTemplates(cwd);
624
618
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ppdocs/mcp",
3
- "version": "3.2.17",
3
+ "version": "3.2.19",
4
4
  "description": "ppdocs MCP Server - Knowledge Graph for Claude",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",