Contents

Claude Code 桥接与插件系统源码解读

Claude Code 桥接与插件系统源码解读

分析版本: Claude Code Main Branch 源码路径: /mnt/e/code/cc/claude-code-main/src


目录

  1. MCP (Model Context Protocol) 集成
  2. 插件扩展点设计
  3. API 桥接机制
  4. 第三方工具接入
  5. 插件生命周期管理
  6. 总结与架构图

1. MCP (Model Context Protocol) 集成

1.1 MCP 客户端架构

Claude Code 实现了完整的 MCP 客户端,支持多种传输协议:

核心文件:

  • src/services/mcp/client.ts - MCP 客户端主实现 (1500+ 行)
  • src/services/mcp/types.ts - MCP 类型定义

支持的传输类型:

// src/services/mcp/types.ts
export const TransportSchema = z.enum([
  'stdio',   // 标准输入输出
  'sse',     // Server-Sent Events
  'sse-ide', // IDE 专用 SSE
  'http',    // HTTP Streamable
  'ws',      // WebSocket
  'ws-ide',  // IDE 专用 WebSocket
  'sdk',     // SDK 模式
])

客户端连接流程 (connectToServer):

// src/services/mcp/client.ts:595-961
export const connectToServer = memoize(
  async (name, serverRef, serverStats) => {
    // 1. 根据传输类型创建 Transport
    let transport
    if (serverRef.type === 'sse') {
      transport = new SSEClientTransport(new URL(serverRef.url), options)
    } else if (serverRef.type === 'http') {
      transport = new StreamableHTTPClientTransport(new URL(serverRef.url), options)
    } else if (serverRef.type === 'ws') {
      transport = new WebSocketTransport(wsClient)
    } else if (serverRef.type === 'stdio') {
      transport = new StdioClientTransport({ command, args, env })
    }
    
    // 2. 创建 MCP Client
    const client = new Client({
      name: 'claude-code',
      version: MACRO.VERSION,
    }, {
      capabilities: { roots: {}, elicitation: {} },
    })
    
    // 3. 设置请求处理器
    client.setRequestHandler(ListRootsRequestSchema, async () => ({
      roots: [{ uri: `file://${getOriginalCwd()}` }],
    }))
    
    // 4. 连接并设置错误处理
    await client.connect(transport)
  }
)

1.2 MCP 服务器实现

Claude Code 可以作为 MCP 服务器运行,暴露其工具给其他 MCP 客户端:

核心文件: src/entrypoints/mcp.ts

// src/entrypoints/mcp.ts:35-57
export async function startMCPServer(cwd: string, debug: boolean, verbose: boolean) {
  const server = new Server({
    name: 'claude/tengu',
    version: MACRO.VERSION,
  }, {
    capabilities: { tools: {} },
  })

  // 暴露工具列表
  server.setRequestHandler(ListToolsRequestSchema, async () => {
    const tools = getTools(toolPermissionContext)
    return {
      tools: tools.map(tool => ({
        name: tool.name,
        description: await tool.prompt(...),
        inputSchema: zodToJsonSchema(tool.inputSchema),
      })),
    }
  })

  // 处理工具调用
  server.setRequestHandler(CallToolRequestSchema, async ({ params }) => {
    const tool = findToolByName(tools, params.name)
    const result = await tool.call(params.arguments, toolUseContext, ...)
    return { content: [{ type: 'text', text: jsonStringify(result) }] }
  })

  const transport = new StdioServerTransport()
  await server.connect(transport)
}

1.3 MCP 认证机制

支持 OAuth 2.0 和自定义认证提供者:

// src/services/mcp/client.ts:619-641
if (serverRef.type === 'sse') {
  const authProvider = new ClaudeAuthProvider(name, serverRef)
  const transportOptions: SSEClientTransportOptions = {
    authProvider,
    fetch: wrapFetchWithTimeout(
      wrapFetchWithStepUpDetection(createFetchWithInit(), authProvider)
    ),
  }
}

1.4 MCP 工具规范化

工具名称经过规范化处理以避免冲突:

// src/services/mcp/mcpStringUtils.ts
export function buildMcpToolName(serverName: string, toolName: string): string {
  return `mcp__${normalizeNameForMCP(serverName)}__${normalizeNameForMCP(toolName)}`
}

