mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-18 06:15:51 +00:00
主要变更: - Skill Learning 闭环系统 (9/9 AC) - Opus 4.7 模型层接入 + adaptive thinking - Prompt 工程优化 (64 审计测试) - Agent Teams 简化门控 (默认启用) - Windows Terminal 后端修复 (EncodedCommand/WT_SESSION) - TF-IDF 技能搜索精准化 (字段加权/CJK 优化) - Autonomy 系统 (/autonomy 命令) - ACP 协议完整实现 - mock.module 泄漏修复 (CI 全绿) - 152+ lint/type 修复
280 lines
11 KiB
Markdown
280 lines
11 KiB
Markdown
# `/mcp` 斜杠命令路由机制
|
||
|
||
本文档描述用户在 REPL 交互模式下输入 `/mcp` 时,命令如何被解析、查找、分发,以及如何通过 React 状态机渲染交互式子项界面。
|
||
|
||
## 架构概览
|
||
|
||
```
|
||
用户输入 /mcp [args]
|
||
│
|
||
▼
|
||
┌─────────────────────────────────┐
|
||
│ 第一层:斜杠命令解析 │
|
||
│ slashCommandParsing.ts │
|
||
│ parseSlashCommand() │
|
||
│ → commandName + args 拆分 │
|
||
└──────────────┬──────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────┐
|
||
│ 第二层:命令查找与加载 │
|
||
│ commands.ts → findCommand() │
|
||
│ commands/mcp/index.ts │
|
||
│ → 懒加载 mcp.tsx 模块 │
|
||
└──────────────┬──────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────┐
|
||
│ 第三层:命令处理器分发 │
|
||
│ commands/mcp/mcp.tsx → call() │
|
||
│ → 根据 args 决定渲染哪个组件 │
|
||
└──────────────┬──────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────┐
|
||
│ 第四层:交互式 UI 状态机 │
|
||
│ MCPSettings → viewState 切换 │
|
||
│ MCPListPanel → 列表导航 │
|
||
│ MCPStdioServerMenu / │
|
||
│ MCPRemoteServerMenu → 操作菜单 │
|
||
└─────────────────────────────────┘
|
||
```
|
||
|
||
## 第一层:斜杠命令解析
|
||
|
||
**文件**: `src/utils/slashCommandParsing.ts`
|
||
|
||
`parseSlashCommand()` 负责将用户的原始输入拆分为命令名和参数:
|
||
|
||
```typescript
|
||
parseSlashCommand('/mcp')
|
||
// → { commandName: 'mcp', args: '', isMcp: false }
|
||
|
||
parseSlashCommand('/mcp enable sorftime')
|
||
// → { commandName: 'mcp', args: 'enable sorftime', isMcp: false }
|
||
|
||
parseSlashCommand('/mcp:tool (MCP) arg1')
|
||
// → { commandName: 'mcp:tool (MCP)', args: 'arg1', isMcp: true }
|
||
```
|
||
|
||
解析规则:
|
||
- 取 `/` 后的第一个词作为 `commandName`
|
||
- 剩余部分整体作为 `args` 字符串
|
||
- 如果第二个词是 `(MCP)`,则拼入 `commandName` 并标记 `isMcp: true`
|
||
- 解析器**不处理子命令层级**,子命令路由由各命令处理器自行实现
|
||
|
||
## 第二层:命令查找与加载
|
||
|
||
### 命令注册
|
||
|
||
**文件**: `src/commands/mcp/index.ts`
|
||
|
||
```typescript
|
||
const mcp = {
|
||
type: 'local-jsx', // 本地 JSX 组件命令,不经过 AI
|
||
name: 'mcp',
|
||
description: 'Manage MCP servers',
|
||
immediate: true, // 直接执行,不需要 AI 处理
|
||
argumentHint: '[enable|disable [server-name]]',
|
||
load: () => import('./mcp.js'), // 懒加载处理器
|
||
} satisfies Command
|
||
```
|
||
|
||
### 命令查找
|
||
|
||
**文件**: `src/commands.ts`
|
||
|
||
`findCommand()` 在全局 `COMMANDS` 列表中按 `name` 或 `aliases` 精确匹配:
|
||
|
||
```typescript
|
||
export function findCommand(commandName: string, commands: Command[]): Command | undefined {
|
||
return commands.find(
|
||
_ => _.name === commandName ||
|
||
getCommandName(_) === commandName ||
|
||
_.aliases?.includes(commandName),
|
||
);
|
||
}
|
||
```
|
||
|
||
全局命令列表由 `COMMANDS()` 函数(memoized)构建,`mcp` 是其中之一。
|
||
|
||
### 命令执行入口
|
||
|
||
**文件**: `src/utils/processUserInput/processSlashCommand.tsx`
|
||
|
||
`processSlashCommand` 调用 `findCommand` 找到命令后:
|
||
1. 对 `local-jsx` 类型命令,调用 `load()` 懒加载模块
|
||
2. 调用模块导出的 `call(onDone, context, args)` 函数
|
||
3. 返回的 React 节点由 Ink 渲染到终端
|
||
|
||
## 第三层:命令处理器分发
|
||
|
||
**文件**: `src/commands/mcp/mcp.tsx`
|
||
|
||
`call()` 函数根据 `args` 参数手动路由到不同的子功能:
|
||
|
||
```typescript
|
||
export async function call(onDone, _context, args?: string): Promise<React.ReactNode> {
|
||
if (args) {
|
||
const parts = args.trim().split(/\s+/);
|
||
|
||
// /mcp no-redirect → 绕过 ant 用户重定向,直接显示 MCP 设置
|
||
if (parts[0] === 'no-redirect') {
|
||
return <MCPSettings onComplete={onDone} />;
|
||
}
|
||
|
||
// /mcp reconnect <server-name> → 重连指定服务器
|
||
if (parts[0] === 'reconnect' && parts[1]) {
|
||
return <MCPReconnect serverName={parts.slice(1).join(' ')} onComplete={onDone} />;
|
||
}
|
||
|
||
// /mcp enable [server-name|all] → 启用服务器
|
||
// /mcp disable [server-name|all] → 禁用服务器
|
||
if (parts[0] === 'enable' || parts[0] === 'disable') {
|
||
return <MCPToggle
|
||
action={parts[0]}
|
||
target={parts.length > 1 ? parts.slice(1).join(' ') : 'all'}
|
||
onComplete={onDone}
|
||
/>;
|
||
}
|
||
}
|
||
|
||
// /mcp (无参数) → ant 用户重定向到 /plugins,其他用户显示 MCPSettings
|
||
if (process.env.USER_TYPE === 'ant') {
|
||
return <PluginSettings onComplete={onDone} args="manage" showMcpRedirectMessage />;
|
||
}
|
||
return <MCPSettings onComplete={onDone} />;
|
||
}
|
||
```
|
||
|
||
### 子命令映射表
|
||
|
||
| 输入 | 路由目标 | 说明 |
|
||
|------|---------|------|
|
||
| `/mcp` | `<MCPSettings>` | 交互式服务器管理 UI |
|
||
| `/mcp no-redirect` | `<MCPSettings>` | 绕过 ant 重定向 |
|
||
| `/mcp reconnect <name>` | `<MCPReconnect>` | 重连指定服务器 |
|
||
| `/mcp enable [name]` | `<MCPToggle action="enable">` | 启用服务器(默认 all) |
|
||
| `/mcp disable [name]` | `<MCPToggle action="disable">` | 禁用服务器(默认 all) |
|
||
|
||
### MCPToggle 组件
|
||
|
||
`MCPToggle` 是一个无 UI 的效果组件(返回 `null`),通过 `useEffect` 执行一次性操作:
|
||
|
||
1. 从 `appState.mcp.clients` 中筛选目标服务器(排除 `ide`)
|
||
2. 调用 `toggleMcpServer(name)` 切换启用状态
|
||
3. 通过 `onComplete` 回调返回结果消息
|
||
|
||
## 第四层:交互式 UI 状态机
|
||
|
||
### MCPSettings — 视图控制器
|
||
|
||
**文件**: `src/components/mcp/MCPSettings.tsx`
|
||
|
||
`MCPSettings` 是整个交互式界面的控制器,用 React state 驱动一个 5 状态的视图状态机:
|
||
|
||
```typescript
|
||
type MCPViewState =
|
||
| { type: 'list'; defaultTab?: string }
|
||
| { type: 'server-menu'; server: ServerInfo }
|
||
| { type: 'server-tools'; server: ServerInfo }
|
||
| { type: 'server-tool-detail'; server: ServerInfo; toolIndex: number }
|
||
| { type: 'agent-server-menu'; agentServer: AgentMcpServerInfo }
|
||
```
|
||
|
||
状态转换图:
|
||
|
||
```
|
||
list ──(选中普通服务器)──→ server-menu ──(查看工具)──→ server-tools ──(选中工具)──→ server-tool-detail
|
||
│ │ │ │
|
||
│ └──(Esc/返回)──→ list └──(返回)──→ server-menu └──(返回)──→ server-tools
|
||
│
|
||
└──(选中 Agent 服务器)──→ agent-server-menu
|
||
│
|
||
└──(Esc/返回)──→ list
|
||
```
|
||
|
||
### MCPSettings 数据准备
|
||
|
||
组件启动时:
|
||
1. 从 `appState.mcp.clients` 获取所有 MCP 客户端,过滤掉 `ide` 类型
|
||
2. 按传输类型(stdio/sse/http/claudeai-proxy)分类
|
||
3. 对远程服务器检查 OAuth 认证状态
|
||
4. 从 `appState.agentDefinitions` 提取 Agent 专属 MCP 服务器
|
||
5. 若无任何服务器,直接调用 `onComplete` 显示提示信息
|
||
|
||
### MCPListPanel — 服务器列表
|
||
|
||
**文件**: `src/components/mcp/MCPListPanel.tsx`
|
||
|
||
这是用户看到的"子项选择"界面,负责:
|
||
|
||
**分组与排序**:
|
||
```
|
||
Project MCPs (.mcp.json) ← scope: project
|
||
Local MCPs (settings.local.json) ← scope: local
|
||
User MCPs (settings.json) ← scope: user
|
||
Enterprise MCPs ← scope: enterprise
|
||
claude.ai ← type: claudeai-proxy
|
||
Agent MCPs ← 来自 agent 定义
|
||
Built-in MCPs (always available) ← scope: dynamic
|
||
```
|
||
|
||
**状态图标**:
|
||
|
||
| 状态 | 图标 | 文字 |
|
||
|------|------|------|
|
||
| `connected` | ✓ (绿色) | connected |
|
||
| `disabled` | ○ (灰色) | disabled |
|
||
| `pending` | ○ (灰色) | connecting… / reconnecting (n/m)… |
|
||
| `needs-auth` | △ (黄色) | needs authentication |
|
||
| `failed` | ✗ (红色) | failed |
|
||
|
||
**键盘交互**:
|
||
- `↑↓` — 在扁平列表中上下移动光标(`selectedIndex`)
|
||
- `Enter` — 选中当前项,触发 `onSelectServer(server)` → `setViewState({ type: 'server-menu', server })`
|
||
- `Esc` — 退出,调用 `onComplete('MCP dialog dismissed')`
|
||
|
||
### 子菜单组件
|
||
|
||
选中某个服务器后,根据传输类型渲染不同的操作菜单:
|
||
|
||
| 传输类型 | 组件 | 可用操作 |
|
||
|---------|------|---------|
|
||
| `stdio` | `MCPStdioServerMenu` | 启用/禁用、重连、查看工具、删除 |
|
||
| `sse` / `http` | `MCPRemoteServerMenu` | 认证、启用/禁用、重连、查看工具、删除 |
|
||
| Agent | `MCPAgentServerMenu` | 查看 Agent 配置信息 |
|
||
|
||
## 与 CLI 模式的对比
|
||
|
||
REPL 斜杠命令和 CLI 参数模式对 `mcp` 子命令的处理方式完全不同:
|
||
|
||
| 维度 | REPL `/mcp` | CLI `claude mcp` |
|
||
|------|------------|-----------------|
|
||
| 定义位置 | `commands/mcp/index.ts` + `mcp.tsx` | `main.tsx:4677-4757` (Commander.js) |
|
||
| 子命令路由 | `call()` 内手动 `args.split()` | Commander.js `.command()` 链式注册 |
|
||
| 子命令集合 | enable, disable, reconnect, no-redirect | serve, add, remove, list, get, add-json, add-from-claude-desktop, reset-project-choices |
|
||
| 交互方式 | Ink React 组件(键盘导航) | 一次性执行并退出 |
|
||
| 处理器 | React 组件 (`MCPSettings`, `MCPToggle`) | async handler 函数 (`cli/handlers/mcp.tsx`) |
|
||
|
||
两套子命令几乎没有重叠——REPL 侧重运行时交互(启用/禁用/浏览),CLI 侧重配置管理(添加/删除/列出)。
|
||
|
||
## 关键文件索引
|
||
|
||
| 文件 | 职责 |
|
||
|------|------|
|
||
| `src/utils/slashCommandParsing.ts` | 斜杠命令输入解析 |
|
||
| `src/utils/processUserInput/processSlashCommand.tsx` | 斜杠命令执行入口 |
|
||
| `src/commands.ts` | 全局命令注册与查找 (`findCommand`) |
|
||
| `src/commands/mcp/index.ts` | `/mcp` 命令定义(type, name, load) |
|
||
| `src/commands/mcp/mcp.tsx` | `/mcp` 处理器,args 分发 + MCPToggle 组件 |
|
||
| `src/components/mcp/MCPSettings.tsx` | 交互式 UI 状态机控制器 |
|
||
| `src/components/mcp/MCPListPanel.tsx` | 服务器列表与键盘导航 |
|
||
| `src/components/mcp/MCPStdioServerMenu.tsx` | stdio 服务器操作菜单 |
|
||
| `src/components/mcp/MCPRemoteServerMenu.tsx` | 远程服务器操作菜单 |
|
||
| `src/components/mcp/MCPAgentServerMenu.tsx` | Agent MCP 服务器菜单 |
|
||
| `src/components/mcp/MCPToolListView.tsx` | 工具列表视图 |
|
||
| `src/components/mcp/MCPToolDetailView.tsx` | 工具详情视图 |
|
||
| `src/main.tsx:4677-4757` | CLI 模式 `claude mcp` 子命令注册 |
|
||
| `src/cli/handlers/mcp.tsx` | CLI 模式 handler 实现 |
|