- MCP 规范了 AI 代理如何发现和调用工具、资源和提示,将代理与具体的 API 解耦。
- A2A 定义了独立代理如何通过 HTTP 和 JSON-RPC 相互发现、交换任务和共享工件。
- 将 MCP 用于工具访问,将 A2A 用于代理协作,从而实现跨团队和供应商的可扩展多代理架构。
- 现实世界的应用对快速设计、安全、身份联合和治理提出了新的挑战,框架和网关必须解决这些问题。

人工智能代理不再仅仅是能在单一窗口中回答问题的花哨聊天机器人。它们正在演变成分布式系统,能够读写代码、调用API、与其他服务协调,甚至与其他代理协商完成任务。一旦从“一个智能助手”过渡到“代理网络”,一个棘手的问题就出现了:所有这些组件如何相互通信而不陷入混乱?
这正是 MCP(模型上下文协议)和 A2A(代理到代理协议)试图填补的空白。MCP关注代理如何连接到工具、数据和上下文,而 A2A 则关注代理之间如何通信和协作。它们在理念上有所重叠,但运行在不同的层面上。在本文中,我们将深入探讨它们各自的功能、相互补充的方式、它们在实际系统中的应用,以及这对未来编码工具和多代理架构的意义。
MCP的实际应用
MCP 的核心在于提供一种标准化的方式,将工具、资源和提示信息暴露给 AI 代理,以便代理能够安全、一致地调用它们。它无需使用自定义粘合代码将每个工具直接连接到每个代理,而是将这些工具暴露在 MCP 服务器之后,并让 MCP 客户端(即代理)通过统一的协议发现并调用它们。
MCP 遵循清晰的客户端-服务器架构:宿主应用程序(例如编辑器、命令行界面或代理运行时)嵌入 MCP 客户端,该客户端与一个或多个 MCP 服务器建立一对一连接。每个服务器都只是一个轻量级进程,提供一系列功能——通常是工具、只读资源和可重用的提示符。
其灵感源自语言服务器协议 (LSP)。LSP将“编辑器 ↔ 语言特性”的问题抽象化,从而避免了为每个编辑器和每种编程语言编写自定义集成。只需实现一次语言服务器,任何兼容 LSP 的编辑器即可与其通信。MCP 借鉴了相同的理念,并将其应用于语言学习模型 (LLM) 的工具和上下文:只需将工具实现为 MCP 服务器,所有支持 MCP 的代理即可使用它。
从传输角度来看,MCP 既灵活又具有足够的规范性,使其切实可行。它使用 JSON-RPC 2.0 作为消息格式,并支持多种传输方式:stdio 用于本地进程(非常适合桌面应用程序和本地开发),HTTP 或 SSE 用于远程服务器(非常适合 Cloud Run 或容器化部署)。该协议还定义了客户端如何发现功能以及如何使用 JSON Schema 描述工具,以便 LLM 可以决定何时以及如何调用它们。
至关重要的是,MCP 不会干预智能体的推理过程。它不会决定何时调用工具,也不会决定如何串联工具。MCP 是连接层:它以结构化、可发现的方式提供工具、资源和提示,而将决策权留给智能体框架、规划器或提示工程。
MCP核心构建模块:工具、资源和提示
MCP 服务器围绕三个主要基本要素展开:工具、资源和提示。这三个概念足以满足大多数实际代理的需求,而无需将协议变成一个完整的编排框架。
工具是代理可以触发的离散操作。 思考 ”get_weather“”search_inventory“”book_flight“”run_sql_query“或”get_exchange_rate每个工具都声明有名称、易于理解的描述和输入模式。该模式使 LLM 能够理解它应该传递哪些参数,并且它还能在执行前验证参数,从而保护您的后端。
资源代表服务器可以按需提供的只读数据。文件、日志、数据库行、文档片段、配置文件——任何用“获取此内容”而非“运行此函数”来建模更合适的信息都属于资源。资源可能很大,因此 MCP 定义了分页和流式传输资源的方法,这在向时间窗口有限的模型中提供上下文时至关重要。
提示是服务器可以向客户端提供的可重用模板。与其在代理程序中硬编码冗长且易出错的提示字符串,不如将它们集中起来,作为 MCP 提示。服务器会提供提示的名称、描述和参数槽,客户端则在运行时填充这些参数槽。当多个代理程序需要共享相同的模式来与特定工具通信或遵循公司范围内的安全合规规则时,这种方式非常强大。
当客户端连接到服务器时,它会执行功能发现步骤。 服务器会返回一个工具、资源和提示的目录,每个工具、资源和提示都包含详细的元数据。然后,该目录会被输入到 LLM 中(通常以摘要形式),以便模型能够推断:“我可以使用 get_exchange_rate 要回答关于货币兑换的问题,我不应该试图编造答案。
由于所有操作都是声明式的,因此无需修改代理的核心逻辑即可添加或移除新功能。只需向服务器添加一个新工具,重新部署,所有连接的 MCP 客户端在下次功能协商时都能看到它。这对于 AI 工具来说,就如同“再插一个 USB 设备”一样简单。
MCP 的一个具体示例:货币转换工具
Google 代理开发工具包 (ADK) 中的货币代理演示完美地展示了 MCP 的实际应用。 首先构建一个小型MCP服务器,该服务器仅公开一个工具。 get_exchange_rate它由公共的 Frankfurter API 提供支持。在磁盘上,它只是一个使用 Python 的小型脚本。 fastmcp.
服务器使用类型化参数定义该工具。 currency_from, currency_to 和 currency_date此外,还具备强大的日志记录和错误处理能力。 当代理调用该功能时,服务器会通过 HTTP 协议向 Frankfurter 发送请求,验证响应,并返回包含汇率的 JSON 数据或错误对象。这并非 AI 特有的;MCP 只是规范了该功能的描述和调用方式。
在本地,您只需一个简单的命令即可运行服务器,它会监听某个进程。 http://localhost:8080. 另一个测试客户端也使用 MCP,连接并发现 get_exchange_rate 并触发美元兑欧元的调用。日志显示了工具调用、发出的 HTTP 请求、成功响应和返回的 JSON。从代理的角度来看,它只是询问“我有哪些工具?”,然后“请调用这个工具”。
将同一台服务器部署到 Cloud Run 上,情况几乎没有改变。 您将 MCP 服务器容器化,然后进行部署。 --no-allow-unauthenticated 因此,它需要 IAM 支持的身份验证,然后使用 Cloud Run 代理命令从本地计算机打开一个安全隧道。在本地,您的 MCP 客户端仍然认为它正在与……通信 http://127.0.0.1:8080代理服务器透明地处理身份验证和网络跃点。
这种模式在团队协作中非常强大:您可以运行一个集中式的 MCP 服务器,用于共享货币汇率、内部 API 或专有数据库等工具。组织中的每个开发人员都可以通过安全传输连接到该服务器,而无需各自发布略有不同且维护不善的 API 封装程序。
基于 MCP 构建代理:从单一工具到完整工作流程
当将 MCP 嵌入到像 Google 的 ADK 这样的代理框架中时,它就变得非常有趣了。 在货币代理示例中,ADK 用于创建一个专门的 LLM 代理,其唯一任务是使用 MCP 工具回答有关汇率的问题。该代理的系统指令明确地告诉它:“你的唯一目的是使用……” get_exchange_rate 工具”。
ADK 会连接此指令和所选模型(例如)。 gemini-2.5-flash) 和 MCPToolset 指向 MCP 服务器 URL 的实例。 从那时起,当用户询问“250 加元等于多少美元?”时,代理会判断是否需要调用工具,填写工具参数,通过 MCP 发送请求,然后使用返回的 JSON 编写用户友好的响应。
同样的模式也适用于更复杂的代理。您无需使用单一的货币 API,而是可以连接多个服务器:一个用于内部数据库,一个用于第三方 SaaS,一个用于文档搜索,还有一个服务器用于公开可重用的提示或 RAG 管道。只要传输受支持且身份验证配置正确,MCP 并不关心这些服务器是运行在本地、Cloud Run、Kubernetes 还是 VPN 之后。
ADK 还引入了 MCP 刻意回避的“代理优先”视角。它将代理视为可组合的软件组件:您可以定义基于 LLM 的代理、工具密集型代理、评估代理和编排器,所有这些组件都能够开箱即用地使用 MCP。因此,“构建代理”看起来更像是“构建微服务”,而不再像“在笔记本中不断调整无休止的提示”。
A2A 是什么——以及为什么仅靠 MCP 还不够
如果说 MCP 关注的是将代理与工具连接起来,那么 A2A 关注的就是将代理与其他代理连接起来。一旦有了多个各自擅长执行特定任务的代理,就需要一种方法让它们彼此发现、交换任务并在工作进行过程中保持同步。这正是 A2A 的设计初衷。
A2A(Ag2A)由 Google Cloud 发起,现由 Linux 基金会管理,是一个用于代理间互操作性的开放标准。它使用常见的技术(HTTP(S)、JSON-RPC 2.0 和用于流处理的 SSE),但将其封装在一个能够理解代理、技能、任务、工件和能力的领域模型中。它摒弃了“工具调用”,转而采用一种更高层次的协作语言。
A2A 的两个核心概念是代理卡片和任务。 代理卡是一个 JSON 文档,通常可以在以下位置找到: /.well-known/agent.json ——它描述了代理的功能、如何访问代理、所需的身份验证以及支持的输入/输出模式。任务是一个代理可以发送给另一个代理的工作单元,具有明确定义的生命周期和结构化的结果。
在 A2A 交互中,一个代理扮演“客户端代理”的角色,另一个代理扮演“远程代理”的角色。客户端发现远程代理的卡片,判断其是否是完成任务的合适人选,然后创建任务请求。远程代理接收任务后,使用自身的 LLM 和内部工具(通常通过 MCP)执行任务,然后将进度更新和最终成果流式传输回客户端。
这种设计使 A2A 原生支持点对点、异步和网络友好型通信。 在底层,Python 实现基于 ASGI 框架,例如 Starlette(通过 A2AStarletteApplication)和 uvicorn,工件和任务更新通过 JSON-RPC 和 SSE 进行传输。这意味着任务可以运行数秒或数小时而不会阻塞任何 HTTP 请求,这对于现实世界的多代理工作流至关重要。
一个 A2A 示例:暴露“Hello”代理及其他
经典的 A2A “HelloWorldAgent” 以简化的形式展示了其机制。 你定义一个 AgentExecutor 实现以下功能的子类 execute 方法内部,您将一条文本消息——“来自 A2A 的问候!”——作为任务结果加入事件队列。在这种简单情况下,取消操作不会产生任何效果,但该钩子函数适用于实际工作负载。
接下来,你要创建一个 AgentSkill 描述该代理的功能。 在这个例子中,技能 hello 包含名称、描述、一组标签和代表性用户查询。然后,该技能会被打包成一个 AgentCard 以及代理的名称、版本、URL、功能和支持的输入/输出模式。
最后,将所有部件连接起来。 A2AStarletteApplication 配 DefaultRequestHandler 并以 uvicorn 的名义运行。 就外界而言,现在您已经拥有一个功能齐全的A2A代理在监听。 http://localhost:9000任何支持 A2A 的客户端都可以获取 /.well-known/agent.json了解该代理提供的服务,并向其发送任务。
在更实际的部署中,同样的模式可以扩展到诸如旅行预订、客户入职或支持自动化等编排场景。 “旅行代理”可以发现并与“机票代理”、“酒店代理”和“租车代理”进行通信,每个代理都运行在各自的 A2A 端点之后,并隐藏了其内部工具和特定于供应商的 API 接口。旅行代理只能看到任务、技能和相关文档。
这正是A2A职责分离的优势所在。每个下游代理都可以选择自己的模型、框架和工具——例如,使用ADK和MCP构建的酒店代理、使用其他技术栈构建的航空公司代理、以及位于合作伙伴基础设施中的租车代理——所有代理仍然可以通过A2A平台进行无缝协作。
将 MCP 和 A2A 整合到一个架构中
从理论上讲,这种划分听起来很清晰——MCP 用于工具,A2A 用于代理——但实际上,界限很快就会变得模糊。实际系统通常希望将 A2A 隐藏在 MCP 之后,或者将 MCP 层层嵌套在 A2A 内部,或者在同一个进程中混合使用两者。官方的 A2A 示例甚至将 A2A 通信封装成从单个服务器公开的 MCP 工具,这样 LLM 看到的就只是“一套 MCP 工具集”,而不是两个并行的协议栈。
一种常见的模式是将 MCP 视为每个代理的内部连接,而将 A2A 视为代理之间的外部网络。在代理内部,LLM 调用 MCP 工具来访问数据库、API 或文档存储。在外部,编排器通过 A2A 与该代理通信,传递任务并读取返回的工件。从编排器的角度来看,代理是一个具有清晰类型化接口的黑盒服务。
从集成角度来看,反向模式——将 A2A 作为 MCP 工具呈现——极具吸引力。许多 LLM 提供商已经拥有完善的 MCP 工具集:开发工具、UI 演示、SDK 和安全指南。通过将“联系远程代理 X”作为单个 MCP 工具公开,LLM 只需极少的设置即可触发 A2A 交互。您只需注册一个 MCP 服务器,但该服务器实际上可以在整个 A2A 网络中协调任务。
一些示例代码库就充分证明了这一点:MCP 服务器并非将每个远程 A2A 代理直接连接到模型中,而是提供了一套简洁的工具集,这些工具本身就支持 A2A 通信。这打破了人们固有的思维模式(“MCP 和 A2A 必须完全分离”),但极大地简化了实际集成,并使 LLM 接口保持简洁且精心维护。
在合适的情况下,您也可以单独使用 MCP 和 A2A。许多项目可能只需要 MCP 将单个代理连接到少数几个工具。而另一些项目,尤其是在整合供应商或内部团队时,则会大量依赖 A2A 进行跨组织协调,同时使用他们自己的内部连接方式,而不是 MCP。关键在于,这些协议并不相互竞争,而是相辅相成。
互操作性、框架和缺失的“大结构”
单凭协议本身并不能保证互操作性,因为每个人都将协议嵌入到截然不同的高层架构中。即使你完美地实现了 MCP 和 A2A,最终仍然会得到一堆互不兼容的代理模式,每种模式都会重新定义规划、内存、错误处理和治理。
生态系统的下一步发展很可能是在 MCP 和 A2A 之上构建一层框架,不仅规范底层连接,更规范整个架构。想想 Web 框架是如何在 HTTP 之上发展起来的,或者 ORM 是如何在 SQL 之上构建的。我们已经开始看到这种趋势,例如 ADK、类似 LangGraph 的编排器、Vertex AI Agent Engine 等托管平台以及能够同时理解这两种协议的 AI 网关。
一旦行业就少数几个务实的模式达成共识——例如“如何基于 A2A 和 MCP 构建多代理工作流”、“如何将团队工具暴露在 MCP 背后”——关于“应该使用 MCP 还是 A2A”的争论就会逐渐消失。大多数开发者只需选择一个框架,接入一两个服务器,就能获得合理的默认配置。
更棘手、更耗时的问题是快速的工程设计和快速的互操作性。即使协议完美无缺,通过 MCP 和 A2A 连接系统时,实际上也允许任意提示信息(系统指令、工具描述、安全规则等)跨边界泄露和交互。如果这些提示信息不一致、冗余或完全矛盾,那么在出现安全问题之前,性能就会受到影响。
在实践中,MCP + A2A 架构中设计糟糕的提示和指令会导致严重的延迟、幻觉和不稳定。每个代理在局部层面上可能都“提示良好”,但当它们叠加在一起时,流程就会变得脆弱:工具优先级错误、上下文窗口被浪费,用户预期被打破。A2A 可以协调任务,MCP 可以暴露工具,但两者都无法强制你保持提示的一致性。
这就是为什么那些真正大规模交付 LLM 产品的团队往往会将提示工程视为首要的工程问题,而不是临时抱佛脚的调整。业务利益相关者常常把提示视为解决所有问题的灵丹妙药;工程师有时则认为提示与代码相比只是次要细节。但事实介于两者之间:提示并不能让一个糟糕的系统变得好,但糟糕的提示绝对会毁掉一个原本稳固的架构。
MCP 和 A2A 中的安全、身份和治理
一旦允许代理代表用户跨越 MCP 和 A2A 边界执行操作,身份验证和授权很快就会成为核心问题。单个请求可能需要经过多层委托:用户与协调代理通信,协调代理通过 MCP 调用工具,该工具内部又会调用其他需要单独凭证的 MCP 服务器或 A2A 代理。
各种具体场景比比皆是: SaaS 应用暴露了一个需要 OAuth 令牌的多方认证平台 (MCP) 服务器;A2A 背后的内部人力资源代理使用企业 LDAP 身份;第三方分析工具使用其自身的单点登录 (SSO)。用户期望“一次登录,即可完成所有操作”,但实际上,幕后需要联合多个身份系统。
Google 的 A2A 文档明确指出,多身份联合是其核心挑战之一。用户 U 可能正在与需要系统 A 身份的代理 A(例如企业 LDAP)进行交互,而代理 A 内部又需要委托给需要系统 B 身份的代理 B(例如外部 SaaS 提供商)。协议必须支持承载和限定这些身份,而无需强制用户在每次跳转时都手动重新验证身份。
身份提供商和 OAuth/OIDC 平台正在迅速适应这种新形势。像 Logto、Auth0 或内部身份提供商这样的基础设施已经可以颁发代理在 MCP 和 A2A 调用中携带的令牌。现在的问题不在于这是否可行——显然是可行的——而在于我们如何规范模式,以确保今天构建的工具不会在明天成为安全或治理方面的隐患。
除了身份验证之外,可观测性和策略执行功能很可能会转移到共享的“代理网关”中。这些网关可以终止 MCP 和 A2A 流量、集中日志记录、强制执行速率限制、附加用户和代理身份,甚至可以过滤在哪些上下文中可以访问哪些工具或代理。这看起来很像 API 网关——只是针对 AI 流量进行了优化,而不是针对普通的 HTTP 流量。
从更宏观的角度来看,MCP 和 A2A 正在悄然重塑我们对软件集成和编码工具的认知。对于开发者而言,接入 MCP 和 ACP(IDE 的代理客户端协议)的编码助手可以发现工具、调用语言服务器、集成版本控制系统,并与其他程序员的代理进行通信——所有这些都通过标准协议实现。对于企业而言,多代理系统可以跨团队和跨供应商实现互操作,而无需为每个新的用例重新构建所有系统。
长远来看,发展趋势是从“硬连接应用”转向“代理生态系统”。正如 USB 和 HTTP 使得连接任意设备和服务成为可能一样,MCP 和 A2A 的目标是让工具和代理实现可插拔性。最终的赢家将是那些将这些协议视为基础架构而非华而不实标志的团队,这些基础架构支撑着他们的系统进行通信、协作并随着时间推移而不断演进。