AI Agent 协议演进:从 MCP 到 ACP 的架构对比与未来展望

1,106 阅读26分钟

Multi-Agent 协作的基石:协议标准化探索之路

基于 Google Gemini CLI 和 OpenAI Codex 源码的深度技术剖析

源码版本说明 本文基于以下版本的源码分析:

  • Gemini CLI: v0.10.0-nightly (2025-10-13)
  • Codex CLI: v0.2.0-alpha.2 (2025-11-25)
  • MCP 协议: 2025-06-18 规范

摘要

  • 随着 AI Agent 的快速发展,如何让不同的 Agent 之间高效协作、如何标准化 Agent 与外部工具的交互,已成为业界关注的焦点。
  • 本文通过深入分析 Google Gemini CLIOpenAI Codex 的源码实现,对比两大主流协议——MCP (Model Context Protocol)ACP (Agent Context Protocol) 的设计理念、技术架构和应用场景,并探讨 AI Agent 协议的未来发展方向。

一、协议背景:为什么需要标准化?

1.1 当前 AI Agent 生态的痛点

在协议标准化之前,AI Agent 面临以下核心挑战:

痛点描述影响
孤岛效应每个 Agent 使用私有协议,无法互操作无法构建 Multi-Agent 系统
工具集成困难每个工具需要为不同 Agent 重复开发适配器开发成本高,生态碎片化
状态不可恢复会话状态无法持久化或跨系统传递用户体验差,无法长期任务
安全性缺失缺乏统一的权限控制和审计机制企业级部署存在风险

1.2 协议标准化的价值

graph TB
    subgraph before["标准化前:N × M 问题"]
        A1["Agent1"] --> T1A["Tool1 (适配器 1-1)"]
        A1 --> T2A["Tool2 (适配器 1-2)"]
        A1 --> T3A["Tool3 (适配器 1-3)"]

        A2["Agent2"] --> T1B["Tool1 (适配器 2-1)"]
        A2 --> T2B["Tool2 (适配器 2-2)"]
        A2 --> T3B["Tool3 (适配器 2-3)"]

        style before fill:#ffebee,stroke:#c62828
    end

    subgraph after["标准化后:N + M 问题"]
        Agent1["Agent1"] --> Protocol["MCP/ACP 协议层"]
        Agent2["Agent2"] --> Protocol
        Agent3["Agent3"] --> Protocol

        Protocol --> Tool1["Tool1"]
        Protocol --> Tool2["Tool2"]
        Protocol --> Tool3["Tool3"]

        style after fill:#e8f5e9,stroke:#2e7d32
        style Protocol fill:#fff3e0,stroke:#e65100
    end

对比结果:

  • 标准化前: 需要 N × M 个适配器 (每个 Agent 为每个 Tool 开发专用适配器)
  • 标准化后: 仅需 N + M 个适配器 (Agent 实现协议 + Tool 实现协议)

二、MCP (Model Context Protocol) 深度解析

2.1 MCP 协议概述

MCP 由 Anthropic 提出,是一个专注于 Agent 与外部工具/资源交互 的标准协议。

核心设计理念:

  • 📦 资源抽象: 将外部系统(数据库、API、文件系统)抽象为统一的 Resource
  • 🔧 工具调用: 标准化的工具发现、调用和响应流程
  • 🔌 传输无关: 支持 stdio、SSE、HTTP 等多种传输方式
  • 🔐 权限控制: 内置的工具执行审批机制

协议版本: 2025-06-18 (来源: Codex mcp-types/src/lib.rs)

2.2 Gemini CLI 的 MCP 实现架构

核心组件:
// packages/core/src/tools/mcp-client.ts
export class McpClient {
  private client: Client;                    // MCP SDK Client
  private transport: Transport;              // 传输层 (stdio/SSE/HTTP)
  private status: MCPServerStatus;           // 连接状态

  async connect(): Promise<void> {
    // 1. 建立传输连接
    this.transport = createTransport(this.serverConfig);

    // 2. 初始化 MCP Client
    this.client = new Client({
      name: 'gemini-cli',
      version: '0.10.0'
    }, {
      capabilities: {
        roots: { listChanged: true },
        sampling: {}
      }
    });

    // 3. 连接到 MCP Server
    await this.client.connect(this.transport);
  }

  async discover(): Promise<void> {
    // 发现工具
    const tools = await this.client.listTools();

    // 发现资源
    const resources = await this.client.listResources();

    // 发现 Prompts
    const prompts = await this.client.listPrompts();
  }
}
工具调用流程:
// packages/core/src/tools/mcp-tool.ts
class DiscoveredMCPToolInvocation {
  async execute(signal: AbortSignal): Promise<ToolResult> {
    // 1. 检查是否需要用户批准
    const confirmationDetails = await this.shouldConfirmExecute(signal);
    if (confirmationDetails) {
      await this.waitForUserApproval(confirmationDetails);
    }

    // 2. 调用 MCP Tool
    const functionCalls: FunctionCall[] = [{
      name: this.serverToolName,
      args: this.params
    }];

    const rawResponseParts = await this.mcpTool.callToolBatch(
      functionCalls,
      signal
    );

    // 3. 处理响应
    return this.parseToolResponse(rawResponseParts);
  }
}

2.3 Codex 的 MCP 实现架构

核心组件 (基于 Rust):
// codex-rs/core/src/mcp_connection_manager.rs
pub struct McpConnectionManager {
    clients: HashMap<String, AsyncManagedClient>,
    elicitation_requests: ElicitationRequestManager,
    tool_timeout: Duration,
}

impl McpConnectionManager {
    pub async fn connect_server(
        &self,
        server_name: String,
        config: McpServerConfig
    ) -> Result<()> {
        // 1. 创建 RmcpClient (Rust MCP Client)
        let client = RmcpClient::new(
            Implementation {
                name: "codex".to_string(),
                version: env!("CARGO_PKG_VERSION").to_string(),
            },
            ClientCapabilities {
                roots: Some(RootsCapability { list_changed: true }),
                sampling: Some(SamplingCapability {}),
            },
        );

        // 2. 建立传输连接
        let transport = match &config.transport {
            StdioTransport => create_stdio_transport(config),
            SseTransport => create_sse_transport(config),
        };

        await client.connect(transport)?;

        // 3. 列举并限定工具
        let tools = client.list_tools().await?;
        let qualified_tools = self.qualify_tools(server_name, tools);

        Ok(())
    }
}
工具名称限定 (Fully Qualified Names):
// codex-rs/core/src/mcp_connection_manager.rs
const MCP_TOOL_NAME_DELIMITER: &str = "__";
const MAX_TOOL_NAME_LENGTH: usize = 64;

fn qualify_tools(tools: Vec<ToolInfo>) -> HashMap<String, ToolInfo> {
    let mut qualified_tools = HashMap::new();

    for tool in tools {
        // 格式: mcp__<server_name>__<tool_name>
        let qualified_name = format!(
            "mcp{}{}{}{}",
            MCP_TOOL_NAME_DELIMITER,
            tool.server_name,
            MCP_TOOL_NAME_DELIMITER,
            tool.tool_name
        );

        // 超长则使用 SHA1 截断
        if qualified_name.len() > MAX_TOOL_NAME_LENGTH {
            let hash = sha1::Sha1::digest(qualified_name.as_bytes());
            qualified_name = format!("{}_{:x}",
                &qualified_name[..48],
                hash
            );
        }

        qualified_tools.insert(qualified_name, tool);
    }

    qualified_tools
}

2.4 MCP 协议消息示例

工具列表请求:
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/list",
  "params": {}
}
工具列表响应:
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": [
      {
        "name": "read_file",
        "description": "Read contents of a file",
        "inputSchema": {
          "type": "object",
          "properties": {
            "path": { "type": "string" }
          },
          "required": ["path"]
        }
      }
    ]
  }
}
工具调用请求:
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "read_file",
    "arguments": {
      "path": "/etc/hosts"
    }
  }
}
工具调用响应:
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "127.0.0.1 localhost\n::1 localhost"
      }
    ],
    "isError": false
  }
}

三、ACP (Agent Client Protocol) 官方标准深度解析

3.1 ACP 协议概述

ACP (Agent Client Protocol) 是由 Zed Industries2025 年 8 月正式发布的开放标准,旨在标准化代码编辑器/IDE 与 AI 编码代理之间的通信

📖 官方资源

核心定位: ACP 类似于 LSP (Language Server Protocol) 在语言服务器领域的作用,解决了 Agent-Editor 集成的 N×M 问题

