☰
MCP与A2A协议实战:从工具调用到多智能体协作的标准化之路
2026/10/2 19:57:03 网站建设 项目流程

2025年上半年我接手一个内部AI平台改造项目,需求一句话:让多个业务系统里散落的AI助手,既能调用企业内部的各种工具,又能在不同的智能体之间互相“派活”。折腾一圈下来,最终落地的方案就是MCP加A2A两个协议打配合。MCP解决模型怎么稳定、标准地调用外部工具和拿数据,A2A解决智能体之间怎么发现彼此、怎么交接任务。这篇文章就围绕这两套协议做个实践向拆解,包括我选型时的对比思考、最小可用实现、以及真实项目里踩过的坑,给正在做AI应用接入的团队一个可以直接参考的路线。

一台AI应用要真正创造价值,只靠模型本身是不行的,它得有手有脚。如果没有一套标准化的“接口约定”,每个AI项目都会回到一个一个写私有插件的老路,重复造轮子且维护成本极高。不少搜索里都在问“MCP是软件协议还是硬件协议”,这里先给结论:MCP和A2A都是应用层软件协议,它们解决的问题和CAN、UART、SPI、IIC这类硬件通信协议不在一个层面。硬件协议管的是设备之间物理链路上的字节怎么走,MCP和A2A管的是AI应用之间、AI与工具之间的消息怎么组织、动作怎么触发。理解了这个分层,后面看任何协议文档都不容易发怵。

这套内容适合三类人:正在做AI Agent产品但接口越做越乱的开发同学,想把现有工具、脚本、内部系统开放给AI调用的平台团队,以及准备在公司内部做多智能体协作POC的架构师。

1. 协议的“为什么”:AI接入碎片化到了必须治的时候

1.1 大模型应用开发的“大乱炖”现状

但凡做过两个以上AI工具集成的人,都体会过那种混乱:A项目里用一套自己定义的Webhook把大模型接到数据库,B项目又搞了另一套HTTP接口给模型调用搜索服务,C项目直接把Python代码注入让模型执行。表面看每个项目都跑通了,实际上每一套集成都是“私有方言”,没法互相复用,也没法跨系统协作。更麻烦的是,模型调用工具的格式不统一,今天这个接口要求JSON里放action字段,明天那个接口要求放function字段,模型每次都要重新学一套“方言”,出错率居高不下。

市场和工程师们需要的是一个类似“USB-C接口”的约定:不管U盘、显示器还是充电器,接口长得一样,插上就能用。MCP做的就是这件事,它给“模型调用外部工具和资源”定了一套统一的会话层与调用层标准。A2A则是把同样的标准化思路往上推一层:不再只是模型调工具,而是智能体与智能体之间互发任务、互传结果,它们也需要一个通用的“工作语言”。

1.2 两份协议各自切中的痛点

MCP切中的痛点是模型和工具之间的点对点集成。有了MCP,一个工具提供方只要实现一次MCP服务器,任何支持MCP的客户端(Claude Desktop、Cursor、自研平台)都能直接复用。对工具方来说,不用为每个AI产品写适配;对AI产品方来说,不用为每个工具写插件。

A2A切中的痛点是智能体之间的互联互通。MCP没有规定“一个智能体怎么发现另一个智能体”,也没有定义“任务从A传到B之后如何跟踪状态”。A2A补上了这一层:它定义AgentCard(智能体名片,描述自己会什么)、任务对象、消息流和工件,让两个完全不同的智能体服务可以在没有私有适配的情况下协同完成一件事。

打个比方:MCP像是把工具的“遥控器”接口统一了,按同一个码率发送按键指令;A2A像是给智能体之间定了“工单流转系统”,每个智能体都是能接工单、回状态的执行单元。两者一个向下接工具,一个向上连队友,层次清晰,目标明确。

2. MCP协议拆解:从“工具接入”到“标准接口”

2.1 搞清楚MCP里的四个角色就够了

MCP的架构不复杂,核心就是两对角色加三类资源。两对角色是MCP客户端(也叫Host,运行在AI应用中,负责发起会话)和MCP服务器(暴露工具和数据的进程)。三类资源是:

  • Tools(工具):模型可以主动调用的函数,比如“执行SQL查询”“发送HTTP请求”“读文件”。工具是使用型资源,模型决定何时调用。
  • Resources(资源):向模型提供的数据内容,比如“项目文档”“数据库Schema”,模型在回答时可以参考这些数据。资源是只读型的上下文。
  • Prompts(提示词模板):预定义的用户交互模板,相当于把一些常用的指令模式固化成标准模板,客户端可以直接复用。