2. 插件扩展点设计

2.1 插件清单 (Plugin Manifest)

插件通过 plugin.json 声明扩展点:

核心文件: src/utils/plugins/schemas.ts

// src/utils/plugins/schemas.ts:884-898
export const PluginManifestSchema = lazySchema(() =>
  z.object({
    ...PluginManifestMetadataSchema().shape,
    ...PluginManifestHooksSchema().partial().shape,      // 钩子扩展
    ...PluginManifestCommandsSchema().partial().shape,   // 命令扩展
    ...PluginManifestAgentsSchema().partial().shape,    // Agent 扩展
    ...PluginManifestSkillsSchema().partial().shape,    // Skill 扩展
    ...PluginManifestOutputStylesSchema().partial().shape, // 输出样式扩展
    ...PluginManifestMcpServerSchema().partial().shape, // MCP 服务器
    ...PluginManifestLspServerSchema().partial().shape, // LSP 服务器
  }),
)

2.2 插件目录结构

my-plugin/
├── .claude-plugin/
│   └── plugin.json          # 插件清单
├── commands/                 # 自定义斜杠命令
│   ├── build.md
│   └── deploy.md
├── agents/                  # 自定义 Agent
│   └── reviewer.md
├── skills/                  # 自定义 Skill
├── hooks/                   # 钩子配置
│   └── hooks.json
├── output-styles/           # 输出样式
└── mcpServers/              # MCP 服务器配置

2.3 插件类型定义

核心文件: src/types/plugin.ts

// src/types/plugin.ts:48-70
export type LoadedPlugin = {
  name: string
  manifest: PluginManifest
  path: string
  source: string
  repository: string
  enabled?: boolean
  isBuiltin?: boolean
  sha?: string  // Git commit SHA for version pinning
  commandsPath?: string
  agentsPath?: string
  skillsPath?: string
  hooksConfig?: HooksSettings
  mcpServers?: Record<string, McpServerConfig>
  lspServers?: Record<string, LspServerConfig>
  settings?: Record<string, unknown>
}

2.4 插件来源类型

// src/utils/plugins/schemas.ts:1062-1161
export const PluginSourceSchema = z.union([
  RelativePath(),  // 本地相对路径
  
  // 远程来源
  z.object({ source: 'npm', package: NpmPackageNameSchema(), version?: string }),
  z.object({ source: 'pip', package: string, version?: string }),  // Python
  z.object({ source: 'github', repo: string, ref?: string, sha?: string }),
  z.object({ source: 'url', url: string, ref?: string, sha?: string }),
  z.object({ source: 'git-subdir', url: string, path: string, ... }),
])

2.5 内置插件 (Builtin Plugins)

内置插件随 CLI 一起发布:

// src/plugins/builtinPlugins.ts
export type BuiltinPluginDefinition = {
  name: string
  description: string
  version?: string
  skills?: BundledSkillDefinition[]
  hooks?: HooksSettings
  mcpServers?: Record<string, McpServerConfig>
  isAvailable?: () => boolean
  defaultEnabled?: boolean
}

2.6 插件市场 (Marketplace)

// src/utils/plugins/schemas.ts:1293-1326
export const PluginMarketplaceSchema = lazySchema(() =>
  z.object({
    name: MarketplaceNameSchema(),
    owner: PluginAuthorSchema(),
    plugins: z.array(PluginMarketplaceEntrySchema()),
    forceRemoveDeletedPlugins?: boolean,
    metadata?: { pluginRoot?: string, version?: string },
    allowCrossMarketplaceDependenciesOn?: string[],
  }),
)

3. API 桥接机制

3.1 桥接主循环 (Bridge Loop)

核心文件: src/bridge/bridgeMain.ts

Claude Code 的 Bridge 是远程控制的核心,负责:

  • 与后端服务器保持长连接
  • 管理多个并发会话
  • 处理工作分发和结果回收