graph LR
    subgraph before["ACP 之前:N × M 集成问题"]
        E1["Editor1"] --> A1A["Agent1 (定制集成)"]
        E1 --> A2A["Agent2 (定制集成)"]
        E1 --> A3A["Agent3 (定制集成)"]

        E2["Editor2"] --> A1B["Agent1 (重复开发)"]
        E2 --> A2B["Agent2 (重复开发)"]

        style before fill:#ffebee,stroke:#c62828
    end

    subgraph after["ACP 之后:N + M 标准化"]
        Editor1["Editor1"] --> ACP["ACP 协议层"]
        Editor2["Editor2"] --> ACP
        Editor3["Editor3"] --> ACP

        ACP --> Agent1["Agent1"]
        ACP --> Agent2["Agent2"]
        ACP --> Agent3["Agent3"]

        style after fill:#e8f5e9,stroke:#2e7d32
        style ACP fill:#e3f2fd,stroke:#1565c0
    end

核心设计理念:

  • 📝 标准化通信: 基于 JSON-RPC 2.0,使用 stdio 传输
  • 🔌 即插即用: 任何支持 ACP 的编辑器都能使用任何 ACP 代理
  • 🎯 代理自主性: 代理作为编辑器的子进程运行,可自主修改代码
  • 🔐 权限控制: 明确的权限请求机制(文件系统、终端等)
  • 🔄 会话管理: 支持会话创建、加载、状态追踪
  • 📊 能力协商: 初始化时协商双方支持的功能

3.2 ACP 协议架构

通信模型

ACP 遵循 JSON-RPC 2.0 规范,定义了两种消息类型:

消息类型描述是否需要响应
Methods请求-响应对,期望返回结果或错误✅ 是
Notifications单向消息,用于事件通知❌ 否
角色定义
// Agent:使用生成式 AI 自主修改代码的程序
interface Agent {
  // === 基线方法(必须实现) ===
  initialize(): InitializeResult;           // 初始化和能力协商
  authenticate?(): AuthResult;              // 身份验证(可选)
  'session/new'(): SessionId;              // 创建新会话
  'session/prompt'(msg: Message): void;    // 接收用户提示词

  // === 可选方法 ===
  'session/load'?(id: string): Session;    // 加载已有会话
  'session/set_mode'?(mode: string): void; // 设置模式(如 edit/chat)

  // === 通知 ===
  'session/cancel'(): void;                // 取消当前操作
}

// Client:提供用户界面的代码编辑器/IDE
interface Client {
  // === 基线方法(必须实现) ===
  'session/request_permission'(req: PermissionRequest): PermissionResult;

  // === 可选方法(根据能力) ===
  'fs/read_text_file'?(path: string): string;
  'fs/write_text_file'?(path: string, content: string): void;
  'terminal/create'?(cmd: string): TerminalId;
  'terminal/output'?(id: TerminalId): TerminalOutput;

  // === 通知 ===
  'session/update'(update: SessionUpdate): void;  // 会话状态更新
}

3.3 ACP 核心流程

1. 初始化流程
// Client → Agent
{
  "jsonrpc": "2.0",
  "id": 0,
  "method": "initialize",
  "params": {
    "protocolVersion": 1,
    "clientCapabilities": {
      "fs": {
        "readTextFile": true,
        "writeTextFile": true
      },
      "terminal": true
    },
    "clientInfo": {
      "name": "vscode",
      "title": "Visual Studio Code",
      "version": "1.95.0"
    }
  }
}

// Agent → Client
{
  "jsonrpc": "2.0",
  "id": 0,
  "result": {
    "protocolVersion": 1,
    "agentCapabilities": {
      "loadSession": true,
      "promptCapabilities": {
        "image": true,
        "audio": false,
        "embeddedContext": true
      },
      "mcp": {
        "http": true,
        "sse": false
      }
    },
    "agentInfo": {
      "name": "claude-agent",
      "title": "Claude Code Agent",
      "version": "1.0.0"
    },
    "authMethods": []
  }
}

关键要求:

  • 🔢 协议版本协商: Client 提供支持的最新版本,Agent 响应选定版本
  • 🎛️ 能力声明: 双方明确声明支持的功能(文件系统、终端、MCP 等)
  • ⚙️ 向后兼容: 未声明的能力视为不支持
2. 会话管理流程
// 创建新会话
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "session/new",
  "params": {
    "workspaceRoot": "/Users/pojian/code/project",
    "capabilities": {
      "edit": true,
      "execute": true
    }
  }
}

// 响应
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "sessionId": "sess_abc123",
    "state": "ready"
  }
}
3. 提示词交互流程
// Client → Agent: 发送用户提示词
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "session/prompt",
  "params": {
    "sessionId": "sess_abc123",
    "message": {
      "parts": [
        {
          "kind": "text",
          "text": "重构这个函数以提高性能"
        },
        {
          "kind": "resource_link",
          "uri": "file:///Users/pojian/code/project/src/utils.ts",
          "lineRange": { "start": 10, "end": 25 }
        }
      ]
    }
  }
}

// Agent → Client: 实时状态更新(通知)
{
  "jsonrpc": "2.0",
  "method": "session/update",
  "params": {
    "sessionId": "sess_abc123",
    "update": {
      "kind": "agent_message_chunk",
      "text": "我来分析这个函数的性能瓶颈..."
    }
  }
}

// Agent → Client: 请求权限
{
  "jsonrpc": "2.0",
  "id": 100,
  "method": "session/request_permission",
  "params": {
    "sessionId": "sess_abc123",
    "permission": {
      "kind": "file_write",
      "path": "/Users/pojian/code/project/src/utils.ts",
      "preview": "--- a/utils.ts\n+++ b/utils.ts\n..."
    }
  }
}

// Client → Agent: 权限响应
{
  "jsonrpc": "2.0",
  "id": 100,
  "result": {
    "granted": true
  }
}

// Agent → Client: 完成状态
{
  "jsonrpc": "2.0",
  "method": "session/update",
  "params": {
    "sessionId": "sess_abc123",
    "update": {
      "kind": "state_change",
      "state": "completed"
    }
  }
}

3.4 ACP 能力系统

