@42ailab/42plugin 0.1.26 → 0.1.27

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@42ailab/42plugin",
3
- "version": "0.1.26",
3
+ "version": "0.1.27",
4
4
  "description": "活水插件",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
package/src/api.ts CHANGED
@@ -527,7 +527,7 @@ class ApiClient {
527
527
  version?: string;
528
528
  content_hash?: string;
529
529
  visibility?: 'self' | 'public';
530
- }>(`/v1/plugins/me/${name}/status`);
530
+ }>(`/v1/plugins/status/${name}`);
531
531
 
532
532
  return {
533
533
  exists: result.exists,
@@ -29,7 +29,6 @@ const SKIP_AUTH_COMMANDS = new Set([
29
29
  'auth',
30
30
  'list',
31
31
  'check',
32
- 'completion',
33
32
  'setup',
34
33
  'version',
35
34
  ]);
@@ -14,7 +14,7 @@ export const listCommand = new Command('list')
14
14
  .description('查看已安装的插件')
15
15
  .option('-g, --global', '显示全局安装的插件 (~/.claude/)')
16
16
  .option('-a, --all', '显示所有项目的插件(包括全局)')
17
- .option('-t, --type <type>', '筛选类型 (skill, agent, command, hook, mcp)')
17
+ .option('-t, --type <type>', '筛选类型 (skill, agent, command, hook)')
18
18
  .option('--json', '输出 JSON 格式')
19
19
  .action(async (options) => {
20
20
  try {
@@ -13,14 +13,13 @@ import { ValidationError, UploadError, AuthRequiredError } from '../errors';
13
13
  import { getTypeIcon } from '../utils';
14
14
  import type { PluginType } from '../types';
15
15
 
16
- const VALID_TYPES: PluginType[] = ['skill', 'agent', 'command', 'hook', 'mcp'];
16
+ const VALID_TYPES: PluginType[] = ['skill', 'agent', 'command', 'hook'];
17
17
 
18
18
  const TYPE_DESCRIPTIONS: Record<PluginType, string> = {
19
19
  skill: 'skill(技能) - 包含 SKILL.md 的目录,为 Claude 提供特定能力',
20
20
  agent: 'agent(代理) - 单个 .md 文件,定义 AI 角色和行为',
21
21
  command: 'command(命令) - 单个 .md 文件,定义可执行的斜杠命令',
22
22
  hook: 'hook(钩子) - 包含 hooks.json 的目录,响应事件触发',
23
- mcp: 'mcp(MCP 服务) - 包含 mcp.json 的目录,Model Context Protocol 服务',
24
23
  };
25
24
 
26
25
  /**
@@ -43,9 +42,6 @@ async function suggestType(pluginPath: string): Promise<PluginType> {
43
42
  if (normalizedPath.includes('/.claude/hooks/') || normalizedPath.includes('.claude/hooks/')) {
44
43
  return 'hook';
45
44
  }
46
- if (normalizedPath.includes('/.claude/mcp/') || normalizedPath.includes('.claude/mcp/')) {
47
- return 'mcp';
48
- }
49
45
 
50
46
  // 2. 检查是否是目录,如果是则检查特征文件
51
47
  try {
@@ -54,9 +50,6 @@ async function suggestType(pluginPath: string): Promise<PluginType> {
54
50
  const files = await fs.readdir(absPath);
55
51
  const lowerFiles = files.map((f) => f.toLowerCase());
56
52
 
57
- if (lowerFiles.includes('mcp.json') || lowerFiles.includes('.mcp.json')) {
58
- return 'mcp';
59
- }
60
53
  if (lowerFiles.includes('hooks.json') || lowerFiles.includes('hook.json')) {
61
54
  return 'hook';
62
55
  }
@@ -80,7 +73,7 @@ export const publishCommand = new Command('publish')
80
73
  .option('-f, --force', '强制发布(即使内容未变化)')
81
74
  .option('--public', '公开发布(默认仅自己可见)')
82
75
  .option('-n, --name <name>', '覆盖插件名称')
83
- .option('-t, --type <type>', '指定插件类型 (skill|agent|command|hook|mcp)')
76
+ .option('-t, --type <type>', '指定插件类型 (skill|agent|command|hook)')
84
77
  .action(async (pluginPath, options) => {
85
78
  try {
86
79
  // 验证 --type 参数
@@ -54,7 +54,7 @@ function displayKitResults(items: KitSearchResult[]): void {
54
54
  export const searchCommand = new Command('search')
55
55
  .description('搜索插件和套包')
56
56
  .argument('<keyword>', '搜索关键词')
57
- .option('-t, --type <type>', '筛选插件类型 (skill, agent, command, hook, mcp)')
57
+ .option('-t, --type <type>', '筛选插件类型 (skill, agent, command, hook)')
58
58
  .option('-k, --kit', '只搜索套包')
59
59
  .option('-p, --plugin', '只搜索插件')
60
60
  .option('-l, --limit <n>', '每页数量', String(DEFAULT_PAGE_SIZE))
@@ -39,7 +39,8 @@ async function setupCompletion(): Promise<void> {
39
39
 
40
40
  if (!shell) {
41
41
  console.log(chalk.yellow('无法检测当前 Shell 类型'));
42
- console.log(chalk.gray('请手动运行: 42plugin completion <bash|zsh|fish>'));
42
+ console.log(chalk.gray('支持的 Shell: bash, zsh, fish'));
43
+ console.log(chalk.gray('请确保 $SHELL 环境变量正确设置'));
43
44
  return;
44
45
  }
45
46
 
@@ -110,7 +111,7 @@ function getShellConfigFile(shell: string): string | null {
110
111
  async function checkAlreadyConfigured(configFile: string): Promise<boolean> {
111
112
  try {
112
113
  const content = await fs.readFile(configFile, 'utf-8');
113
- return content.includes('42plugin completion');
114
+ return content.includes('# 42plugin CLI 补全');
114
115
  } catch {
115
116
  return false;
116
117
  }
@@ -136,22 +137,227 @@ async function installCompletion(shell: string, configFile: string): Promise<voi
136
137
  }
137
138
 
138
139
  function getCompletionInitScript(shell: string): string {
140
+ // 42plugin 支持的命令和选项
141
+ const commands = ['auth', 'search', 'install', 'list', 'uninstall', 'publish', 'check', 'setup', 'version'];
142
+ const globalOptions = ['--help', '--version', '--verbose', '--no-color'];
143
+
139
144
  switch (shell) {
140
145
  case 'bash':
141
146
  return `
142
147
  # 42plugin CLI 补全
143
- eval "$(42plugin completion bash)"
148
+ _42plugin_installed_plugins() {
149
+ 42plugin list --all --json 2>/dev/null | grep -o '"fullName": "[^"]*"' | cut -d'"' -f4
150
+ }
151
+
152
+ _42plugin_completions() {
153
+ local cur prev pprev commands
154
+ cur="\${COMP_WORDS[COMP_CWORD]}"
155
+ prev="\${COMP_WORDS[COMP_CWORD-1]}"
156
+ pprev="\${COMP_WORDS[COMP_CWORD-2]:-}"
157
+ commands="${commands.join(' ')}"
158
+
159
+ # 处理 --type 后的类型补全
160
+ if [[ "\${prev}" == "--type" ]] || [[ "\${prev}" == "-t" ]]; then
161
+ COMPREPLY=( $(compgen -W "skill agent command hook" -- "\${cur}") )
162
+ return 0
163
+ fi
164
+
165
+ case "\${prev}" in
166
+ 42plugin)
167
+ COMPREPLY=( $(compgen -W "\${commands} ${globalOptions.join(' ')}" -- "\${cur}") )
168
+ return 0
169
+ ;;
170
+ uninstall|rm)
171
+ # 从本地数据库获取已安装插件
172
+ local plugins=$(_42plugin_installed_plugins)
173
+ COMPREPLY=( $(compgen -W "\${plugins}" -- "\${cur}") )
174
+ return 0
175
+ ;;
176
+ install)
177
+ return 0
178
+ ;;
179
+ search)
180
+ return 0
181
+ ;;
182
+ publish|pub)
183
+ # 路径补全 + 选项补全
184
+ if [[ "\${cur}" == -* ]]; then
185
+ COMPREPLY=( $(compgen -W "--dry-run --force --public --name --type -f -n -t" -- "\${cur}") )
186
+ else
187
+ COMPREPLY=( $(compgen -f -d -- "\${cur}") )
188
+ fi
189
+ return 0
190
+ ;;
191
+ check)
192
+ # 路径补全
193
+ COMPREPLY=( $(compgen -f -d -- "\${cur}") )
194
+ return 0
195
+ ;;
196
+ *)
197
+ # 检查是否在 publish/check 子命令中
198
+ for word in "\${COMP_WORDS[@]}"; do
199
+ if [[ "\$word" == "publish" ]] || [[ "\$word" == "pub" ]] || [[ "\$word" == "check" ]]; then
200
+ if [[ "\${cur}" == -* ]]; then
201
+ COMPREPLY=( $(compgen -W "--dry-run --force --public --name --type -f -n -t --help" -- "\${cur}") )
202
+ else
203
+ COMPREPLY=( $(compgen -f -d -- "\${cur}") )
204
+ fi
205
+ return 0
206
+ fi
207
+ if [[ "\$word" == "uninstall" ]] || [[ "\$word" == "rm" ]]; then
208
+ local plugins=$(_42plugin_installed_plugins)
209
+ COMPREPLY=( $(compgen -W "\${plugins}" -- "\${cur}") )
210
+ return 0
211
+ fi
212
+ done
213
+ COMPREPLY=( $(compgen -W "--help" -- "\${cur}") )
214
+ return 0
215
+ ;;
216
+ esac
217
+ }
218
+ complete -F _42plugin_completions 42plugin
144
219
  `;
220
+
145
221
  case 'zsh':
146
222
  return `
147
223
  # 42plugin CLI 补全
148
- eval "$(42plugin completion zsh)"
224
+ _42plugin_installed_plugins() {
225
+ local -a plugins
226
+ plugins=(\${(f)"$(42plugin list --all --json 2>/dev/null | grep -o '"fullName": "[^"]*"' | cut -d'"' -f4)"})
227
+ _describe 'installed plugin' plugins
228
+ }
229
+
230
+ _42plugin() {
231
+ local -a commands
232
+ commands=(
233
+ 'auth:登录或查看认证状态'
234
+ 'search:搜索插件'
235
+ 'install:安装插件'
236
+ 'list:列出已安装插件'
237
+ 'uninstall:卸载插件'
238
+ 'publish:发布插件'
239
+ 'check:检查插件更新'
240
+ 'setup:配置 CLI 环境'
241
+ 'version:显示版本信息'
242
+ )
243
+
244
+ _arguments -C \\
245
+ "1: :{_describe 'command' commands}" \\
246
+ "*::arg:->args"
247
+
248
+ case "\$state" in
249
+ args)
250
+ case \$words[1] in
251
+ publish|pub)
252
+ _arguments \\
253
+ '--dry-run[仅验证不发布]' \\
254
+ '-f[强制发布]' '--force[强制发布]' \\
255
+ '--public[公开发布]' \\
256
+ '-n[指定名称]:name:' '--name[指定名称]:name:' \\
257
+ '-t[指定类型]:type:(skill agent command hook)' '--type[指定类型]:type:(skill agent command hook)' \\
258
+ '*:path:_files -/'
259
+ ;;
260
+ check)
261
+ _arguments \\
262
+ '--fix[自动修复问题]' \\
263
+ '*:path:_files -/'
264
+ ;;
265
+ install)
266
+ _arguments \\
267
+ '-g[全局安装]' '--global[全局安装]' \\
268
+ '*:plugin:'
269
+ ;;
270
+ uninstall|rm)
271
+ _arguments \\
272
+ '-g[卸载全局插件]' '--global[卸载全局插件]' \\
273
+ '*:plugin:_42plugin_installed_plugins'
274
+ ;;
275
+ list|ls)
276
+ _arguments \\
277
+ '-g[显示全局插件]' '--global[显示全局插件]' \\
278
+ '-a[显示所有项目]' '--all[显示所有项目]' \\
279
+ '-t[筛选类型]:type:(skill agent command hook)' '--type[筛选类型]:type:(skill agent command hook)' \\
280
+ '--json[输出 JSON]'
281
+ ;;
282
+ search)
283
+ _arguments \\
284
+ '-t[筛选类型]:type:(skill agent command hook kit)' '--type[筛选类型]:type:(skill agent command hook kit)' \\
285
+ '*:query:'
286
+ ;;
287
+ auth)
288
+ _arguments \\
289
+ '--logout[登出]' \\
290
+ '--status[查看状态]'
291
+ ;;
292
+ *)
293
+ _arguments '*: :_files'
294
+ ;;
295
+ esac
296
+ ;;
297
+ esac
298
+ }
299
+ compdef _42plugin 42plugin
149
300
  `;
301
+
150
302
  case 'fish':
151
303
  return `
152
304
  # 42plugin CLI 补全
153
- 42plugin completion fish | source
305
+
306
+ # 获取已安装插件列表
307
+ function __42plugin_installed_plugins
308
+ 42plugin list --all --json 2>/dev/null | string match -r '"fullName": "[^"]*"' | string replace -r '"fullName": "([^"]*)"' '$1'
309
+ end
310
+
311
+ # 主命令
312
+ complete -c 42plugin -n "__fish_use_subcommand" -a "auth" -d "登录或查看认证状态"
313
+ complete -c 42plugin -n "__fish_use_subcommand" -a "search" -d "搜索插件"
314
+ complete -c 42plugin -n "__fish_use_subcommand" -a "install" -d "安装插件"
315
+ complete -c 42plugin -n "__fish_use_subcommand" -a "list" -d "列出已安装插件"
316
+ complete -c 42plugin -n "__fish_use_subcommand" -a "uninstall" -d "卸载插件"
317
+ complete -c 42plugin -n "__fish_use_subcommand" -a "publish" -d "发布插件"
318
+ complete -c 42plugin -n "__fish_use_subcommand" -a "check" -d "检查插件更新"
319
+ complete -c 42plugin -n "__fish_use_subcommand" -a "setup" -d "配置 CLI 环境"
320
+ complete -c 42plugin -n "__fish_use_subcommand" -a "version" -d "显示版本信息"
321
+
322
+ # auth 选项
323
+ complete -c 42plugin -n "__fish_seen_subcommand_from auth" -l logout -d "登出"
324
+ complete -c 42plugin -n "__fish_seen_subcommand_from auth" -l status -d "查看状态"
325
+
326
+ # publish 选项 + 路径补全
327
+ complete -c 42plugin -n "__fish_seen_subcommand_from publish pub" -l dry-run -d "仅验证不发布"
328
+ complete -c 42plugin -n "__fish_seen_subcommand_from publish pub" -s f -l force -d "强制发布"
329
+ complete -c 42plugin -n "__fish_seen_subcommand_from publish pub" -l public -d "公开发布"
330
+ complete -c 42plugin -n "__fish_seen_subcommand_from publish pub" -s n -l name -d "指定名称" -r
331
+ complete -c 42plugin -n "__fish_seen_subcommand_from publish pub" -s t -l type -d "指定类型" -ra "skill agent command hook"
332
+ complete -c 42plugin -n "__fish_seen_subcommand_from publish pub" -a "(__fish_complete_path)" -d "路径"
333
+
334
+ # check 选项 + 路径补全
335
+ complete -c 42plugin -n "__fish_seen_subcommand_from check" -l fix -d "自动修复"
336
+ complete -c 42plugin -n "__fish_seen_subcommand_from check" -a "(__fish_complete_path)" -d "路径"
337
+
338
+ # install 选项
339
+ complete -c 42plugin -n "__fish_seen_subcommand_from install" -s g -l global -d "全局安装"
340
+
341
+ # uninstall 选项 + 已安装插件补全
342
+ complete -c 42plugin -n "__fish_seen_subcommand_from uninstall rm" -s g -l global -d "卸载全局插件"
343
+ complete -c 42plugin -n "__fish_seen_subcommand_from uninstall rm" -a "(__42plugin_installed_plugins)" -d "已安装插件"
344
+
345
+ # list 选项
346
+ complete -c 42plugin -n "__fish_seen_subcommand_from list ls" -s g -l global -d "显示全局插件"
347
+ complete -c 42plugin -n "__fish_seen_subcommand_from list ls" -s a -l all -d "显示所有项目"
348
+ complete -c 42plugin -n "__fish_seen_subcommand_from list ls" -s t -l type -d "筛选类型" -ra "skill agent command hook"
349
+ complete -c 42plugin -n "__fish_seen_subcommand_from list ls" -l json -d "输出 JSON"
350
+
351
+ # search 选项
352
+ complete -c 42plugin -n "__fish_seen_subcommand_from search" -s t -l type -d "筛选类型" -ra "skill agent command hook kit"
353
+
354
+ # 全局选项
355
+ complete -c 42plugin -l help -d "显示帮助"
356
+ complete -c 42plugin -s v -l version -d "显示版本"
357
+ complete -c 42plugin -l verbose -d "详细输出"
358
+ complete -c 42plugin -l no-color -d "禁用颜色"
154
359
  `;
360
+
155
361
  default:
156
362
  return '';
157
363
  }
@@ -1,14 +1,14 @@
1
1
  /**
2
2
  * 插件清单解析服务
3
3
  *
4
- * 从插件目录读取 SKILL.md / AGENT.md / COMMAND.md / HOOK.md / MCP.md
4
+ * 从插件目录读取 SKILL.md / AGENT.md / COMMAND.md / HOOK.md
5
5
  * 解析 frontmatter 获取插件元数据
6
6
  */
7
7
  import * as fs from 'fs/promises';
8
8
  import * as path from 'path';
9
9
  import matter from 'gray-matter';
10
10
 
11
- export type CapabilityType = 'skill' | 'agent' | 'command' | 'hook' | 'mcp';
11
+ export type CapabilityType = 'skill' | 'agent' | 'command' | 'hook';
12
12
 
13
13
  export interface PluginManifest {
14
14
  name: string; // 必填,插件名称
@@ -28,13 +28,12 @@ const TYPE_FILES: Record<string, CapabilityType> = {
28
28
  'AGENT.md': 'agent',
29
29
  'COMMAND.md': 'command',
30
30
  'HOOK.md': 'hook',
31
- 'MCP.md': 'mcp',
32
31
  };
33
32
 
34
33
  /**
35
34
  * 从目录读取插件清单
36
35
  *
37
- * 扫描顺序:SKILL.md → AGENT.md → COMMAND.md → HOOK.md → MCP.md
36
+ * 扫描顺序:SKILL.md → AGENT.md → COMMAND.md → HOOK.md
38
37
  * 返回第一个找到的清单
39
38
  */
40
39
  export async function readManifest(pluginPath: string): Promise<PluginManifest> {
@@ -97,8 +96,7 @@ export async function readManifest(pluginPath: string): Promise<PluginManifest>
97
96
  ` - SKILL.md (技能插件)\n` +
98
97
  ` - AGENT.md (代理插件)\n` +
99
98
  ` - COMMAND.md (命令插件)\n` +
100
- ` - HOOK.md (钩子插件)\n` +
101
- ` - MCP.md (MCP 插件)`
99
+ ` - HOOK.md (钩子插件)`
102
100
  );
103
101
  }
104
102
 
@@ -16,7 +16,6 @@ import type { PackageResult } from '../types';
16
16
 
17
17
  // 需要保留的功能性隐藏文件
18
18
  const ALLOWED_HIDDEN_FILES = [
19
- '.mcp.json',
20
19
  '.tool.json',
21
20
  '.plugin.json',
22
21
  '.claude',
@@ -268,7 +268,6 @@ export class Publisher {
268
268
  agent: ['AGENT.md', 'agent.md'],
269
269
  command: ['COMMAND.md', 'command.md'],
270
270
  hook: ['HOOK.md', 'hook.md'],
271
- mcp: ['MCP.md', 'mcp.md'],
272
271
  };
273
272
 
274
273
  const fallbackNames = ['README.md', 'readme.md'];
package/src/types.ts CHANGED
@@ -8,7 +8,7 @@
8
8
  // 基础类型
9
9
  // ============================================================================
10
10
 
11
- export type PluginType = 'skill' | 'agent' | 'command' | 'hook' | 'mcp';
11
+ export type PluginType = 'skill' | 'agent' | 'command' | 'hook';
12
12
  export type PriceTier = 'free' | 'vip' | 'premium';
13
13
 
14
14
  // ============================================================================
@@ -393,18 +393,3 @@ export interface HookConfig {
393
393
  };
394
394
  }
395
395
 
396
- // MCP 配置
397
- export interface McpConfig {
398
- name?: string;
399
- protocol_version?: string;
400
- capabilities?: {
401
- resources?: boolean;
402
- tools?: boolean;
403
- sampling?: boolean;
404
- };
405
- tools?: Array<{
406
- name: string;
407
- description?: string;
408
- inputSchema?: Record<string, unknown>;
409
- }>;
410
- }
package/src/utils.ts CHANGED
@@ -104,8 +104,6 @@ export function getInstallPath(type: PluginType, name: string): string {
104
104
  return `.claude/commands/${name}.md`;
105
105
  case 'hook':
106
106
  return `.claude/hooks/${name}`;
107
- case 'mcp':
108
- return `.claude/mcp/${name}/`;
109
107
  default:
110
108
  return `.claude/${type}/${name}/`;
111
109
  }
@@ -157,7 +155,6 @@ const TYPE_LABELS: Record<PluginType, string> = {
157
155
  agent: 'Agent',
158
156
  command: 'Command',
159
157
  hook: 'Hook',
160
- mcp: 'MCP',
161
158
  };
162
159
 
163
160
  const TYPE_ICONS: Record<PluginType, string> = {
@@ -165,7 +162,6 @@ const TYPE_ICONS: Record<PluginType, string> = {
165
162
  agent: '🤖',
166
163
  command: '⌘',
167
164
  hook: '🪝',
168
- mcp: '🔌',
169
165
  };
170
166
 
171
167
  export function getTypeLabel(type: PluginType): string {
@@ -6,7 +6,6 @@
6
6
  * - agent: Agent 插件(仅单文件)
7
7
  * - command: 命令插件(目录或单文件)
8
8
  * - hook: Hook 插件(仅目录,需要 hooks.json)
9
- * - mcp: MCP 服务器插件(仅目录,需要 mcp.json)
10
9
  */
11
10
 
12
11
  import fs from 'fs/promises';
@@ -19,7 +18,6 @@ import type {
19
18
  ValidationResult,
20
19
  ValidationIssue,
21
20
  HookConfig,
22
- McpConfig,
23
21
  } from '../types';
24
22
 
25
23
  // ============================================================================
@@ -33,7 +31,7 @@ const MIN_DESCRIPTION_LENGTH = 20;
33
31
  const MAX_TAG_LENGTH = 32;
34
32
  const MAX_AGENT_FILE_SIZE = 50 * 1024; // 50KB
35
33
 
36
- const VALID_TYPES: PluginType[] = ['skill', 'agent', 'command', 'hook', 'mcp'];
34
+ const VALID_TYPES: PluginType[] = ['skill', 'agent', 'command', 'hook'];
37
35
 
38
36
  // ============================================================================
39
37
  // PluginValidator 类
@@ -349,9 +347,6 @@ export class PluginValidator {
349
347
  case 'hook':
350
348
  await this.validateHook(absPath, isDirectory, result);
351
349
  break;
352
- case 'mcp':
353
- await this.validateMcp(absPath, isDirectory, result);
354
- break;
355
350
  case 'skill':
356
351
  case 'command':
357
352
  // skill 和 command 支持单文件和目录,无特殊限制
@@ -471,76 +466,6 @@ export class PluginValidator {
471
466
  }
472
467
  }
473
468
 
474
- /**
475
- * MCP 类型验证
476
- */
477
- private async validateMcp(
478
- absPath: string,
479
- isDirectory: boolean,
480
- result: ValidationResult
481
- ): Promise<void> {
482
- // MCP 必须是目录
483
- if (!isDirectory) {
484
- result.errors.push({
485
- code: 'E050',
486
- field: 'type',
487
- message: 'MCP 类型必须是目录格式',
488
- suggestion: '请创建包含 mcp.json 的目录',
489
- });
490
- return;
491
- }
492
-
493
- // 检查 mcp.json 是否存在
494
- const mcpJsonPath = path.join(absPath, 'mcp.json');
495
- const dotMcpJsonPath = path.join(absPath, '.mcp.json');
496
-
497
- let configPath: string | null = null;
498
- if (await this.exists(mcpJsonPath)) {
499
- configPath = mcpJsonPath;
500
- } else if (await this.exists(dotMcpJsonPath)) {
501
- configPath = dotMcpJsonPath;
502
- }
503
-
504
- if (!configPath) {
505
- result.errors.push({
506
- code: 'E051',
507
- message: '缺少 mcp.json 配置文件',
508
- suggestion: '创建 mcp.json 文件定义 MCP 服务器配置',
509
- });
510
- return;
511
- }
512
-
513
- // 验证 mcp.json 内容
514
- try {
515
- const content = await fs.readFile(configPath, 'utf-8');
516
- const config = JSON.parse(content) as McpConfig;
517
-
518
- // 建议指定 protocol_version
519
- if (!config.protocol_version) {
520
- result.warnings.push({
521
- code: 'W050',
522
- message: '建议指定 protocol_version',
523
- suggestion: '添加 "protocol_version": "2024-11" 到 mcp.json',
524
- });
525
- }
526
-
527
- // 建议声明 capabilities
528
- if (!config.capabilities) {
529
- result.warnings.push({
530
- code: 'W051',
531
- message: '建议声明 capabilities',
532
- suggestion: '添加 capabilities 对象声明支持的功能',
533
- });
534
- }
535
- } catch (e) {
536
- result.errors.push({
537
- code: 'E051',
538
- message: `mcp.json 解析失败: ${(e as Error).message}`,
539
- suggestion: '请检查 JSON 格式是否正确',
540
- });
541
- }
542
- }
543
-
544
469
  // ==========================================================================
545
470
  // 引用检查
546
471
  // ==========================================================================