ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

MCP与A2A协议实战:从工具调用到多智能体协作的标准化之路

MCP与A2A协议实战:从工具调用到多智能体协作的标准化之路 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调用走了哪些步骤MCP客户端启动时先发initialize携带协议版本和能力声明与服务器完成握手。然后客户端发tools/list服务器返回工具清单每个工具带名字、描述和JSON Schema参数定义。用户问“看看web服务器的CPU”大模型根据工具描述和参数Schema自己决定调用run_cmd工具参数填top -bn1 | head -20。客户端通过JSON-RPC把tools/call请求发到MCP服务器。服务器执行实际命令把stdout封装成结果内容返回给客户端。模型拿到结果后结合工具输出组织自然语言回答“当前web服务器第一核CPU使用率约23%负载正常”。注意一个关键设计工具清单里的描述和参数Schema其实就是给模型看的“使用说明书”。同一个工具描述写得清楚模型用得就好参数Schema定义得松散模型就容易传错值。所以MCP项目里最花时间的往往不是协议联调而是把每个工具的描述和参数约束写好、写细。2.3 传输层如何选stdio、Streamable HTTP还是WebSocketMCP的传输层决定客户端和服务器进程之间怎么互通。你可能会在资料里看到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/mcptoken放在查询参数或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附上状态置为completedA收到后做后续处理。这种“任务对象状态机可推送可轮询”的设计是从人类协作工单系统里抽象出来的只要照着任务状态机驱动业务逻辑不容易出现双方状态不同步的问题。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协议”这类五花八门的东西顺势做一个梳理。协议选型时要先问三个问题交互双方是什么角色如果是人或模型去操作外部能力优先MCP如果是程序化的智能体之间交接任务优先A2A。一次交互的粒度多大一次调用、即发即收MCP够用涉及多步、跨系统、异步等待必须引入A2A的任务模型。历史资产怎么办老系统会有自己的RPC、私有Webhook甚至硬件协议不需要强行改造成MCP或A2A可以包一层适配器把它们“翻译”成标准协议入口。记住一句话协议是让你省力的不是让你赶时髦的。只要接入链路清晰哪怕先不上任何标准协议将来也总有办法平滑迁移。5. 实操一从零搭建一个MCP服务器Python5.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, shellTrue, capture_outputTrue, timeout10, ) output result.stdout.decode(utf-8, errorsignore) if result.returncode ! 0: output result.stderr.decode(utf-8, errorsignore) return output[:4000] except subprocess.TimeoutExpired: return 命令执行超时 except Exception as exc: return f命令执行出错: {exc}启动时如果要支持网络化调用用Streamable HTTP传输方式if __name__ __main__: # 默认stdio适合本地原生客户端 # mcp.run(transportstdio) # 网络共享模式使用HTTP传输 mcp.run(transporthttp, host0.0.0.0, port8000, 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( levellogging.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角色把闭环跑通再把这套骨架往外扩展。希望这篇实践笔记能帮你少踩几个坑。
返回列表