// src/bridge/bridgeMain.ts:141-151
export async function runBridgeLoop(
  config: BridgeConfig,
  environmentId: string,
  environmentSecret: string,
  api: BridgeApiClient,
  spawner: SessionSpawner,
  logger: BridgeLogger,
  signal: AbortSignal,
  backoffConfig: BackoffConfig = DEFAULT_BACKOFF,
) {
  const activeSessions = new Map<string, SessionHandle>()
  
  while (!loopSignal.aborted) {
    // 1. 轮询工作
    const work = await api.pollForWork(environmentId, environmentSecret, ...)
    
    // 2. 处理工作类型
    switch (work.data.type) {
      case 'healthcheck':
        await ackWork()
        break
      case 'session':
        // 启动新会话
        const handle = spawner.spawn({ sessionId, sdkUrl, accessToken, ... })
        activeSessions.set(sessionId, handle)
        break
    }
    
    // 3. 心跳保活
    await heartbeatActiveWorkItems()
  }
}

3.2 会话生命周期

// src/bridge/bridgeMain.ts:442-591
function onSessionDone(sessionId, startTime, handle) {
  return (status: SessionDoneStatus) => {
    // 清理会话
    activeSessions.delete(sessionId)
    
    // 通知服务器工作完成
    stopWorkWithRetry(api, environmentId, workId, ...)
    
    // 清理关联的工作树
    removeAgentWorktree(wt.worktreePath, wt.worktreeBranch, ...)
    
    // 多会话模式: 存档会话; 单会话模式: 关闭环境
    if (config.spawnMode !== 'single-session') {
      api.archiveSession(compatId)
    } else {
      controller.abort()  // 关闭桥接循环
    }
  }
}

3.3 多会话与工作树隔离

Bridge 支持多会话模式,每个会话可在独立的工作树中运行:

// src/bridge/bridgeMain.ts:976-1015
if (spawnModeAtDecision === 'worktree' && ...) {
  const wt = await createAgentWorktree(`bridge-${safeFilenameId(sessionId)}`)
  sessionWorktrees.set(sessionId, {
    worktreePath: wt.worktreePath,
    worktreeBranch: wt.worktreeBranch,
    gitRoot: wt.gitRoot,
  })
  sessionDir = wt.worktreePath
}

3.4 Token 刷新机制

// src/bridge/bridgeMain.ts:279-313
const tokenRefresh = createTokenRefreshScheduler({
  getAccessToken,
  onRefresh: (sessionId, oauthToken) => {
    const handle = activeSessions.get(sessionId)
    if (v2Sessions.has(sessionId)) {
      // v2: 调用 reconnectSession 触发服务器重新分发
      api.reconnectSession(environmentId, sessionId)
    } else {
      // v1: 直接更新 access token
      handle.updateAccessToken(oauthToken)
    }
  },
})

3.5 桥接配置

// src/bridge/types.ts
export type BridgeConfig = {
  apiBaseUrl: string
  sessionIngressUrl: string
  spawnMode: 'single-session' | 'worktree' | 'same-dir'
  maxSessions: number
  sessionTimeoutMs?: number
  debugFile?: string
}

4. 第三方工具接入

4.1 工具系统架构

核心文件:

  • src/Tool.ts - 工具基类
  • src/tools.ts - 工具注册表
  • src/services/tools/toolExecution.ts - 工具执行
// src/Tool.ts
export abstract class Tool {
  name: string
  description: string
  inputSchema: z.ZodType
  outputSchema?: z.ZodType
  
  abstract prompt(params: ToolParams): string | Promise<string>
  abstract call(params: unknown, context: ToolUseContext, ...): Promise<ToolResult>
  validateInput?(params: unknown, context: ToolUseContext): ValidationResult
  isEnabled?(): boolean
}

4.2 内置工具类型

工具文件功能
BashToolsrc/tools/BashTool/BashTool.tsx执行 shell 命令
FileReadToolsrc/tools/FileReadTool/FileReadTool.ts读取文件
FileWriteToolsrc/tools/FileWriteTool/FileWriteTool.ts写入文件
FileEditToolsrc/tools/FileEditTool/FileEditTool.ts编辑文件
MCPToolsrc/tools/MCPTool/MCPTool.tsMCP 工具代理
GrepToolsrc/tools/GrepTool/GrepTool.ts文本搜索
WebFetchToolsrc/tools/WebFetchTool/WebFetchTool.tsHTTP 请求
WebSearchToolsrc/tools/WebSearchTool/WebSearchTool.ts网络搜索
AgentToolsrc/tools/AgentTool/AgentTool.tsxAgent 代理
TaskCreateToolsrc/tools/TaskCreateTool/TaskCreateTool.ts创建任务
TodoWriteToolsrc/tools/TodoWriteTool/TodoWriteTool.ts待办事项