Client 能力
能力域能力描述关联方法
文件系统fs.readTextFile读取文本文件fs/read_text_file
fs.writeTextFile写入文本文件fs/write_text_file
终端terminal执行和管理 Shell 命令terminal/* 全系列方法
Agent 能力
能力域能力描述
会话loadSession支持加载已有会话
提示词image支持图像输入
audio支持音频输入
embeddedContext支持嵌入式上下文资源
MCPhttp支持 HTTP 传输的 MCP 服务器
sse支持 SSE 传输的 MCP 服务器(已弃用)

3.5 ACP 协议约定

// 关键约定
const ACP_CONVENTIONS = {
  // 1. 路径要求
  filePaths: "MUST be absolute",  // 所有文件路径必须是绝对路径

  // 2. 行号约定
  lineNumbers: "1-based",  // 行号从 1 开始

  // 3. 文本格式
  textFormat: "Markdown",  // 默认使用 Markdown 格式

  // 4. 扩展机制
  customMethods: "prefix with underscore (_method_name)",
  customData: "use _meta field",

  // 5. 错误处理
  errorHandling: "JSON-RPC 2.0 standard (code + message)"
};

四、A2A (Agent-to-Agent) 深度剖析:Multi-Agent 系统的探索

4.0 A2A 概述与设计哲学

A2A (Agent-to-Agent Protocol) 是 Google Gemini CLI 团队提出的实验性协议,专注于解决 Multi-Agent 系统中的核心挑战:如何让不同的 Agent 无缝协作、状态同步和任务编排。

🎯 核心价值主张

虽然 ACP 解决了 Editor ↔ Agent 的标准化,MCP 解决了 Agent ↔ Tools 的标准化,但 Agent ↔ Agent 的协作仍是空白地带。A2A 正是为填补这一空白而生。

A2A 的三大设计支柱
graph TD
    A2A["A2A 设计哲学"]

    A2A --> P1["1️⃣ Event-Driven Architecture<br/>事件驱动"]
    A2A --> P2["2️⃣ Stateful Task Management<br/>有状态任务管理"]
    A2A --> P3["3️⃣ HTTP + SSE Hybrid Transport<br/>混合传输"]

    P1 --> P1A["通过 EventBus 实现松耦合"]
    P1 --> P1B["Agent 只需订阅感兴趣的事件"]
    P1 --> P1C["支持流式和实时状态更新"]

    P2 --> P2A["任务可持久化和恢复"]
    P2 --> P2B["完整的状态转换历史"]
    P2 --> P2C["支持长时间运行的复杂任务"]

    P3 --> P3A["HTTP 用于 Request/Response"]
    P3 --> P3B["SSE 用于实时事件推送"]
    P3 --> P3C["天然支持跨网络的 Agent 协作"]

    style A2A fill:#e1f5fe,stroke:#01579b,stroke-width:3px
    style P1 fill:#fff3e0,stroke:#e65100
    style P2 fill:#f3e5f5,stroke:#4a148c
    style P3 fill:#e8f5e9,stroke:#1b5e20
为什么需要 A2A?
场景传统方案的痛点A2A 的解决方案
Multi-Agent 协作每个 Agent 使用私有 API,无法互操作统一的 AgentCard + Task API
长时间任务同步调用易超时,状态无法追踪异步 Task + 状态机管理
实时反馈只能轮询或等待最终结果SSE 流式推送中间状态
Agent 发现硬编码 Agent 地址和能力AgentCard 动态发现和能力协商

4.1 A2A 核心架构组件

1. AgentCard - Agent 身份与能力声明
// packages/a2a-server/src/http/app.ts
const agentCard: AgentCard = {
  name: 'Gemini SDLC Agent',
  description: 'Code generation agent with streaming support',
  url: 'http://localhost:41242/',
  protocolVersion: '0.3.0',

  capabilities: {
    streaming: true,              // 支持流式输出
    pushNotifications: false,     // 不支持推送
    stateTransitionHistory: true  // 支持状态历史
  },

  skills: [
    {
      id: 'code_generation',
      name: 'Code Generation',
      description: 'Generate code from natural language',
      tags: ['code', 'development'],
      inputModes: ['text'],
      outputModes: ['text'],
      examples: [
        'Write a Python function to calculate fibonacci',
        'Create a REST API with authentication'
      ]
    }
  ]
};

AgentCard 的关键字段解析:

字段作用示例值
nameAgent 的唯一标识符"Gemini SDLC Agent"
urlAgent 的 HTTP 端点"http://localhost:41242/"
protocolVersionA2A 协议版本"0.3.0"
capabilities.streaming是否支持 SSE 流式输出true
capabilities.stateTransitionHistory是否保留状态历史true
skills[]Agent 擅长的技能列表代码生成、测试、重构等
2. 任务状态机 - 生命周期管理
// 基于 @a2a-js/sdk 的 TaskState
type TaskState =
  | 'submitted'       // 已提交
  | 'working'         // 执行中
  | 'input-required'  // 等待输入
  | 'completed'       // 已完成
  | 'failed'          // 失败
  | 'canceled';       // 取消

// 状态转换流程
submitted → working → input-required → working → completed
                                    ↓
                                  failed
                                    ↓
                                 canceled

状态转换详解:

// packages/a2a-server/src/types.ts
interface TaskMetadata {
  id: string;                    // 任务唯一 ID
  contextId: string;             // 所属会话 ID
  taskState: TaskState;          // 当前状态
  model: string;                 // 使用的 LLM 模型
  mcpServers: MCPServerInfo[];   // 可用的 MCP 服务器列表
  availableTools: ToolInfo[];    // 可调用的工具列表
}

// 状态转换触发器
class Task {
  setTaskState(newState: TaskState) {
    const oldState = this.metadata.taskState;
    this.metadata.taskState = newState;

    // 记录状态历史(如果开启)
    if (this.capabilities.stateTransitionHistory) {
      this.stateHistory.push({
        from: oldState,
        to: newState,
        timestamp: Date.now(),
        reason: this.transitionReason
      });
    }

    // 触发状态变更事件
    this.eventBus.publish({
      kind: CoderAgentEvent.StateChangeEvent,
      taskId: this.id,
      oldState,
      newState,
      timestamp: Date.now()
    });
  }
}

关键状态说明:

状态含义典型持续时间下一状态
submitted任务已提交但未开始执行0-50msworking
workingLLM 正在生成响应或执行工具调用数秒到数分钟input-required / completed / failed
input-required等待用户确认工具调用或提供额外输入取决于用户working / canceled
completed任务成功完成终态-
failed任务执行失败终态-
canceled用户主动取消终态-
3. EventBus - 事件驱动核心

A2A 的 EventBus 是整个系统的神经中枢,负责:

  • 📡 解耦组件:Agent、Task、Tool 之间通过事件通信
  • 🔄 流式传输:通过 SSE 实时推送事件到客户端
  • 📊 状态追踪:所有状态变化都通过事件记录
// packages/a2a-server/src/agent/executor.ts

// EventBus 事件类型定义
enum CoderAgentEvent {
  ToolCallConfirmationEvent = 'tool-call-confirmation',  // 请求工具确认
  ToolCallUpdateEvent = 'tool-call-update',              // 工具调用状态更新
  TextContentEvent = 'text-content',                     // LLM 生成的文本
  StateChangeEvent = 'state-change',                     // 任务状态变更
  ThoughtEvent = 'thought',                              // Agent 的思考过程
}

// EventBus 实现
class ExecutionEventBus {
  private listeners = new Map<string, Set<EventListener>>();
  private sseClients = new Set<SSEClient>();

  // 发布事件
  publish(event: CoderAgentMessage) {
    // 1. 通知本地监听器
    const listeners = this.listeners.get(event.kind) || new Set();
    listeners.forEach(listener => listener(event));

    // 2. 通过 SSE 推送给客户端
    this.sseClients.forEach(client => {
      client.send({
        event: event.kind,
        data: JSON.stringify(event)
      });
    });

    // 3. 持久化到数据库(可选)
    if (this.persistenceEnabled) {
      this.saveEvent(event);
    }
  }

  // 订阅事件
  subscribe(eventType: CoderAgentEvent, listener: EventListener) {
    if (!this.listeners.has(eventType)) {
      this.listeners.set(eventType, new Set());
    }
    this.listeners.get(eventType)!.add(listener);
  }

  // 添加 SSE 客户端
  addSSEClient(client: SSEClient) {
    this.sseClients.add(client);

    // 发送历史事件(如果需要)
    if (client.wantsHistory) {
      this.replayEvents(client);
    }
  }
}

EventBus 流式工作流程:

graph TB
    subgraph LLM["LLM Stream 处理流程"]
        Stream["LLM Stream"] --> Chunk1["Chunk 1"]
        Stream --> Chunk2["Chunk 2"]
        Stream --> Chunk3["Chunk 3"]
        Stream --> ToolCall["Tool Call"]

        Chunk1 --> Publish1["EventBus.publish(TextContent)"]
        Chunk2 --> Publish1
        Chunk3 --> Publish1
        ToolCall --> Publish1

        Publish1 --> Local["Local Listeners"]
        Publish1 --> SSE["SSE Clients<br/>(实时推送)"]
        Publish1 --> Persist["Persistence Layer"]

        style LLM fill:#e3f2fd,stroke:#1565c0
    end

    subgraph Tool["Tool Execution 处理流程"]
        ToolExec["Tool Execution"] --> ConfReq["Confirmation Request"]
        ConfReq --> Publish2["EventBus.publish()"]

        UserApproval["User Approval"] --> SetState["setState(working)"]

        ToolResult["Tool Result"] --> Publish3["EventBus.publish()"]

        style Tool fill:#fff3e0,stroke:#e65100
    end

    style Publish1 fill:#c8e6c9,stroke:#2e7d32
    style Publish2 fill:#c8e6c9,stroke:#2e7d32
    style Publish3 fill:#c8e6c9,stroke:#2e7d32
4. 核心执行器 - 编排引擎
// packages/a2a-server/src/agent/executor.ts
export class CoderAgentExecutor implements AgentExecutor {
  async execute(requestContext: RequestContext, eventBus: ExecutionEventBus) {
    const { userMessage, task } = requestContext;

    // 1. 获取或创建任务
    let wrapper = this.tasks.get(taskId) || await this.createTask(taskId);

    // 2. 设置状态为 working
    wrapper.task.setTaskState('working');
    eventBus.publish({
      kind: 'status-update',
      taskId,
      status: { state: 'working' },
      final: false
    });

    // 3. 调用 LLM
    const agentEvents = wrapper.task.geminiClient.sendMessageStream(
      userMessage.parts,
      abortSignal
    );

    // 4. 处理 Agent 响应
    for await (const event of agentEvents) {
      if (event.type === 'tool_call_request') {
        // 调度工具执行
        await wrapper.task.scheduleToolCalls(event.toolCalls);
      } else if (event.type === 'content') {
        // 发布文本内容
        eventBus.publish({
          kind: 'status-update',
          status: {
            state: 'working',
            message: { parts: [{ kind: 'text', text: event.content }] }
          }
        });
      }
    }

    // 5. 等待工具执行完成
    await wrapper.task.waitForPendingTools();

    // 6. 设置状态为 input-required
    wrapper.task.setTaskState('input-required');
    eventBus.publish({
      kind: 'status-update',
      status: { state: 'input-required' },
      final: true
    });
  }
}

执行器的核心职责:

  1. 📝 任务生命周期管理:从 submitted 到终态的完整流程控制
  2. 🔄 流式响应处理:实时处理 LLM 的 streaming output
  3. 🛠️ 工具调度编排:管理并发的工具调用请求
  4. 📡 事件发布:将所有状态变化通过 EventBus 广播
  5. 💾 状态持久化:支持任务暂停和恢复
5. Tool Scheduling - 工具调度机制

A2A 的工具调度是其核心能力之一,支持:

  • 并发执行:多个工具可以并行调用
  • 🔄 依赖管理:自动处理工具间的依赖关系
  • ⏸️ 暂停/恢复:可以中断工具执行并稍后恢复
// packages/a2a-server/src/agent/task.ts

class Task {
  private pendingTools = new Map<string, ToolExecution>();
  private toolQueue: ToolCall[] = [];

  async scheduleToolCalls(toolCalls: ToolCall[]) {
    for (const toolCall of toolCalls) {
      const execution: ToolExecution = {
        id: toolCall.id,
        toolName: toolCall.name,
        args: toolCall.arguments,
        status: 'pending',
        startTime: null,
        endTime: null,
        result: null
      };

      this.pendingTools.set(toolCall.id, execution);

      // 检查是否需要用户确认
      if (this.shouldConfirmTool(toolCall.name)) {
        this.eventBus.publish({
          kind: CoderAgentEvent.ToolCallConfirmationEvent,
          taskId: this.id,
          toolCall: {
            id: toolCall.id,
            name: toolCall.name,
            arguments: toolCall.arguments,
            description: this.getToolDescription(toolCall.name)
          }
        });
        execution.status = 'awaiting_confirmation';
      } else {
        // 自动批准,立即执行
        this.executeToolCall(toolCall);
      }
    }
  }

  async executeToolCall(toolCall: ToolCall) {
    const execution = this.pendingTools.get(toolCall.id)!;
    execution.status = 'running';
    execution.startTime = Date.now();

    // 发布开始事件
    this.eventBus.publish({
      kind: CoderAgentEvent.ToolCallUpdateEvent,
      taskId: this.id,
      toolCallId: toolCall.id,
      status: 'running'
    });

    try {
      // 调用 MCP 工具
      const result = await this.mcpClient.callTool(
        toolCall.name,
        toolCall.arguments
      );

      execution.status = 'completed';
      execution.result = result;
      execution.endTime = Date.now();

      // 发布完成事件
      this.eventBus.publish({
        kind: CoderAgentEvent.ToolCallUpdateEvent,
        taskId: this.id,
        toolCallId: toolCall.id,
        status: 'completed',
        result: result,
        duration: execution.endTime - execution.startTime
      });

      // 从 pending 移除
      this.pendingTools.delete(toolCall.id);

    } catch (error) {
      execution.status = 'failed';
      execution.error = error.message;
      execution.endTime = Date.now();

      this.eventBus.publish({
        kind: CoderAgentEvent.ToolCallUpdateEvent,
        taskId: this.id,
        toolCallId: toolCall.id,
        status: 'failed',
        error: error.message
      });

      this.pendingTools.delete(toolCall.id);
    }
  }

  // 等待所有待处理的工具完成
  async waitForPendingTools(): Promise<void> {
    while (this.pendingTools.size > 0) {
      await new Promise(resolve => setTimeout(resolve, 100));
    }
  }
}

工具调度流程图:

graph TD
    LLM["LLM: I need to call tools A, B, C"] --> Schedule["scheduleToolCalls([A, B, C])"]

    Schedule --> ToolA["Tool A: Auto-approved"]
    Schedule --> ToolB["Tool B: Needs confirmation"]
    Schedule --> ToolC["Tool C: Auto-approved"]

    ToolA --> ExecA["executeToolCall(A)"]
    ExecA --> MCPA["MCP Server"]

    ToolB --> ConfEvent["Publish ConfirmationEvent"]
    ConfEvent --> WaitApproval["Wait for user approval"]
    WaitApproval --> ExecB["executeToolCall(B)"]
    ExecB --> MCPB["MCP Server"]

    ToolC --> ExecC["executeToolCall(C)"]
    ExecC --> MCPC["MCP Server"]

    MCPA --> Complete["All tools completed"]
    MCPB --> Complete
    MCPC --> Complete

    Complete --> Continue["LLM continues"]

    style LLM fill:#e1f5fe,stroke:#01579b
    style Schedule fill:#fff3e0,stroke:#e65100
    style ToolA fill:#c8e6c9,stroke:#2e7d32
    style ToolB fill:#ffcdd2,stroke:#c62828
    style ToolC fill:#c8e6c9,stroke:#2e7d32
    style Complete fill:#e1bee7,stroke:#6a1b9a
    style Continue fill:#e1f5fe,stroke:#01579b

    %% 注释:A 和 C 并发执行,B 需要等待确认

4.2 A2A 与 MCP 的深度集成

A2A 并非孤立协议,它巧妙地将 MCP 整合为底层工具层,形成两层协议栈

graph LR
    subgraph Layer3["Layer 3: Agent Orchestration (A2A)"]
        A3A["Agent discovery<br/>(AgentCard)"]
        A3B["Task management<br/>(TaskState)"]
        A3C["Event streaming<br/>(EventBus + SSE)"]

        style Layer3 fill:#e1f5fe,stroke:#01579b,stroke-width:2px
    end

    subgraph Layer2["Layer 2: Tool Interface (MCP)"]
        A2A["Tool discovery<br/>(tools/list)"]
        A2B["Tool execution<br/>(tools/call)"]
        A2C["Resource access<br/>(resources/read)"]

        style Layer2 fill:#fff3e0,stroke:#e65100,stroke-width:2px
    end

    subgraph Layer1["Layer 1: Transport Layer"]
        A1A["JSON-RPC 2.0<br/>(for MCP)"]
        A1B["HTTP + SSE<br/>(for A2A)"]
        A1C["stdio / HTTP / SSE"]

        style Layer1 fill:#f3e5f5,stroke:#4a148c,stroke-width:2px
    end

    Layer3 --> Layer2
    Layer2 --> Layer1

    style A3A fill:#b3e5fc,stroke:#01579b
    style A3B fill:#b3e5fc,stroke:#01579b
    style A3C fill:#b3e5fc,stroke:#01579b
    style A2A fill:#ffe0b2,stroke:#e65100
    style A2B fill:#ffe0b2,stroke:#e65100
    style A2C fill:#ffe0b2,stroke:#e65100

集成实现细节:

// packages/a2a-server/src/agent/task.ts

class Task {
  private mcpClients = new Map<string, McpClient>();

  async initializeMCPServers(serverConfigs: MCPServerConfig[]) {
    for (const config of serverConfigs) {
      const client = new McpClient(config);

      // 连接到 MCP Server
      await client.connect();

      // 获取工具列表
      const tools = await client.listTools();

      // 注册到任务的可用工具
      for (const tool of tools) {
        const qualifiedName = `mcp__${config.name}__${tool.name}`;
        this.availableTools.set(qualifiedName, {
          originalName: tool.name,
          serverName: config.name,
          description: tool.description,
          parameterSchema: tool.inputSchema,
          mcpClient: client
        });
      }

      this.mcpClients.set(config.name, client);
    }

    // 通知 LLM 可用的工具列表(通过 Gemini Function Calling)
    this.geminiClient.updateTools(
      Array.from(this.availableTools.values()).map(tool => ({
        name: tool.originalName,  // Gemini 看到的是原始名称
        description: tool.description,
        parameters: tool.parameterSchema
      }))
    );
  }

  async callTool(toolName: string, args: any): Promise<any> {
    // 从qualified name 解析 server 和 tool
    const [_, serverName, originalToolName] = toolName.split('__');

    const toolInfo = this.availableTools.get(toolName);
    if (!toolInfo) {
      throw new Error(`Tool ${toolName} not found`);
    }

    // 调用 MCP Server
    const result = await toolInfo.mcpClient.callTool(
      originalToolName,
      args
    );

    return result;
  }
}

工具名称转换策略:

层级工具名称说明
MCP Serverread_fileMCP 原生工具名
A2A 内部存储mcp__filesystem__read_file带命名空间的限定名
Gemini LLMread_fileLLM 看到的简化名(通过 description 区分)
用户界面"读取文件 (filesystem)"用户友好的显示名

4.3 A2A 实战案例:Multi-Agent 协作系统

场景:AI 驱动的全栈应用开发

假设我们要开发一个包含前端、后端、数据库的完整应用。传统方式是单个 Agent 完成所有工作,但使用 A2A 可以让专业 Agent 协作:

import { createAgent, AgentOrchestrator } from '@a2a-js/sdk';

// 1. 定义专业 Agent 团队
const agents = {
  // 前端专家
  frontendAgent: await createAgent({
    name: 'Frontend Specialist',
    agentUrl: 'http://localhost:8001/api',
    skills: ['react', 'typescript', 'css', 'ui-design']
  }),

  // 后端专家
  backendAgent: await createAgent({
    name: 'Backend Specialist',
    agentUrl: 'http://localhost:8002/api',
    skills: ['nodejs', 'express', 'api-design', 'authentication']
  }),

  // 数据库专家
  databaseAgent: await createAgent({
    name: 'Database Specialist',
    agentUrl: 'http://localhost:8003/api',
    skills: ['postgresql', 'schema-design', 'migrations', 'optimization']
  }),

  // 测试专家
  testAgent: await createAgent({
    name: 'QA Specialist',
    agentUrl: 'http://localhost:8004/api',
    skills: ['jest', 'e2e-testing', 'test-strategy']
  })
};

// 2. 创建编排器
const orchestrator = new AgentOrchestrator(agents);

// 3. 定义工作流
const workflow = orchestrator.defineWorkflow({
  name: 'Build E-Commerce App',

  steps: [
    {
      id: 'design-schema',
      agent: 'databaseAgent',
      task: '设计电商应用的数据库 schema,包括用户、产品、订单表',
      dependencies: []
    },
    {
      id: 'create-migrations',
      agent: 'databaseAgent',
      task: '创建数据库迁移文件',
      dependencies: ['design-schema']
    },
    {
      id: 'build-api',
      agent: 'backendAgent',
      task: '基于数据库 schema 构建 REST API,包括 CRUD 和认证',
      dependencies: ['design-schema'],
      inputs: {
        schema: '{{ steps.design-schema.result.schema }}'
      }
    },
    {
      id: 'build-frontend',
      agent: 'frontendAgent',
      task: '构建 React 前端,连接到 API',
      dependencies: ['build-api'],
      inputs: {
        apiSpec: '{{ steps.build-api.result.openapi }}'
      }
    },
    {
      id: 'write-tests',
      agent: 'testAgent',
      task: '编写端到端测试',
      dependencies: ['build-frontend', 'build-api']
    }
  ]
});

// 4. 执行工作流(支持流式监控)
const execution = await orchestrator.execute(workflow);

// 5. 订阅事件,实时监控进度
execution.on('step-started', ({ stepId, agent }) => {
  console.log(`✨ ${agent} 开始工作: ${stepId}`);
});

execution.on('step-progress', ({ stepId, progress }) => {
  console.log(`⏳ ${stepId}: ${progress.message}`);
});

execution.on('step-completed', ({ stepId, result, duration }) => {
  console.log(`✅ ${stepId} 完成 (耗时: ${duration}ms)`);
  console.log(`   输出: ${result.summary}`);
});

execution.on('error', ({ stepId, error }) => {
  console.error(`❌ ${stepId} 失败: ${error.message}`);
});

// 等待完成
const finalResult = await execution.complete();

console.log('🎉 全栈应用开发完成!');
console.log(`总耗时: ${finalResult.totalDuration}ms`);
console.log(`创建的文件数: ${finalResult.filesCreated}`);

工作流执行时间线:

Time  Agent              Event
────  ────────────────  ──────────────────────────────────
00:00 DatabaseAgent     ✨ 开始设计 schema
00:05 DatabaseAgent       ⏳ 正在分析电商领域模型...
00:15 DatabaseAgent       ⏳ 生成用户表 schema...
00:25 DatabaseAgent       ⏳ 生成产品表 schema...
00:35 DatabaseAgent     ✅ Schema 设计完成

00:35 DatabaseAgent     ✨ 开始创建迁移文件
00:38 DatabaseAgent       ⏳ 生成 SQL migration...
00:42 DatabaseAgent     ✅ 迁移文件创建完成

00:42 BackendAgent      ✨ 开始构建 API
00:45 BackendAgent        ⏳ 设置 Express server...
00:50 BackendAgent        ⏳ 生成 CRUD endpoints...
01:05 BackendAgent        ⏳ 实现 JWT 认证...
01:20 BackendAgent      ✅ API 构建完成

01:20 FrontendAgent     ✨ 开始构建前端
01:25 FrontendAgent       ⏳ 创建 React 项目结构...
01:35 FrontendAgent       ⏳ 生成组件代码...
01:50 FrontendAgent       ⏳ 集成 API client...
02:10 FrontendAgent     ✅ 前端构建完成

02:10 TestAgent         ✨ 开始编写测试
02:15 TestAgent           ⏳ 生成 E2E 测试场景...
02:30 TestAgent           ⏳ 编写测试代码...
02:45 TestAgent         ✅ 测试完成

🎉 全栈应用开发完成!
总耗时: 165秒
创建的文件数: 47
测试通过率: 100%

4.4 A2A 的核心优势

与其他协议相比,A2A 在以下方面具有独特优势:

优势具体表现对比 ACP/MCP
🔄 真正的流式体验通过 SSE 实时推送 LLM 生成的每个 tokenACP 也支持流式,MCP 不支持
📊 完整状态管理6 种状态 + 状态转换历史ACP 有会话状态,MCP 无状态
🔌 Multi-Agent 支持原生支持 Agent 发现和协作ACP 专注 Editor-Agent,MCP 无此概念
🛠️ MCP 集成无缝复用整个 MCP 生态的工具ACP 也支持 MCP,但未深度集成
⚡ 并发工具调用可同时执行多个工具,大幅提升效率MCP 也支持,但需要自行实现并发控制
💾 任务持久化支持暂停任务,稍后从断点恢复ACP 支持 session 加载,MCP 无此能力
🎯 事件驱动架构EventBus 解耦组件,易于扩展ACP 使用通知,但没有统一 EventBus

A2A 的适用场景:

推荐使用 A2A:

  • 需要多个 Agent 协作完成复杂任务
  • 任务执行时间较长(>30秒),需要中间状态反馈
  • 需要支持任务暂停和恢复
  • 需要完整的审计日志和状态历史
  • 希望复用 MCP 生态的工具

不推荐使用 A2A:

  • 简单的单 Agent 场景(用 ACP 更轻量)
  • 对性能要求极高的场景(Rust 实现的 Codex 更快)
  • 只需要工具调用,不需要 Agent 协作(直接用 MCP)
  • 低延迟要求(<100ms)的实时场景

4.5 Codex 的 SQ/EQ 协议设计

⚠️ 注意: Codex 的实现与 ACP 官方标准也不同,采用了独特的 SQ/EQ (Submission Queue / Event Queue) 模式。

Codex 的协议设计:

// codex-rs/protocol/src/protocol.rs

/// Submission Queue - 用户提交的操作
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Submission {
    pub id: String,
    pub op: Op,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum Op {
    /// 用户输入
    UserTurn {
        items: Vec<UserInput>,
        cwd: PathBuf,
        approval_policy: AskForApproval,
        sandbox_policy: SandboxPolicy,
        model: String,
    },

    /// 中断当前任务
    Interrupt,

    /// 批准工具执行
    ExecApproval {
        id: String,
        decision: ReviewDecision,
    },

    /// 批准代码补丁
    PatchApproval {
        id: String,
        decision: ReviewDecision,
    },

    /// 解决 MCP 授权请求
    ResolveElicitation {
        server_name: String,
        request_id: RequestId,
        decision: ElicitationAction,
    },
}

/// Event Queue - Agent 发出的事件
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Event {
    pub id: String,
    pub msg: EventMsg,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum EventMsg {
    /// Agent 消息
    AgentMessage(AgentMessageEvent),

    /// 工具调用请求
    ToolCall(ToolCallEvent),

    /// 需要批准执行
    ExecApprovalRequest(ExecApprovalRequestEvent),

    /// 需要批准补丁
    ApplyPatchApprovalRequest(ApplyPatchApprovalRequestEvent),

    /// Turn 完成
    TurnComplete(TurnCompleteEvent),

    /// Turn 中止
    TurnAborted(TurnAbortedEvent),
}

4.3 协议关系梳理:ACP vs A2A vs Codex

为避免混淆,这里明确三者的定位和关系:

协议/实现定位标准化状态主要用途实现方
ACP (Agent Client Protocol)官方标准协议✅ 开放标准Editor ↔ Agent 通信Zed Industries (2025-08)
A2A (Agent-to-Agent)实验性实现🔬 非标准Agent ↔ Agent 协作Google Gemini CLI
Codex SQ/EQ实验性实现🔬 非标准User ↔ Agent 交互OpenAI/社区
关键区别
graph TB
    subgraph Official["官方标准"]
        MCP["MCP (Anthropic)<br/>Agent ↔ Tools"]
        ACP["ACP (Zed)<br/>Editor ↔ Agent"]

        style Official fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px
        style MCP fill:#a5d6a7,stroke:#388e3c
        style ACP fill:#a5d6a7,stroke:#388e3c
    end

    subgraph Vendor["厂商实现 (实验性)"]
        A2A["A2A (Google)<br/>Agent ↔ Agent"]
        Codex["Codex SQ/EQ (社区)<br/>User ↔ Agent"]

        style Vendor fill:#fff3e0,stroke:#e65100,stroke-width:2px
        style A2A fill:#ffcc80,stroke:#f57c00
        style Codex fill:#ffcc80,stroke:#f57c00
    end

为什么会有这种现象?

  1. ACP 发布时间线:ACP 在 2025 年 8 月才正式发布,而 Gemini CLI 和 Codex 的开发更早,当时还没有统一标准
  2. 不同的关注点
    • ACP 关注 编辑器集成(类似 LSP)
    • A2A 关注 Agent 编排(Multi-Agent 系统)
    • Codex SQ/EQ 关注 用户体验(审批流程和安全)
  3. 演进方向:预计未来这些实现可能会向 ACP 标准靠拢或互补

对开发者的建议

  • ✅ 如果开发编辑器插件,优先使用 ACP 官方标准
  • 🔬 如果研究 Multi-Agent 系统,可以参考 A2A 的设计思路
  • 🔐 如果注重安全审批,可以借鉴 Codex 的 Approval 机制

五、核心差异对比:ACP vs MCP vs 各家实现

5.1 协议定位对比

graph TB
    subgraph AppLayer["应用层 - A2A (Agent-to-Agent)"]
        App1["Gemini A2A Server"]
        App2["Agent 协作编排"]
        App3["任务状态管理"]

        style AppLayer fill:#e1f5fe,stroke:#01579b,stroke-width:2px
    end

    subgraph AgentLayer["Agent层 - Codex SQ/EQ Protocol"]
        Agent1["Submission Queue<br/>(用户 → Agent)"]
        Agent2["Event Queue<br/>(Agent → 用户)"]
        Agent3["审批流程 (Approval)"]

        style AgentLayer fill:#f3e5f5,stroke:#4a148c,stroke-width:2px
    end

    subgraph ToolLayer["工具层 - MCP (Model Context Protocol)"]
        Tool1["工具发现与调用"]
        Tool2["资源访问"]
        Tool3["Prompt 管理"]

        style ToolLayer fill:#fff3e0,stroke:#e65100,stroke-width:2px
    end

    subgraph TransportLayer["传输层"]
        Trans1["stdio / SSE / HTTP / WebSocket"]

        style TransportLayer fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px
    end

    AppLayer --> AgentLayer
    AgentLayer --> ToolLayer
    ToolLayer --> TransportLayer

    style App1 fill:#b3e5fc,stroke:#01579b
    style App2 fill:#b3e5fc,stroke:#01579b
    style App3 fill:#b3e5fc,stroke:#01579b
    style Agent1 fill:#e1bee7,stroke:#6a1b9a
    style Agent2 fill:#e1bee7,stroke:#6a1b9a
    style Agent3 fill:#e1bee7,stroke:#6a1b9a
    style Tool1 fill:#ffe0b2,stroke:#e65100
    style Tool2 fill:#ffe0b2,stroke:#e65100
    style Tool3 fill:#ffe0b2,stroke:#e65100

5.2 详细对比表

维度MCPACP (官方)A2A (Gemini)Codex SQ/EQ
协议目标Agent ↔ 工具/资源Editor ↔ AgentAgent ↔ Agent用户 ↔ Agent
发布方AnthropicZed IndustriesGoogleOpenAI (社区)
协议版本2025-06-18Version 1 (2025-08)0.3.0v0.2.0-alpha
通信模式Request/ResponseRequest/Response + NotificationsEvent-Driven (SSE)Queue-Based
状态管理无状态有状态 (会话)有状态 (任务)有状态 (会话)
传输方式stdio, SSE, HTTPstdio (JSON-RPC)HTTP + SSEIn-Process Channels
权限模型ElicitationPermission RequestConfirmationApproval
流式支持❌ 不支持✅ 支持✅ 支持✅ 支持
语言绑定TS, Rust, PythonTS, Go, Rust, PythonTypeScriptRust + TS SDK
标准化程度✅ 官方标准✅ 官方标准🔬 实验性实现🔬 实验性实现

5.3 工具调用流程对比

MCP 工具调用 (同步):
User  Agent: "读取文件 /etc/hosts"
Agent  MCP Server: tools/call { name: "read_file", args: {...} }
MCP Server  Agent: { content: [...], isError: false }
Agent  User: "文件内容如下..."
A2A 工具调用 (流式):
User → Agent A: "读取并分析文件"
Agent A → EventBus: { status: 'working', message: "正在读取..." }
Agent A → Tool: read_file(...)
Tool → Agent A: (file content)
Agent A → EventBus: { status: 'working', message: "正在分析..." }
Agent A → Agent B: analyze(content)  // 可选的 Multi-Agent
Agent B → EventBus: { status: 'working', message: "分析结果..." }
EventBus → User: (流式展示每一步)
Codex SQ/EQ (异步队列):
User → SQ: Submission { op: UserTurn { text: "..." } }
Agent → EQ: Event { msg: AgentMessage { text: "正在处理..." } }
Agent → EQ: Event { msg: ToolCall { tool: "shell", cmd: "ls" } }
Agent → EQ: Event { msg: ExecApprovalRequest {...} }
User → SQ: Submission { op: ExecApproval { decision: Allow } }
Agent → EQ: Event { msg: ToolCallResult {...} }
Agent → EQ: Event { msg: TurnComplete }

六、实际应用场景

6.1 MCP 典型场景

场景 1: 统一的开发工具接入
// 配置文件: ~/.gemini/settings.json
{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_TOKEN": "${GITHUB_TOKEN}"
      }
    },
    "postgres": {
      "command": "uvx",
      "args": ["mcp-server-postgres"],
      "env": {
        "DATABASE_URL": "postgresql://..."
      }
    },
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/workspace"]
    }
  }
}

使用:

$ gemini
> @github List my open pull requests
> @postgres Run query: SELECT * FROM users WHERE active = true
> @filesystem Read file package.json
场景 2: 企业内部工具集成
// 自定义 MCP Server
import { Server } from '@modelcontextprotocol/sdk/server';

const server = new Server({
  name: 'company-internal-tools',
  version: '1.0.0'
});

server.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools: [
    {
      name: 'query_jira',
      description: 'Query JIRA tickets',
      inputSchema: {
        type: 'object',
        properties: {
          jql: { type: 'string' }
        }
      }
    },
    {
      name: 'deploy_to_k8s',
      description: 'Deploy application to Kubernetes',
      inputSchema: {
        type: 'object',
        properties: {
          namespace: { type: 'string' },
          image: { type: 'string' }
        }
      }
    }
  ]
}));

6.2 ACP 典型场景(官方标准)

场景 1: Multi-Agent 协作工作流
import { createAgent } from '@a2a-js/sdk';

// Agent 1: 代码生成专家
const codeGenAgent = await createAgent({
  agentUrl: 'http://gemini-a2a:41242'
});

// Agent 2: 代码审查专家
const codeReviewAgent = await createAgent({
  agentUrl: 'http://claude-a2a:3000'
});

// 工作流编排
async function developFeature(requirement: string) {
  // Step 1: 生成代码
  const codeTask = await codeGenAgent.createTask({
    message: {
      parts: [{ kind: 'text', text: `实现功能: ${requirement}` }]
    }
  });

  const code = await codeTask.waitForCompletion();

  // Step 2: 审查代码
  const reviewTask = await codeReviewAgent.createTask({
    message: {
      parts: [{
        kind: 'text',
        text: `审查以下代码并提供改进建议:\n${code}`
      }]
    }
  });

  const review = await reviewTask.waitForCompletion();

  // Step 3: 根据审查意见改进
  const improvedCodeTask = await codeGenAgent.createTask({
    message: {
      parts: [{
        kind: 'text',
        text: `根据审查意见改进代码:\n审查意见: ${review}\n原代码: ${code}`
      }]
    }
  });

  return await improvedCodeTask.waitForCompletion();
}
场景 2: Agent 服务化部署
// 将 Gemini CLI 部署为 A2A 服务
import { A2AExpressApp } from '@a2a-js/sdk/server/express';
import express from 'express';

const app = express();
const a2aApp = new A2AExpressApp(requestHandler);

a2aApp.setupRoutes(app, '/api');
app.listen(41242, () => {
  console.log('Gemini A2A Server running on http://localhost:41242');
});

// 现在其他 Agent 可以调用
const geminiAgent = await createAgent({
  agentUrl: 'http://localhost:41242/api'
});

6.3 Codex SQ/EQ 典型场景

场景 1: 细粒度的审批控制
// 定义审批策略
let approval_policy = AskForApproval::AskBeforeExecuting;
let sandbox_policy = SandboxPolicy::Strict;

// 提交用户输入
let submission = Submission {
    id: "sub-001".to_string(),
    op: Op::UserTurn {
        items: vec![UserInput::Text("删除所有日志文件".to_string())],
        cwd: PathBuf::from("/var/log"),
        approval_policy,
        sandbox_policy,
        model: "gpt-4".to_string(),
    }
};

// Agent 请求批准
let event = Event {
    id: "evt-001".to_string(),
    msg: EventMsg::ExecApprovalRequest(ExecApprovalRequestEvent {
        command: "rm -rf *.log",
        assessment: SandboxCommandAssessment {
            risk_level: SandboxRiskLevel::High,
            reason: "批量删除操作".to_string(),
        }
    })
};

// 用户批准或拒绝
let approval = Submission {
    id: "sub-002".to_string(),
    op: Op::ExecApproval {
        id: "evt-001".to_string(),
        decision: ReviewDecision::Approve,
    }
};
场景 2: 会话恢复
// 保存会话状态
let conversation_id = ConversationId::new();
conversation_manager.save_state(conversation_id, &state).await?;

// 稍后恢复
let restored_state = conversation_manager.load_state(conversation_id).await?;
let conversation = CodexConversation::from_state(restored_state)?;

七、技术挑战与解决方案

7.1 工具命名冲突

问题: 多个 MCP Server 可能提供同名工具

Gemini CLI 解决方案:

// 使用 server_name 作为 namespace
const toolName = `${serverName}.${originalToolName}`;
// 例如: "github.create_issue", "gitlab.create_issue"

Codex 解决方案:

// 使用双下划线分隔符 + SHA1 截断
const DELIMITER = "__";
let qualified_name = format!(
    "mcp{}{}{}{}",
    DELIMITER, server_name, DELIMITER, tool_name
);

if qualified_name.len() > 64 {
    let hash = sha1::Sha1::digest(qualified_name);
    qualified_name = format!("{}_{:x}", &qualified_name[..48], hash);
}
// 例如: "mcp__github__create_issue"

7.2 流式输出的挑战

问题: LLM 生成是流式的,但工具调用是同步的

A2A 解决方案:

// 使用 EventBus 解耦
for await (const chunk of llmStream) {
  eventBus.publish({
    kind: 'status-update',
    status: {
      message: { parts: [{ kind: 'text', text: chunk }] }
    },
    final: false  // 非最终状态,继续接收
  });
}

Codex 解决方案:

// 使用 AsyncIterator
pub fn send_message_stream(
    &self,
    items: Vec<UserInput>
) -> impl Stream<Item = Result<Event>> {
    async_stream::stream! {
        let response = self.llm_client.chat(items).await?;
        for await chunk in response.stream {
            yield Ok(Event {
                msg: EventMsg::AgentMessage(chunk)
            });
        }
    }
}

7.3 安全性和沙箱

Codex 的多层沙箱方案:

// 1. Execpolicy - 命令级别的策略
pub struct ExecPolicy {
    auto_approve: Vec<String>,    // 自动批准的命令
    always_deny: Vec<String>,      // 始终拒绝的命令
    require_confirm: Vec<String>,  // 需要确认的命令
}

// 2. Platform Sandbox - 操作系统级别的隔离
#[cfg(target_os = "macos")]
fn apply_seatbelt_sandbox(cmd: &str) -> Result<()> {
    let profile = "(version 1) (deny default) (allow network*) (allow file-read* /usr/bin)";
    sandbox_exec(cmd, profile)
}

#[cfg(target_os = "linux")]
fn apply_landlock_sandbox(cmd: &str) -> Result<()> {
    landlock::Ruleset::new()
        .allow_read("/usr/bin")
        .allow_execute("/usr/bin")
        .restrict_self()?;
    execute(cmd)
}

// 3. Network Isolation
if sandbox_policy == SandboxPolicy::Strict {
    env::set_var("CODEX_SANDBOX_NETWORK_DISABLED", "1");
}

八、性能对比

8.1 连接建立时间

实现传输方式平均耗时备注
Gemini MCP (TypeScript)stdio~150msNode.js 子进程启动
Gemini MCP (TypeScript)SSE~80msHTTP 连接
Codex MCP (Rust)stdio~50ms原生进程启动
Codex MCP (Rust)SSE~40msTokio HTTP Client

8.2 工具调用延迟

场景Gemini CLICodex CLI
简单工具 (read_file)~100ms~30ms
复杂工具 (database query)~500ms~200ms
批量工具调用 (10个)~1.5s~600ms

性能差异原因:

  • Rust 的零成本抽象和编译优化
  • Tokio 异步运行时的高效调度
  • 无 GC (Garbage Collection) 的确定性延迟

8.3 内存占用

实现空闲内存单会话内存10会话内存
Gemini CLI (Node.js)~80MB~150MB~500MB
Codex CLI (Rust)~5MB~15MB~80MB

九、未来发展方向

9.1 协议融合趋势

graph TB
    subgraph Layer4["Layer 4: Orchestration Layer"]
        L4A["Multi-Agent DAG 编排"]
        L4B["分布式任务调度"]
        L4C["Agent Marketplace"]

        style Layer4 fill:#e8eaf6,stroke:#283593,stroke-width:2px
    end

    subgraph Layer3["Layer 3: Agent Communication (ACP++)"]
        L3A["统一的任务状态管理"]
        L3B["Agent 发现与注册"]
        L3C["流式通信 + 状态持久化"]

        style Layer3 fill:#e1f5fe,stroke:#01579b,stroke-width:2px
    end

    subgraph Layer2["Layer 2: Tool & Resource (MCP++)"]
        L2A["工具发现与调用"]
        L2B["资源抽象与访问控制"]
        L2C["Prompt 库管理"]

        style Layer2 fill:#fff3e0,stroke:#e65100,stroke-width:2px
    end

    subgraph Layer1["Layer 1: Transport Layer"]
        L1A["gRPC / WebSocket / QUIC"]
        L1B["加密传输 (TLS 1.3)"]

        style Layer1 fill:#f3e5f5,stroke:#4a148c,stroke-width:2px
    end

    Layer4 --> Layer3
    Layer3 --> Layer2
    Layer2 --> Layer1

    style L4A fill:#c5cae9,stroke:#283593
    style L4B fill:#c5cae9,stroke:#283593
    style L4C fill:#c5cae9,stroke:#283593
    style L3A fill:#b3e5fc,stroke:#01579b
    style L3B fill:#b3e5fc,stroke:#01579b
    style L3C fill:#b3e5fc,stroke:#01579b
    style L2A fill:#ffe0b2,stroke:#e65100
    style L2B fill:#ffe0b2,stroke:#e65100
    style L2C fill:#ffe0b2,stroke:#e65100

9.2 关键演进方向

1. 标准化组织推动
# 可能的标准化路径
- W3C Web Agent Working Group
  - 定义 Web-native Agent Protocol
  - 浏览器原生支持 Agent 通信

- IETF RFC 提案
  - Agent Communication Protocol (ACP) RFC
  - 类似 HTTP/2, gRPC 的标准化进程

- Linux Foundation AI & Data
  - MCP Foundation (类似 CNCF)
  - 开源参考实现和认证体系
2. 性能优化
// 使用 gRPC 替代 JSON-RPC
service AgentService {
  rpc ExecuteTask(TaskRequest) returns (stream TaskEvent);
  rpc CallTool(ToolCallRequest) returns (ToolCallResponse);
}

// 使用 Protocol Buffers 替代 JSON
message TaskEvent {
  string task_id = 1;
  TaskState state = 2;
  oneof payload {
    AgentMessage message = 3;
    ToolCall tool_call = 4;
  }
}

// 性能提升预期
// - 序列化速度: 5-10x
// - 传输体积: 30-50% 减少
// - 类型安全: 编译时检查
3. 安全性增强
# Zero Trust Agent Network
- 端到端加密 (E2EE)
  - Agent 间通信默认加密
  - 密钥轮换机制

- 细粒度访问控制 (FGAC)
  - 基于 RBAC 的工具权限
  - 基于 ABAC 的资源访问

- 审计与合规
  - 完整的调用链追踪
  - 符合 SOC2 / ISO27001

- 沙箱增强
  - WebAssembly (WASI) 沙箱
  - 容器级别隔离 (Firecracker)
4. 可观测性
// OpenTelemetry 集成
import { trace, context } from '@opentelemetry/api';

class InstrumentedAgent {
  async executeTask(task: Task) {
    const span = trace.getTracer('agent').startSpan('execute_task', {
      attributes: {
        'task.id': task.id,
        'agent.name': this.name,
        'agent.version': this.version
      }
    });

    try {
      const result = await this.executor.execute(task);
      span.setStatus({ code: SpanStatusCode.OK });
      return result;
    } catch (error) {
      span.recordException(error);
      span.setStatus({ code: SpanStatusCode.ERROR });
      throw error;
    } finally {
      span.end();
    }
  }
}

// 分布式追踪
UserAgent A (trace_id: abc123, span_id: 001)
  → MCP Tool 1 (trace_id: abc123, span_id: 002)
  → Agent B (trace_id: abc123, span_id: 003)
    → MCP Tool 2 (trace_id: abc123, span_id: 004)
5. 跨语言互操作
┌─────────────────────────────────────────────────────────┐
│           多语言 SDK 生态                                │
├─────────────────────────────────────────────────────────┤
│                                                          │
│  TypeScript  │  @mcp/sdk, @acp/sdk                      │
│  Rust        │  mcp-rs, acp-rs                          │
│  Python      │  mcp-python, acp-python                  │
│  Go          │  go-mcp, go-acp                          │
│  Java        │  mcp-java, acp-java                      │
│                                                          │
│  共同特性:                                               │
│  - Protocol Buffers 定义                                │
│  - 自动生成代码绑定                                     │
│  - 统一的测试套件                                       │
│  - 互操作性验证                                         │
└─────────────────────────────────────────────────────────┘

9.3 应用场景展望

场景 1: 企业级 AI Mesh
# Agent 服务网格
apiVersion: v1
kind: AgentMesh
metadata:
  name: company-ai-mesh
spec:
  agents:
    - name: code-gen-agent
      provider: gemini
      replicas: 3
      tools:
        - github
        - gitlab
        - jira

    - name: code-review-agent
      provider: claude
      replicas: 2
      tools:
        - sonarqube
        - codecov

    - name: security-scan-agent
      provider: codex
      replicas: 1
      tools:
        - snyk
        - trivy

  routing:
    - match: code_generation
      route: code-gen-agent
    - match: code_review
      route: code-review-agent
    - match: security_scan
      route: security-scan-agent
场景 2: Personal AI Assistant Ecosystem
// 个人 AI 助手编排
const personalAI = new AgentOrchestrator({
  agents: {
    calendar: await createAgent({ url: 'http://calendar-agent:8080' }),
    email: await createAgent({ url: 'http://email-agent:8081' }),
    task: await createAgent({ url: 'http://task-agent:8082' }),
    research: await createAgent({ url: 'http://research-agent:8083' })
  }
});

// 复杂任务编排
await personalAI.execute({
  task: "准备下周的产品发布会",
  steps: [
    {
      agent: 'calendar',
      action: '检查下周日程并预定会议室'
    },
    {
      agent: 'task',
      action: '创建发布会任务清单'
    },
    {
      agent: 'research',
      action: '调研竞品最新动态',
      depends_on: ['task']
    },
    {
      agent: 'email',
      action: '发送会议邀请给相关人员',
      depends_on: ['calendar', 'research']
    }
  ]
});

十、给开发者的建议

10.1 选择 MCP 还是 ACP?

如果你需要...推荐协议理由
为 Agent 添加外部工具能力MCP成熟的工具发现和调用机制
构建多 Agent 协作系统ACP/A2A原生的 Agent 间通信支持
企业级合规和审计Codex SQ/EQ完整的审批流程和状态追踪
快速原型开发MCP丰富的社区工具和示例
高性能生产环境Codex (Rust)低延迟、低内存占用

10.2 最佳实践

1. MCP Server 开发
// ✅ 好的实践
import { Server } from '@modelcontextprotocol/sdk/server';

const server = new Server({
  name: 'my-tool-server',
  version: '1.0.0'
});

// 提供详细的工具描述
server.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools: [{
    name: 'search_documents',
    description: '在文档库中搜索相关内容。支持全文搜索和语义搜索。',
    inputSchema: {
      type: 'object',
      properties: {
        query: {
          type: 'string',
          description: '搜索关键词或自然语言问题'
        },
        mode: {
          type: 'string',
          enum: ['fulltext', 'semantic'],
          default: 'semantic',
          description: '搜索模式'
        }
      },
      required: ['query']
    }
  }]
}));

// ❌ 不好的实践
const badTools = [{
  name: 'search',  // 名称过于泛化
  description: '搜索',  // 描述不清晰
  inputSchema: {
    type: 'object',
    properties: {
      q: { type: 'string' }  // 参数名不明确
    }
  }
}];
2. Agent 安全设计
// ✅ 好的实践: 最小权限原则
const agentConfig = {
  mcpServers: {
    filesystem: {
      command: 'npx',
      args: ['-y', '@mcp/server-filesystem', '/workspace/project'],
      // 仅允许访问项目目录
      env: {
        ALLOWED_PATHS: '/workspace/project'
      }
    }
  },
  execPolicy: {
    autoApprove: [
      'npm install',
      'git status',
      'git diff'
    ],
    alwaysDeny: [
      'rm -rf /',
      'sudo *',
      'chmod 777 *'
    ]
  }
};

// ❌ 不好的实践: 过度权限
const badConfig = {
  mcpServers: {
    filesystem: {
      args: ['/'],  // 允许访问整个文件系统
    }
  },
  execPolicy: {
    autoApprove: ['*']  // 自动批准所有命令
  }
};
3. 错误处理和重试
// ✅ 好的实践: 指数退避重试
async function callToolWithRetry(
  tool: string,
  params: any,
  maxRetries = 3
): Promise<any> {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await mcpClient.callTool(tool, params);
    } catch (error) {
      if (attempt === maxRetries - 1) throw error;

      if (isRetryable(error)) {
        const backoff = Math.pow(2, attempt) * 1000;
        await sleep(backoff);
        continue;
      }

      throw error;
    }
  }
}

function isRetryable(error: Error): boolean {
  // 网络错误、超时等可重试
  return error.message.includes('ETIMEDOUT') ||
         error.message.includes('ECONNREFUSED');
}

十一、总结

11.1 核心洞察

  1. MCP 专注于 Agent ↔ 工具/资源 的标准化,由 Anthropic 主导
  2. ACPEditor ↔ Agent 的官方标准,由 Zed Industries 发布,类似于 LSP 在语言服务器领域的作用
  3. A2A (Gemini 实现) 专注于 Agent ↔ Agent 的互操作,是构建 Multi-Agent 系统的探索
  4. Codex SQ/EQ 提供了一个完整的 用户 ↔ Agent 交互模型,强调安全性和可控性

11.2 技术趋势

2024          2025          2026          2027
                                         
  ├─ MCP 1.0    ├─ MCP++      ├─ Unified    ├─ W3C Standard
    发布         - gRPC       Protocol     - 浏览器原生
                 - WebAssembly│              - 硬件加速
  ├─ A2A 0.3    ├─ A2A 1.0    ├─ Agent Mesh ├─ Edge AI
    实验         生产可用     - K8s 集成   - 本地优先
                                         
  └─ 碎片化     └─ 融合期     └─ 成熟期     └─ 普及期

11.3 给未来的思考

"The future of AI is not just about smarter models, but about smarter collaboration between models."

—— 未来的 AI 不仅仅是更智能的模型,而是模型之间更智能的协作。

协议标准化是 AI Agent 从 工具基础设施 演进的关键一步。就像 HTTP 成就了互联网,Docker 成就了云原生,MCP 和 ACP 正在成就 AI Agent 的生态系统


参考资源

官方文档

源码仓库

社区资源

作者:前端领秀——悄悄学习,惊艳所有人~

扫码_搜索联合传播样式-白色版.png