会话层有明确的消息类型:初始化握手、工具列表拉取、工具调用请求和响应、资源读取、提示词获取等。这些都是基于JSON-RPC 2.0来组织的,所以从实现角度说,MCP没有引入什么玄学,凡是写过RPC的人都能快速上手。

2.2 一次工具调用的完整旅程

以“AI查询服务器CPU状态”为例,理解一次MCP调用走了哪些步骤:

  1. MCP客户端启动时先发initialize,携带协议版本和能力声明,与服务器完成握手。然后客户端发tools/list,服务器返回工具清单,每个工具带名字、描述和JSON Schema参数定义。
  2. 用户问“看看web服务器的CPU”,大模型根据工具描述和参数Schema,自己决定调用run_cmd工具,参数填top -bn1 | head -20。
  3. 客户端通过JSON-RPC把tools/call请求发到MCP服务器。服务器执行实际命令,把stdout封装成结果内容返回给客户端。
  4. 模型拿到结果后,结合工具输出组织自然语言回答:“当前web服务器第一核CPU使用率约23%,负载正常”。

注意一个关键设计:工具清单里的描述和参数Schema,其实就是给模型看的“使用说明书”。同一个工具,描述写得清楚,模型用得就好;参数Schema定义得松散,模型就容易传错值。所以MCP项目里最花时间的往往不是协议联调,而是把每个工具的描述和参数约束写好、写细。

2.3 传输层如何选:stdio、Streamable HTTP还是WebSocket

MCP的传输层决定客户端和服务器进程之间怎么互通。你可能会在资料里看到stdio、SSE、WebSocket、Streamable HTTP这些词,它们是不同时期的传输方案。

  • stdio传输:适用于客户端和服务器在同一台机器上的场景。比如桌面AI应用本地拉起一个Python脚本,输入输出通过标准输入输出流传递。优点是无需网络端口,排障简单;缺点是远程没法用,一条命令只能服务一个客户端会话。
  • Streamable HTTP传输:这是当前主流的网络化传输方式,也是wss://your-host/mcp?token=...这类地址背后对应的方案。它允许远端客户端通过HTTP或WebSocket与MCP服务器通信,支持服务端主动推送消息,非常适合企业内部多个AI客户端共享同一批工具。
  • 早期SSE方案已逐渐被Streamable HTTP收敛,新项目不必再走老路。

实操建议:本地原型用stdio就行,要部署成团队共用服务请直接上Streamable HTTP,并且配好鉴权与TLS。地址形式通常是http(s)://domain/mcp或ws(s)://domain/mcp,token放在查询参数或Authorization头里都常见,具体以你的网关设计为准。

3. A2A协议拆解:让智能体学会互相派活

3.1 A2A的核心拼图:AgentCard、任务与消息流

A2A协议解决的是“智能体之间互相发现、协作、追踪”的问题。它的体系里,最核心的三个概念是AgentCard、任务(Task)和消息(Message)。

AgentCard是一份公开的JSON文档,描述一个智能体的身份、能力、技能列表、接入点URL和认证方式。可以理解为“智能体名片”。当一个智能体想找人帮忙时,先拉取对方的AgentCard,看到对方会做哪些技能,再决定是否把任务派过去。这个机制和OAuth里的Discovery Document、以及微服务里的服务注册信息都很像。

任务是有状态的。A2A把一个跨智能体的请求建模为任务对象,任务有状态机:pending等待执行,然后是working进行中,最后落到completed、failed或canceled。双方通过message/send、task/send、task/get这些JSON-RPC方法相互通信。注意,A2A同样使用JSON-RPC 2.0作为消息协议,这点和MCP一致,学习成本因此低了不少。消息里还支持携带Artifact(工件),比如生成的文档、图片、配置文件,智能体之间可以传文件级结果,而不是只传一句话。

3.2 同步与异步:协议视角下的协作节奏

A2A设计里特别值得琢磨的是它把同步和异步路由拆开了。内部使用长连接通道处理快速请求,外部使用推送机制处理慢任务,用同一套任务状态机把两种节奏统一起来。

举个例子:智能体A把“生成一份本月运维报告”派给智能体B。这个任务显然不是几秒能完成的,可能涉及拉数据、分析、排版。A2A的交互模式是:A调用task/send把任务发出,B受理后任务状态变成working,同时B通过推送不断更新任务状态和进度消息,A可以监听这些消息,也可以随时task/get主动轮询。任务完成时,B把最终报告作为Artifact附上,状态置为completed,A收到后做后续处理。