4.3 MCP 工具桥接

MCP 工具通过 MCPTool 接入:

// src/tools/MCPTool/MCPTool.ts
export class MCPTool extends Tool {
  constructor(
    private serverName: string,
    private toolName: string,
    private client: Client,
  ) {
    super({
      name: buildMcpToolName(serverName, toolName),
      description: tool.description,
      inputSchema: tool.inputSchema,
    })
  }

  async call(params: unknown, context: ToolUseContext) {
    const result = await this.client.callTool({
      name: this.toolName,
      arguments: params,
    })
    return this.formatResult(result)
  }
}

4.4 工具权限系统

// src/utils/permissions/permissions.ts
export function hasPermissionsToUseTool(
  tool: Tool,
  context: ToolUseContext,
): Promise<PermissionResult> {
  // 检查工具是否需要权限
  // 检查用户是否已授权
  // 返回允许/拒绝/询问结果
}

4.5 工具执行流程

// src/services/tools/toolExecution.ts
export async function executeTool(
  tool: Tool,
  params: unknown,
  context: ToolUseContext,
): Promise<ToolResult> {
  // 1. 权限检查
  const permission = await hasPermissionsToUseTool(tool, context)
  if (permission.behavior === 'deny') {
    return { success: false, reason: 'Permission denied' }
  }

  // 2. 输入验证
  if (tool.validateInput) {
    const validation = await tool.validateInput(params, context)
    if (!validation.result) {
      throw new Error(validation.message)
    }
  }

  // 3. 执行工具
  const result = await tool.call(params, context, hasPermissionsToUseTool)

  // 4. 触发后置钩子
  runPostToolUseHooks(tool.name, result)

  return result
}

5. 插件生命周期管理

5.1 生命周期操作

核心文件: src/services/plugins/pluginOperations.ts

操作函数功能
安装installPluginOp()从市场安装插件
卸载uninstallPluginOp()卸载插件
启用enablePluginOp()启用插件
禁用disablePluginOp()禁用插件
更新updatePluginOp()更新到新版本

5.2 插件安装流程

// src/services/plugins/pluginOperations.ts:321-418
export async function installPluginOp(
  plugin: string,
  scope: InstallableScope = 'user',
): Promise<PluginOperationResult> {
  // 1. 解析插件标识符
  const { name: pluginName, marketplace: marketplaceName } = 
    parsePluginIdentifier(plugin)

  // 2. 搜索市场获取插件信息
  let foundPlugin: PluginMarketplaceEntry | undefined
  if (marketplaceName) {
    pluginInfo = await getPluginById(plugin)
  } else {
    // 在所有已知市场中搜索
    const marketplaces = await loadKnownMarketplacesConfig()
    for (const [mktName, mktConfig] of Object.entries(marketplaces)) {
      const marketplace = await getMarketplace(mktName)
      const pluginEntry = marketplace.plugins.find(p => p.name === pluginName)
      // ...
    }
  }

  // 3. 执行安装
  const result = await installResolvedPlugin({
    pluginId,
    entry: foundPlugin,
    scope,
    marketplaceInstallLocation,
  })

  // 4. 写入配置 (设置优先原则)
  updateSettingsForSource(settingSource, {
    enabledPlugins: { [pluginId]: true },
  })

  // 5. 缓存插件
  copyPluginToVersionedCache(sourcePath, pluginId, version)
}

5.3 插件加载流程

核心文件: src/utils/plugins/pluginLoader.ts

