1. 从配置文件骨架看 A2A 与 MCP 的职责边界
A2A 协议和 MCP 协议的区别,用一句话概括就是:MCP 解决的是“模型怎么调用工具”,A2A 解决的是“智能体怎么找智能体干活”。前者是模型与工具/数据源之间的连接层,后者是智能体与智能体之间的任务协商层。很多人在搭建多智能体协作链路时,会把两者混在一起配置,结果要么工具描述塞满上下文窗口,要么子智能体的任务状态无法回传。这篇内容会从 Cline、CC Switch 等工具的实际配置文件骨架出发,把两类协议的接入方式拆开讲清楚,并给出可复制的 settings.json 与 config.toml 片段,帮你在本地跑通一条“主智能体分发任务、子智能体调用工具”的完整链路。
先明确两个协议各自管什么。MCP 的核心角色是客户端与服务端:服务端把本地函数包装成标准接口暴露出来,客户端查询可用工具列表并按需调用。它关心的是工具发现、参数传递、结果返回。A2A 的核心角色是 Client Agent 与 Server Agent:Client Agent 创建 Task,Server Agent 维护 Task 状态并产出 Artifact。它关心的是任务生命周期、状态流转、能力发现(AgentCard)、安全协作。换句话说,MCP 让模型“手上有工具”,A2A 让智能体“身边有同事”。
为什么不能只用多个 MCP 工具来替代 A2A?假设你要做一个“公司全能助理”,如果给一个 LLM 挂载 50 个 MCP 工具,上下文会被海量工具描述塞满,工具越多模型越容易产生幻觉,分不清该调用哪一个。而 A2A 方案下,主助理只挂载几个垂直领域的 Agent,每个 Agent 内部再通过 MCP 连接自己的工具集。主助理只负责分发任务和接收结果,子 Agent 独立消耗 Token、独立维护任务状态。这就是职责边界的本质差异:MCP 是纵向的“模型到工具”,A2A 是横向的“智能体到智能体”。
在实际工具中,这个差异直接体现在配置文件结构上。Cline 的 settings.json 里,MCP 配置通常放在mcpServers字段下,每个条目描述一个工具服务端的启动命令或远程地址。而 A2A 的接入更多体现在智能体注册与路由配置中,比如 AgentNetwork 的代理列表、AgentCard 的 URL 注册。CC Switch 的 config.toml 则可能同时包含模型供应商配置和 MCP 服务端配置,A2A 相关的部分通常以独立的 agent 节点或路由规则出现。理解这个结构差异,是同时接入两类协议的前提。
还有一个容易踩的坑:Token 消耗模式不同。MCP 模式下,所有工具描述和中间调用过程都在主 AI 的上下文中,主模型需要“看到”每一步工具调用。A2A 模式下,主 AI 只负责中转任务,子 Agent 独立消耗 Token,主模型不需要盯着子 Agent 的每一步执行。这意味着在配置时,MCP 服务端的工具描述要尽量精简,避免上下文爆炸;而 A2A 的 AgentCard 描述要足够清晰,方便主智能体做能力匹配和路由决策。
权限隔离也是配置时要考虑的点。MCP 模式下主 AI 拥有所有工具的访问权,存在安全风险;A2A 模式下权限被封装在子 Agent 内部,主 AI 只能看到最终结果。所以在 settings.json 中配置 MCP 服务端时,建议按功能域拆分多个服务端,而不是把所有工具塞进一个。在 A2A 配置中,则可以通过 AgentCard 的 authentication 字段和 capabilities 字段来控制暴露的能力范围。
总结这一节:MCP 管“工具调用”,A2A 管“任务协商”。配置文件里,MCP 相关字段围绕服务端启动、工具列表、传输方式展开;A2A 相关字段围绕代理注册、能力发现、任务路由展开。两者不是替代关系,而是互补关系。下一节会讲怎么用 TaoToken 作为统一的模型接入层,让这两类协议在同一个环境里跑起来。
2. TaoToken 前置准备:统一模型接入与 Key 管理
在同时接入 A2A 和 MCP 之前,需要一个稳定的模型接入层。因为无论是主智能体的路由决策,还是子智能体的任务处理,都需要调用大模型。TaoToken 在这里的角色是提供统一的 API 入口,让你不用在多个供应商之间来回切换配置。官网地址是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 入口是 https://taotoken.net/api 。
先注册并拿到 API Key。进入控制台后,在 API Keys 页面创建一个新的 Key。这个 Key 会用在后续所有配置文件的api_key或apiKey字段中。建议按用途创建不同的 Key,比如一个用于主智能体路由,一个用于子智能体工具调用,方便后续排查问题时定位来源。
TaoToken 的 API 兼容 OpenAI 格式,这意味着在 Cline、CC Switch 等工具中,只需要把 Base URL 指向https://taotoken.net/api,然后填入对应的 Key 和 Model ID 即可。Model ID 的选择取决于你的任务类型:如果是路由决策这类需要快速响应的场景,可以选轻量级模型;如果是子智能体的复杂任务处理,可以选能力更强的模型。具体可用的 Model ID 可以在模型对话页面查看,也可以参考接入文档中的模型列表。
对于 A2A 场景,主智能体的 AIAgentRouter 需要一个 LLM 客户端来做路由决策。在 Python 代码中,可以这样初始化:
from langchain_openai import ChatOpenAI llm = ChatOpenAI( base_url="https://taotoken.net/api", api_key="你的TaoToken API Key", model="你的Model ID", temperature=0.1 )对于 MCP 场景,MCP 服务端本身不直接调用大模型,但 MCP 客户端(也就是主智能体)在决定调用哪个工具时,需要模型来做推理。所以 MCP 客户端的模型配置同样指向 TaoToken 的 API 入口。
如果你使用的是 Cline 这类编辑器插件,可以在设置中找到 API Provider 配置项,选择 OpenAI Compatible,然后填入 Base URL 和 API Key。Cline 的 settings.json 中对应的字段通常是:
{ "apiProvider": "openai", "openAiBaseUrl": "https://taotoken.net/api", "openAiApiKey": "你的TaoToken API Key", "openAiModelId": "你的Model ID" }CC Switch 的 config.toml 中,模型供应商配置通常长这样:
[providers.taotoken] base_url = "https://taotoken.net/api" api_key = "你的TaoToken API Key" model = "你的Model ID"这里要注意一个细节:TaoToken 的 API 入口不带 UTM 参数,直接使用https://taotoken.net/api即可。官网链接可以带 UTM 参数用于来源追踪,但 API 调用地址保持干净。
拿到 Key 并配置好模型接入后,还需要确认一件事:你的本地环境是否能正常访问 TaoToken 的 API。可以用一个简单的 curl 命令做连通性验证:
curl -X POST https://taotoken.net/api/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer 你的TaoToken API Key" \ -d '{ "model": "你的Model ID", "messages": [{"role": "user", "content": "ping"}], "max_tokens": 10 }'如果返回中包含choices字段和正常的文本内容,说明模型接入层已经通了。如果返回 401,检查 Key 是否正确、是否有多余空格;如果返回 404,检查 Base URL 是否写成了https://taotoken.net/api而不是其他路径。
对于长期编码和 Agent 场景,可以考虑使用 Coding Plan,它在频繁调用模型时能提供更稳定的配额和更低的延迟。具体可以在控制台中查看 Coding Plan 的说明和开通方式。
这一节的核心是:先把模型接入层跑通,再往上叠加 A2A 和 MCP 的配置。模型接入层不通,后面的协议配置都是空中楼阁。下一节会给出完整的可复制配置片段,把 A2A 的 AgentCard 注册和 MCP 的服务端配置放在同一个环境里。
3. 可复制配置:settings.json 与 config.toml 骨架
这一节直接给配置。先看 Cline 的 settings.json 中如何同时体现 MCP 服务端和 A2A 代理注册。Cline 本身对 MCP 的支持比较直接,A2A 的接入通常通过自定义脚本或外部 AgentNetwork 来管理,但配置文件里可以预留相关字段。
MCP 服务端配置在 settings.json 中的典型结构:
{ "mcpServers": { "weather-tool": { "command": "python", "args": ["-m", "mcp_server_weather"], "env": { "API_KEY": "你的天气服务Key" } }, "database-tool": { "command": "node", "args": ["/path/to/mcp-database-server/index.js"], "env": { "DB_CONNECTION": "your_connection_string" } } } }每个 MCP 服务端对应一个工具提供者。command和args描述如何启动这个服务端,env传递环境变量。注意不要把生产数据库的直接连接串放在这里,应该通过子 Agent 封装权限,主智能体只调用子 Agent 暴露的接口。
A2A 代理注册在 Cline 中通常不直接写在 settings.json 里,而是通过 AgentNetwork 在代码中管理。但如果你使用的工具支持在配置文件中声明 A2A 代理,结构可能类似:
{ "a2aAgents": { "TicketAgent": { "url": "http://127.0.0.1:5010", "agentCard": { "name": "TicketAgentServer", "description": "票务代理,支持火车票、机票预订", "skills": [ { "name": "book_ticket", "description": "预订票务", "examples": ["预订从上海到北京的火车票"] } ] } } } }这个结构对应 A2A 协议中的 AgentCard 和 AgentNetwork。url是 Server Agent 的地址,agentCard描述能力信息,主智能体通过discover_agents或network.add来注册和发现这些代理。
再看 CC Switch 的 config.toml。CC Switch 通常用于管理多个模型供应商和工具配置,config.toml 中可能同时包含模型供应商、MCP 服务端和 A2A 代理的配置:
[providers.taotoken] base_url = "https://taotoken.net/api" api_key = "你的TaoToken API Key" model = "你的Model ID" [mcp_servers.weather] command = "python" args = ["-m", "mcp_server_weather"] [mcp_servers.database] command = "node" args = ["/path/to/mcp-database-server/index.js"] [a2a_agents.TicketAgent] url = "http://127.0.0.1:5010" description = "票务代理" [a2a_agents.HotelAgent] url = "http://127.0.0.1:5011" description = "酒店预订代理"这个骨架把三类配置放在同一个文件里:模型供应商(providers)、MCP 服务端(mcp_servers)、A2A 代理(a2a_agents)。实际使用时,根据你所用工具的具体字段名调整。
如果你使用 Codex 的 auth.json,配置结构会有所不同。Codex 的 auth.json 通常用于存储认证信息,MCP 和 A2A 的配置可能分开存放。一个典型的 auth.json 片段:
{ "base_url": "https://taotoken.net/api", "api_key": "你的TaoToken API Key", "model": "你的Model ID" }注意这里的三件套:Base URL、Key、Model ID 必须同时出现且一致。Base URL 指向 TaoToken 的 API 入口,Key 是控制台创建的 API Key,Model ID 是你要使用的模型标识。三者缺一不可,否则会出现 401 或模型不存在的报错。
对于 A2A 的 Server Agent,需要在代码中定义 AgentCard 并启动服务。一个最小化的 TicketServer 配置:
from python_a2a import A2AServer, run_server, AgentCard, AgentSkill, TaskStatus, TaskState ticket_card = AgentCard( name="TicketAgentServer", description="票务代理", url="http://127.0.0.1:5010", skills=[AgentSkill(name="book_ticket", description="预订票务")] ) class TicketServer(A2AServer): def __init__(self): super().__init__(agent_card=ticket_card) def handle_task(self, task): query = (task.message or {}).get("content", {}).get("text", "") if "上海" in query and "北京" in query: result = "上海到北京的火车票已经预订成功!G1001,10车1A" else: result = "请输入明确的出发地和目的地。" task.artifacts = [{"parts": [{"type": "text", "text": result}]}] task.status = TaskStatus(state=TaskState.COMPLETED) return task if __name__ == "__main__": server = TicketServer() run_server(server, host="127.0.0.1", port=5010, debug=False)这个 Server Agent 内部可以调用 MCP 工具来完成实际工作。比如handle_task中不直接模拟结果,而是通过 MCP 客户端调用票务查询工具。这样就形成了“A2A 负责任务协商,MCP 负责工具调用”的分工。
配置完成后,检查几个关键点:MCP 服务端的command和args是否能在本地正常执行;A2A 代理的url是否可访问;TaoToken 的 Base URL、Key、Model ID 是否三件套齐全。下一节会讲如何验证这些配置是否真正跑通。
4. 验证请求与成功结果:跑通多智能体协作链路
配置写完后,需要分步验证。先验证 MCP 服务端是否能正常启动并暴露工具列表,再验证 A2A 代理是否能被主智能体发现和调用,最后验证整条链路是否能完成一个实际任务。
第一步,验证 MCP 服务端。以 Python 的 MCP 服务端为例,启动后可以用 MCP 客户端查询工具列表:
from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client server_params = StdioServerParameters( command="python", args=["-m", "mcp_server_weather"] ) async def check_tools(): async with stdio_client(server_params) as (read, write): async with ClientSession(read, write) as session: await session.initialize() tools = await session.list_tools() print("可用工具:", [t.name for t in tools]) import asyncio asyncio.run(check_tools())如果输出中包含你配置的工具名称,说明 MCP 服务端启动成功且工具发现正常。如果报错local proxy failed或连接超时,检查command和args是否正确,以及服务端脚本是否有执行权限。
第二步,验证 A2A 代理注册。启动 TicketServer 后,用 AgentNetwork 注册并查询 AgentCard:
from python_a2a import AgentNetwork network = AgentNetwork(name="MyNetwork") network.add("TicketAgent", "http://127.0.0.1:5010") print("已注册代理:", network.agent_cards)如果输出中能看到 TicketAgent 的 AgentCard 信息,包括 name、description、skills,说明 A2A 代理注册成功。如果报错Connection refused,检查 Server Agent 是否已启动、端口是否被占用。
第三步,验证主智能体路由。用 AIAgentRouter 做一次路由决策:
from python_a2a import AIAgentRouter, AgentNetwork from langchain_openai import ChatOpenAI network = AgentNetwork(name="MyNetwork") network.add("TicketAgent", "http://127.0.0.1:5010") llm = ChatOpenAI( base_url="https://taotoken.net/api", api_key="你的TaoToken API Key", model="你的Model ID", temperature=0.1 ) router = AIAgentRouter(llm_client=llm, agent_network=network) agent_name, confidence = router.route_query("预订票") print(f"路由结果:{agent_name},置信度:{confidence}")如果输出TicketAgent 0.1或类似的置信度,说明主智能体成功将查询路由到了票务代理。如果报错reading choices或返回空结果,检查 TaoToken 的 API Key 和 Model ID 是否正确,以及网络是否能访问https://taotoken.net/api。
第四步,验证完整链路。用 A2AClient 向 TicketAgent 发送任务:
import asyncio from python_a2a import A2AClient async def main(): client = A2AClient("http://127.0.0.1:5010") result = client.ask("预订一张从北京到上海的火车票") print("任务结果:", result) asyncio.run(main())预期输出类似:上海到北京的火车票已经预订成功!G1001,10车1A。如果输出是“请输入明确的出发地和目的地”,说明任务消息没有正确传递,检查task.message的解析逻辑。
到这里,一条完整的链路就跑通了:主智能体通过 A2A 路由将任务分发给 TicketAgent,TicketAgent 内部可以通过 MCP 调用票务工具,最终返回 Artifact。整个过程主智能体不需要知道票务工具的具体实现,只需要知道 TicketAgent 能处理票务任务。
如果要在 Cline 或 CC Switch 中验证,可以在对话中直接输入“帮我预订一张从北京到上海的火车票”,观察工具调用日志。Cline 会显示 MCP 工具调用过程,如果配置了 A2A 代理,也会显示任务分发记录。成功时,你会看到 MCP 工具返回结果,以及 A2A 任务状态从submitted变为completed。
验证过程中,建议打开 debug 日志。A2AServer 的run_server中设置debug=True可以看到详细的任务处理日志。MCP 服务端的日志通常输出到 stderr,可以在启动命令中重定向到文件方便排查。
下一节会列出这个过程中常见的报错和排查方法。
5. 常见报错排查:401、local proxy failed、reading choices、OAuth
配置和验证过程中,最容易遇到四类报错。每一类都对应不同的配置环节,排查时按顺序检查。
第一类:401 Unauthorized。这个报错通常出现在调用 TaoToken API 时。原因可能是 API Key 错误、Key 过期、或者请求头格式不对。检查步骤:确认Authorization头是Bearer 你的Key格式,注意 Bearer 后面有一个空格;确认 Key 没有多余的空格或换行;确认 Key 是在 TaoToken 控制台的 API Keys 页面创建的,并且没有删除。如果使用 Cline 或 CC Switch,检查 settings.json 或 config.toml 中的api_key字段是否与三件套中的 Key 一致。Base URL、Key、Model ID 三者必须同时正确,缺一不可。
第二类:local proxy failed。这个报错通常出现在 MCP 服务端启动时。原因可能是command指定的可执行文件不存在,或者args中的脚本路径错误。检查步骤:在终端中手动执行command和args组合的命令,看是否能正常启动;确认 Python 或 Node 的路径在系统 PATH 中;如果使用虚拟环境,确认command指向的是虚拟环境中的解释器。另外,如果 MCP 服务端需要网络访问,确认本地网络能正常访问外部服务。
第三类:reading choices 报错。这个报错通常出现在解析模型返回结果时。原因可能是 TaoToken API 返回的 JSON 结构与代码期望的不一致,或者模型返回了空结果。检查步骤:用 curl 直接调用 TaoToken API,确认返回中包含choices字段;检查代码中解析choices的部分是否正确处理了嵌套结构;确认 Model ID 是有效的,并且该模型支持当前请求的参数。如果返回的是流式响应,检查代码是否正确处理了 SSE 格式。
第四类:OAuth 相关报错。这个报错通常出现在 A2A 代理需要认证时。A2A 协议的 AgentCard 中有authentication字段,如果 Server Agent 配置了认证机制,Client Agent 需要提供相应的凭证。检查步骤:确认 AgentCard 中的authentication字段是否与 Client Agent 的配置匹配;如果使用 OAuth,确认 token 是否有效、是否过期;如果不需要认证,确认 AgentCard 中没有误配置authentication字段。对于本地开发环境,通常可以暂时不配置认证,先跑通链路再叠加安全机制。
除了这四类,还有一些常见问题。比如 A2A 任务状态一直停留在submitted,说明 Server Agent 没有正确处理任务。检查handle_task方法是否被调用,以及task.status是否被更新为COMPLETED或FAILED。如果任务状态是input-required,说明 Server Agent 需要额外输入,检查任务消息中是否包含了必要的信息。
MCP 工具调用返回空结果,检查工具函数的返回值是否符合 MCP 协议要求的格式。MCP 工具通常返回一个包含content字段的对象,content是一个数组,每个元素有type和text或data字段。
如果 Cline 中 MCP 工具列表为空,检查 settings.json 中mcpServers的配置是否正确,以及 Cline 是否重新加载了配置。有些工具需要重启后才能识别新的 MCP 服务端。
排查时的一个实用技巧:把日志级别调到 debug。A2AServer 的run_server中设置debug=True,MCP 服务端在启动命令中加入--verbose或类似参数。日志会告诉你请求发到了哪里、返回了什么、在哪一步失败。
如果排查后仍然无法解决,可以对照接入文档中的示例配置,逐项检查自己的配置文件。也可以使用模型对话功能,直接向模型描述报错信息,获取排查建议。
6. 从配置到落地:多智能体协作的实用建议
跑通链路之后,有几个实用建议可以让你的多智能体协作更稳定。第一,MCP 服务端按功能域拆分,不要把所有工具塞进一个服务端。比如天气工具、数据库工具、文件工具分别独立启动,这样单个服务端出问题不会影响其他工具,也方便权限隔离。第二,A2A 的 AgentCard 描述要具体,skills 中的 examples 要覆盖典型查询,这样主智能体的路由决策会更准确。第三,主智能体的路由提示词要精简,只保留必要的代理描述和技能信息,避免上下文过长导致路由延迟。
对于长期运行的 Agent 场景,建议使用 Coding Plan 来获得更稳定的模型调用配额。在控制台中可以看到 Coding Plan 的详细说明和开通入口。对于需要频繁验证模型效果的场景,可以使用模型对话页面快速测试不同 Model ID 的表现。
配置文件的版本管理也很重要。settings.json 和 config.toml 中的 API Key 不要直接提交到代码仓库,可以使用环境变量或本地密钥文件。TaoToken 的 API Key 可以在控制台中随时轮换,如果怀疑泄露,立即删除旧 Key 并创建新 Key。
最后,多智能体协作的调试建议从简单链路开始。先跑通一个 MCP 工具调用,再跑通一个 A2A 代理注册,最后把两者串起来。每一步都验证通过后再进入下一步,这样出问题时容易定位是哪个环节的配置有误。整条链路跑通后,你会得到一个主智能体负责路由、子智能体负责执行、MCP 工具负责具体操作的协作系统,每个部分各司其职,扩展和维护都会清晰很多。