这种“任务对象+状态机+可推送可轮询”的设计,是从人类协作工单系统里抽象出来的,只要照着任务状态机驱动业务逻辑,不容易出现双方状态不同步的问题。

3.3 企业级A2A落地要过的三道坎

第一道坎是智能体注册与发现。AgentCard如果散落在各个服务目录里,仍然会变成“信息孤岛”。落地时一般要求每个智能体在自己的域名根路径比如/.well-known/agent-card.json暴露AgentCard,或者统一注册到一个内部网关里。

第二道坎是认证授权。智能体之间互相信任不能靠裸奔。A2A本身把认证设计成可插拔的,可以用Bearer Token,也可以对接企业已有的OAuth/OIDC体系。我建议所有跨部门的A2A调用都走网关统一认证,不能每家自己发明一套签名方案。

第三道坎是可观测性。多智能体协作一出问题,排查难度呈指数级上升。必须让每个任务携带全局Trace ID,所有智能体的处理日志都按Trace ID关联,否则任务卡在上游还是下游你都说不清楚。这部分我现在会坚持做成强制规范,比协议本身更能救你命。

4. MCP与A2A:它们不是二选一,是上下楼关系

4.1 两种协议定位对比

我在设计内部平台时,很长一段时间都在纠结一个问题:有了MCP,是不是就够用了?答案是不够。MCP解决的是智能体“如何操作工具”,A2A解决的是“两个智能体如何配合”。一个管手和脚,一个管同事关系。

把搜热词时看到的现象总结一下,很多人在问“同花顺MCP”“Playwright MCP”“Unity MCP”——这些都是把特定领域的工具能力封装成MCP服务器供AI调用,属于MCP的典型落地形态。而“蓝湖MCP”“Burp Suite MCP”这类,是行业内把高频专用工具接入AI的标准做法。A2A相关讨论则更多出现在“多个Agent如何协同完成业务闭环”的架构话题里。

用表格对比更清楚:

维度MCPA2A
核心对象工具、资源、提示词智能体、任务、消息、工件
解决关系模型 ↔ 工具/数据源智能体 ↔ 智能体
消息协议JSON-RPC 2.0JSON-RPC 2.0
典型传输stdio、Streamable HTTPHTTP + 流式推送/轮询
能力发现客户端向服务器拉取工具列表拉取AgentCard发现智能体
状态管理单次请求响应即完成任务状态机贯穿全程
适用场景模型要调用具体API/脚本/数据库多智能体编排与交接

4.2 真实架构:MCP和A2A怎么混着用

我们最终形成的架构很明确:A2A管编排,MCP管执行。企业内部有一个“总控智能体”,它通过A2A协议对接三个子智能体:运维智能体、安全智能体、数据分析智能体。每个子智能体本身又通过MCP服务器去调用各自领域的工具——运维智能体用MCP调用服务器监控脚本,安全智能体用MCP调用扫描器接口,数据分析智能体用MCP查数仓。

这样分工的好处是每层只解决一个问题:“总控”看到用户任务后,把它拆解成多个子任务,通过A2A派发下去;子任务在具体执行时,落到MCP工具调用。修改其中一个子智能体内部的工具不影响总控编排;更换总控智能体也不影响各子智能体内部工具。层与层之间的契约是稳定的,这就是协议标准化的价值。

4.3 选型决策,别被热度带着走

结合热词里出现了“MCP回写打通”“锁控板协议”“UART协议”这类五花八门的东西,顺势做一个梳理。协议选型时要先问三个问题:

  1. 交互双方是什么角色?如果是人或模型去操作外部能力,优先MCP;如果是程序化的智能体之间交接任务,优先A2A。
  2. 一次交互的粒度多大?一次调用、即发即收,MCP够用;涉及多步、跨系统、异步等待,必须引入A2A的任务模型。
  3. 历史资产怎么办?老系统会有自己的RPC、私有Webhook甚至硬件协议,不需要强行改造成MCP或A2A,可以包一层适配器把它们“翻译”成标准协议入口。

记住一句话:协议是让你省力的,不是让你赶时髦的。只要接入链路清晰,哪怕先不上任何标准协议,将来也总有办法平滑迁移。

5. 实操一:从零搭建一个MCP服务器(Python)

5.1 最小可用的服务器代码

下面用一个FastMCP库的最小实现,让你半小时内就能跑通“AI调工具”的闭环。我特意写了一个执行只读命令的工具,注意它内部做了高危命令拦截,这是生产环境必须有的底线。