// src/utils/plugins/pluginLoader.ts:1348-1587
export async function createPluginFromPath(
  pluginPath: string,
  source: string,
  enabled: boolean,
  fallbackName: string,
): Promise<{ plugin: LoadedPlugin; errors: PluginError[] }> {
  // 1. 加载插件清单
  const manifestPath = join(pluginPath, '.claude-plugin', 'plugin.json')
  const manifest = await loadPluginManifest(manifestPath, fallbackName, source)

  // 2. 创建基础插件对象
  const plugin: LoadedPlugin = {
    name: manifest.name,
    manifest,
    path: pluginPath,
    source,
    repository: source,
    enabled,
  }

  // 3. 自动检测组件目录
  const [commandsDirExists, agentsDirExists, skillsDirExists, outputStylesDirExists] =
    await Promise.all([
      pathExists(join(pluginPath, 'commands')),
      pathExists(join(pluginPath, 'agents')),
      pathExists(join(pluginPath, 'skills')),
      pathExists(join(pluginPath, 'output-styles')),
    ])

  // 4. 注册组件路径
  if (commandsDirExists) plugin.commandsPath = commandsPath
  if (agentsDirExists) plugin.agentsPath = agentsPath
  if (skillsDirExists) plugin.skillsPath = skillsPath
  if (outputStylesDirExists) plugin.outputStylesPath = outputStylesPath

  // 5. 加载钩子配置
  if (manifest.hooks) {
    plugin.hooksConfig = await loadPluginHooks(hooksConfigPath, plugin.name)
  }

  return { plugin, errors }
}

5.4 版本化缓存系统

// src/utils/plugins/pluginLoader.ts:139-177
export function getVersionedCachePath(
  pluginId: string,
  version: string,
): string {
  return join(
    getPluginsDirectory(),
    'cache',
    sanitizedMarketplace,
    sanitizedPlugin,
    sanitizedVersion,
  )
}

// 缓存目录格式:
// ~/.claude/plugins/cache/{marketplace}/{plugin}/{version}/

5.5 插件设置作用域

// src/services/plugins/pluginOperations.ts:71-75
export const VALID_INSTALLABLE_SCOPES = ['user', 'project', 'local'] as const

// 优先级: local > project > user

5.6 插件钩子系统

核心文件: src/utils/plugins/loadPluginHooks.ts

// src/utils/plugins/loadPluginHooks.ts:28-86
function convertPluginHooksToMatchers(
  plugin: LoadedPlugin,
): Record<HookEvent, PluginHookMatcher[]> {
  const pluginMatchers: Record<HookEvent, PluginHookMatcher[]> = {
    PreToolUse: [],
    PostToolUse: [],
    PostToolUseFailure: [],
    PermissionDenied: [],
    Notification: [],
    UserPromptSubmit: [],
    SessionStart: [],
    SessionEnd: [],
    Stop: [],
    // ... 更多事件
  }

  if (!plugin.hooksConfig) return pluginMatchers

  for (const [event, matchers] of Object.entries(plugin.hooksConfig)) {
    const hookEvent = event as HookEvent
    for (const matcher of matchers) {
      pluginMatchers[hookEvent].push({
        matcher: matcher.matcher,
        hooks: matcher.hooks,
        pluginRoot: plugin.path,
        pluginName: plugin.name,
      })
    }
  }

  return pluginMatchers
}

5.7 钩子事件类型

// src/types/hooks.ts
export type HookEvent = 
  | 'PreToolUse'
  | 'PostToolUse'
  | 'PostToolUseFailure'
  | 'PermissionDenied'
  | 'Notification'
  | 'UserPromptSubmit'
  | 'SessionStart'
  | 'SessionEnd'
  | 'Stop'
  | 'StopFailure'
  | 'SubagentStart'
  | 'SubagentStop'
  | 'PreCompact'
  | 'PostCompact'
  | 'PermissionRequest'
  | 'Setup'
  | 'TeammateIdle'
  | 'TaskCreated'
  | 'TaskCompleted'
  | 'Elicitation'
  | 'ElicitationResult'
  | 'ConfigChange'
  | 'WorktreeCreate'
  | 'WorktreeRemove'
  | 'InstructionsLoaded'
  | 'CwdChanged'
  | 'FileChanged'

5.8 插件依赖管理

// src/utils/plugins/dependencyResolver.ts
export function findReverseDependents(
  pluginId: string,
  plugins: LoadedPlugin[],
): string[] {
  // 查找依赖该插件的其他插件
}