# server.py from fastmcp import FastMCP import subprocess # 初始化MCP服务器,名字会作为工具前缀呈现给模型 mcp = FastMCP("ops-assistant") @mcp.tool() def run_readonly_command(cmd: str) -> str: """执行服务器只读命令并返回输出,例如查询状态、查看进程。禁止高危操作。""" blocked = ("rm", "reboot", "shutdown", "mkfs", "kill -9") if any(cmd.strip().startswith(b) for b in blocked): return "拒绝执行高危命令" try: result = subprocess.run( cmd, shell=True, capture_output=True, timeout=10, ) output = result.stdout.decode("utf-8", errors="ignore") if result.returncode != 0: output += result.stderr.decode("utf-8", errors="ignore") return output[:4000] except subprocess.TimeoutExpired: return "命令执行超时" except Exception as exc: return f"命令执行出错: {exc}"

启动时如果要支持网络化调用,用Streamable HTTP传输方式:

if __name__ == "__main__": # 默认stdio适合本地原生客户端 # mcp.run(transport="stdio") # 网络共享模式使用HTTP传输 mcp.run(transport="http", host="0.0.0.0", port=8000, path="/mcp")

启动后,http://your-server:8000/mcp就是MCP端点。把地址交给支持MCP的客户端(Cursor、Claude Desktop、自研客户端都行),客户端初始化握手后会自动拉到run_readonly_command这个工具。

5.2 鉴权与安全配置不能跳

MCP服务器本质是一个“让AI替你执行动作”的服务,它比普通HTTP接口更需要安全约束。我的经验是三个必须:

  • 必须有鉴权:至少用Bearer Token,生产环境建议对接内部OIDC或API网关。token只应通过代码注入或密钥管理服务下发,绝不能写死在配置文件里。
  • 必须做命令白名单:与其拦截“危险命令”,不如只放行“允许的命令”。上面代码用了黑名单演示,但更稳的是白名单,比如只允许top、df、ps、uptime、tail这类明确的安全命令。
  • 必须限制执行范围:给MCP服务器专门的运行账号,限制目录访问、限制网络访问,像对待一个普通服务那样做主机级隔离。

5.3 自定义日志:排查MCP问题的基础设施

搜索里专门有人问“MCP服务器端的日志如何使用自定义日志管理”,这也算常见需求。MCP服务器跑在AI客户端后面,用户看到的是模型输出,一旦工具调用报错,中间过程全是黑盒。我会用标准的logging包加结构化日志,把每次工具请求、入参、耗时、结果截断、错误码都打到统一日志平台。

import logging import time logging.basicConfig( level=logging.INFO, format="%(asctime)s | %(levelname)s | %(name)s | %(message)s", ) logger = logging.getLogger("mcp.ops") # 在run_readonly_command中埋点 @mcp.tool() def run_readonly_command(cmd: str) -> str: start = time.time() logger.info(f"[MCP_TOOL_INVOKE] cmd={cmd}") # ... 执行逻辑 ... duration = round(time.time() - start, 3) logger.info(f"[MCP_TOOL_RESULT] cmd={cmd} duration={duration}s") return output

这种日志的价值在于:当模型说“工具调用失败”但实际没问题时,你能立刻定位是不是客户端传参格式的问题;当工具真的超时,你能看到具体是哪条命令拖慢了链路。

6. 实操二:打通A2A智能体互通

6.1 AgentCard与A2A服务器骨架

A2A的落地比MCP稍重一点,核心是你得先暴露一个AgentCard,然后按协议实现任务处理方法。下面是一个概念性的Node.js实现(具体库的API可能随版本调整,但流程不变):

// agent.ts 概念示意 import { A2AServer, InMemoryTaskStore } from 'a2a-sdk'; const agentCard = { name: 'ops-bot', description: '负责服务器状态查询与基础运维动作的智能体', url: 'https://agent.example.com/a2a', capabilities: { skills: [ { id: 'system_status', name: '查询系统状态' }, { id: 'read_logs', name: '读取应用日志' }, ], }, auth: { schemes: ['bearer'], }, }; const store = new InMemoryTaskStore(); const server = new A2AServer({ agentCard, taskStore: store, handleTask: async ({ taskId, message, origin }) => { // 根据message中的skillId派发到内部处理函数 store.update(taskId, { status: 'working' }); // 内部可以再去调用MCP工具或其他系统 const result = await dispatchSkill(message); store.update(taskId, { status: 'completed', artifacts: [{ kind: 'text', data: result }], }); }, }); server.start(3000);

上面这个代码展示的是最小骨架,实际生产环境中dispatchSkill内部就是业务逻辑的实现点,它完全可以再封装一个MCP客户端,去请求第5节那个MCP服务器。A2A协作与MCP工具调用在你的代码里是上下两层的关系。

6.2 从一个智能体发起任务并订阅进度

当另一个智能体要调用这个“职责体”时,流程是:先请求https://agent.example.com/.well-known/agent-card.json,拿到名片信息;然后对url发起task/send,附上目标技能和参数;后续要么监听推送,要么轮询task/get。为了快速起步,我建议先做轮询版本,跑通后再上推送。轮询版本逻辑非常简单可靠,至少不会因为事件推送通道没配对而查半天。

6.3 多智能体编排的一个简单模式

一开始别上来就做自由路由、动态规划,我用的是“总控+专家”静态编排模式:总控智能体用LLM意图识别把用户需求路由给按能力分好工的专家智能体,每个专家智能体被A2A封装,内部再用MCP调用具体工具。这个模式在项目早期就能稳定跑,等积累足够多任务样本后,再根据任务依赖关系尝试更复杂的编排逻辑。

7. 实战复盘:让AI直接操控Burp Suite的MCP集成实践

7.1 需求拆解与技术方案

搜索热词里有一条“让AI直接操控Burp Suite”,这个思路在安全圈里讨论度挺高。我做类似集成时拆解过需求:安全测试人员希望AI辅助读取代理抓包、发起扫描任务、汇总漏洞结果,而不是手动在Burp界面里点来点去。

技术方案不复杂,核心就是为Burp Suite写一个MCP服务器,把几个高频动作封装成工具:

  • get_proxy_history:获取最近代理拦截的请求列表。
  • send_to_repeater:把请求放进Repeater并执行。
  • start_scan:对指定目标URL发起主动扫描。
  • get_vulns:拉取当前项目的漏洞列表与详情。

AI客户端把这些工具当成普通MCP工具来调度,安全测试人员对AI说“把刚才那个登录接口的请求重放一遍,把响应里可疑参数标出来”,模型就把任务拆成两步,先取代理历史,再把请求放进Repeater执行。

7.2 这个方向上的安全边界

这类集成有一个红线:AI不能绕过人工确认直接触发高破坏力动作。我设计上强制加了一层人工审核闭环。MCP服务器里把start_scan这类高风险工具标记为“需要确认”,执行前必须回写一个确认工单给测试人员,测试人员在Web界面上确认后扫描任务才真正发起。这是从实际教训里得出来的:AI替你执行功能的动作,在安全敏感工具上必须人工兜底。

再补一个细节:AI调用的历史记录全部留痕。谁在什么时间通过哪个客户端,AI把哪个请求发给了哪个目标,这些审计日志和Burp自身的日志同样重要。合规压力下,这个记录往往比功能本身还关键。

8. 常见问题排查实录

把两个协议落地过程中最常遇到的问题列成速查表,希望对你有直接帮助。

现象可能原因排查思路
MCP客户端初始化失败服务器启动在stdio模式但客户端走HTTP确认传输模式匹配,检查启动日志与监听端口
拉取不到工具列表工具函数没注册或装饰器漏写检查tools/list返回,核对是否有语法错误
tools调用返回空结果命令执行了但输出被截断或stdout为空先用本地命令验证,再检查代码中的编码处理与截断逻辑
报错“未携带认证”请求头缺token或token过期看网关日志,确认token注入位置,优先用Authorization头
A2A任务一直pending服务器没启动监听或任务分发逻辑没进调用task/get看状态,检查AgentCard的url是否可达
A2A completed但没收据结果存在Artifact里而调用方只读message按协议字段拉取全部artifacts,别只解析文本消息
AI多智能体协作链路超时下游智能体同步等待时间过长改用异步任务+轮询,设置全局超时与重试策略

还有一个我自己常犯的错:工具或任务描述里写了一些模糊表述,模型理解能力再强也会跑偏。配工具和AgentCard时,每一句话都按“给一个不太懂业务的实习生看”的标准来写,宁可啰嗦,不可含糊。描述越具体,模型自动编排的成功率越高。

结尾:一点个人体会

这两个协议组合在一起,让我最明显的感受是“AI应用从定制开发变成了配置开发”。过去接一个内部系统可能要专门开发一个月,现在只要把系统能力按MCP协议包一层服务器,AI客户端就能直接用;智能体之间的协作也从“两家靠情分联调”变成了“电话打通,按协议来”。当然,协议只是地基,架构设计、安全边界、可观测性这些工程问题一个都少不了。我建议团队在动手前先把目标缩到最小:一个MCP服务器、两个工具、一个A2A角色,把闭环跑通,再把这套骨架往外扩展。希望这篇实践笔记能帮你少踩几个坑。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询