export function verifyAndDemote(
  pluginId: string,
  plugins: LoadedPlugin[],
): void {
  // 验证依赖链,禁用无法满足依赖的插件
}

5.9 热重载支持

// src/utils/plugins/loadPluginHooks.ts:255-286
export function setupPluginHookHotReload(): void {
  settingsChangeDetector.subscribe(source => {
    if (source === 'policySettings') {
      // 检测插件相关设置的变更
      const newSnapshot = getPluginAffectingSettingsSnapshot()
      if (newSnapshot !== lastPluginSettingsSnapshot) {
        lastPluginSettingsSnapshot = newSnapshot
        // 清除缓存并重新加载
        clearPluginCache(...)
        clearPluginHookCache()
        void loadPluginHooks()
      }
    }
  })
}

6. 总结与架构图

6.1 系统架构总览

┌─────────────────────────────────────────────────────────────────┐
│                        Claude Code CLI                            │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌─────────────┐  ┌─────────────┐  ┌──────────────────────┐    │
│  │   Bridge    │  │   Plugin    │  │        MCP          │    │
│  │   System    │  │   System    │  │      Client         │    │
│  └─────────────┘  └─────────────┘  └──────────────────────┘    │
│        │                │                    │                 │
│        │                │                    │                 │
│  ┌─────▼─────┐    ┌─────▼─────┐        ┌─────▼─────┐          │
│  │  Remote   │    │ Market-   │        │  Stdio    │          │
│  │  Server   │    │ place     │        │   SSE     │          │
│  │  Sessions │    │ Manager   │        │   HTTP    │          │
│  └───────────┘    └───────────┘        │   WS      │          │
│                                        └───────────┘          │
│                                              │                │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │                     Tool System                           │  │
│  │  ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────────┐   │  │
│  │  │  Bash   │ │  File   │ │   Git   │ │    MCP      │   │  │
│  │  │  Tool   │ │  Tools  │ │  Tools  │ │   Tools     │   │  │
│  │  └─────────┘ └─────────┘ └─────────┘ └─────────────┘   │  │
│  └──────────────────────────────────────────────────────────┘  │
│                                                                 │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │                   Hook System                             │   │
│  │  PreToolUse │ PostToolUse │ SessionStart │ ...           │   │
│  └──────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

6.2 关键设计模式

模式应用场景实现方式
传输抽象支持多种 MCP 传输协议Transport 接口 + 具体实现 (StdioClientTransport, SSEClientTransport, etc.)
设置优先插件启用/禁用状态写入 settings.json → 触发缓存重建
版本化缓存插件多版本管理~/.claude/plugins/cache/{market}/{plugin}/{version}/
热插拔插件动态加载memoize 缓存 + 显式清除机制
事件驱动钩子系统HookEvent 联合类型 + HookCallback 回调
错误联合插件错误处理PluginError discriminated union
工作树隔离多会话隔离git worktree + 工作目录分离

6.3 核心文件索引

功能模块关键文件
MCP 客户端src/services/mcp/client.ts, src/services/mcp/types.ts
MCP 服务器src/entrypoints/mcp.ts
插件清单src/utils/plugins/schemas.ts
插件加载src/utils/plugins/pluginLoader.ts
插件操作src/services/plugins/pluginOperations.ts
插件钩子src/utils/plugins/loadPluginHooks.ts
桥接主循环src/bridge/bridgeMain.ts
工具系统src/Tool.ts, src/tools.ts, src/services/tools/toolExecution.ts
类型定义src/types/plugin.ts, src/types/hooks.ts

6.4 安全考虑

  1. 插件来源验证

    • 官方市场名称保护 (ALLOWED_OFFICIAL_MARKETPLACE_NAMES)
    • 同形异义攻击防护 (Unicode 字符检查)
    • GitHub 组织验证
  2. MCP 认证

    • OAuth 2.0 支持
    • Bearer Token 刷新
    • 401 错误自动重试
  3. 工具权限

    • 权限分类器
    • 文件系统访问控制
    • 命令执行白名单
  4. 路径安全

    • 版本化缓存防止路径遍历
    • 符号链接解析与验证
    • 插件目录隔离

文档生成时间: 2026-04-03 分析深度: P9 研究级