1. 从 MCP 到 A2A,AI Agent 架构演进到底在解决什么问题
如果你最近在折腾 AI Agent,大概率会被两个词反复刷屏:MCP 和 A2A。MCP(Model Context Protocol)解决的是「Agent 怎么规范地调用外部工具和数据」,A2A(Agent-to-Agent)解决的是「不同框架、不同平台造出来的 Agent 之间怎么互相说话」。前者是纵向的「Agent 到资源」,后者是横向的「Agent 到 Agent」,两者叠在一起,才构成一个能落地的多 Agent 架构。
但真正上手时,很多人卡住的不是概念,而是配置文件。MCP 阶段你要写settings.json或mcp.json去声明 server、command、args;切到 A2A 阶段,你要维护 agent card、endpoint、capability 声明,可能落在config.toml或agent.yaml里。协议一换,配置骨架就得跟着换,验证动作也得跟着换。这篇就按「配置骨架 + 验证路径」这条线,把 MCP 到 A2A 的演进拆成可复制的片段,你可以直接拿去改。
适合谁看:已经在用 Claude Desktop、Cursor、Cline 这类支持 MCP 的客户端,想进一步理解多 Agent 协作怎么配的人;或者正在设计内部 Agent 平台,需要一套从单 Agent 工具调用过渡到多 Agent 通信的配置规范的人。下面所有配置都以 TaoToken 作为模型与 Agent 接入层来演示,因为它同时提供 OpenAI 兼容接口和 Anthropic 兼容接口,MCP 和 A2A 两种场景都能接。
2. TaoToken 前置:把模型接入层先固定下来
在写任何 MCP 或 A2A 配置之前,先把模型接入层固定住,否则后面每换一个协议就要重配一遍 key 和 base_url,非常痛苦。TaoToken 的定位就是这一层:它对外暴露统一的 API 入口,MCP 客户端和 A2A Agent 都通过它拿模型能力。
你需要先拿到 API Key。进入控制台,在 API Keys 页面创建一个新 key,建议按用途命名,比如mcp-local和a2a-orchestrator,方便后面排查是哪个环节出的问题。创建后立刻复制保存,页面刷新后就看不到完整 key 了。
拿到 key 之后,记住两个地址:
| 用途 | 地址 |
|---|---|
| 官网入口 | https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= |
| API Base URL | https://taotoken.net/api |
API Base URL 后面不加任何 UTM 参数,配置里直接写这个。模型对话调试可以用模型对话页面先确认 key 是通的,长期跑编码类 Agent 任务的话,Coding Plan 的额度模型更适合高频调用,接入文档里有各客户端的完整写法。
注意:MCP 配置里的
env字段经常被用来传 API Key,不要把 key 硬编码进提交到 git 的settings.json,用环境变量引用。
3. MCP 阶段的配置骨架:settings.json 与 mcp.json
MCP 的核心是客户端-服务器架构。客户端(比如 Claude Desktop、Cursor)读一份配置,按配置去启动或连接 MCP Server,Server 再把请求转发到具体资源。所以配置骨架的关键字段就三类:怎么启动 server(command/args)、怎么传环境(env)、怎么限定权限(可选)。
3.1 Claude Desktop 风格的 settings.json
Claude Desktop 的配置一般放在用户目录下的claude_desktop_config.json,结构是mcpServers对象。下面是一个接 TaoToken 作为模型后端、同时挂一个本地文件系统 server 的骨架:
{ "mcpServers": { "taotoken-bridge": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-everything"], "env": { "OPENAI_API_KEY": "${TAOTOKEN_API_KEY}", "OPENAI_BASE_URL": "https://taotoken.net/api" } }, "local-files": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/me/workspace"], "env": {} } } }这里taotoken-bridge负责把模型请求导向 TaoToken,local-files负责暴露本地目录。${TAOTOKEN_API_KEY}是环境变量引用,实际运行时由系统注入。
3.2 通用 mcp.json 骨架
很多 IDE 插件和自研客户端用mcp.json,字段名略有差异,但语义一致。常见写法:
{ "mcpServers": { "taotoken": { "type": "stdio", "command": "node", "args": ["./servers/taotoken-server.js"], "env": { "TAOTOKEN_API_KEY": "${TAOTOKEN_API_KEY}", "TAOTOKEN_BASE_URL": "https://taotoken.net/api" }, "disabled": false, "autoApprove": ["read_file", "list_dir"] } } }type指定传输方式,本地进程用stdio,远程用sse或http。autoApprove是权限白名单,只放读类操作,写操作和网络请求保持手动确认,这是踩过坑之后的习惯——早期我把autoApprove开太大,Agent 直接批量改了工作区文件。
3.3 MCP 阶段的验证动作
配置写完不要直接上生产任务,先做三步验证。第一步,确认 server 能启动:
npx -y @modelcontextprotocol/server-everything --help能打印帮助就说明包能拉下来。第二步,确认模型通道通:
curl https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-4o-mini", "messages": [{"role": "user", "content": "ping"}] }'返回里有choices字段就说明 key 和 base_url 都对。第三步,在客户端里发一句会触发工具调用的话,比如「列出 workspace 目录下的文件」,看客户端日志里有没有tools/call记录。三步都过,MCP 这条链路才算通。
4. A2A 阶段的配置骨架:config.toml 与 agent card
MCP 解决的是单 Agent 调工具,A2A 解决的是 Agent 之间通信。A2A 基于 HTTP、SSE、JSON-RPC 这些标准技术构建,所以配置骨架从「启动命令」转向「服务声明」:每个 Agent 要暴露一个 agent card,声明自己的 endpoint、能力、认证方式;调用方通过 card 发现对方,再发 JSON-RPC 请求。
4.1 config.toml 里的 Agent 注册
假设你用 Rust 或 Python 写编排层,config.toml里可以这样声明两个 Agent:
[orchestrator] model_base_url = "https://taotoken.net/api" api_key_env = "TAOTOKEN_API_KEY" timeout_seconds = 60 [[agents]] name = "researcher" endpoint = "http://127.0.0.1:8081/a2a" capabilities = ["search", "summarize"] auth = "bearer" [[agents]] name = "coder" endpoint = "http://127.0.0.1:8082/a2a" capabilities = ["code_gen", "code_review"] auth = "bearer"orchestrator段是编排层自己的模型配置,指向 TaoToken。agents数组是下游 Agent 注册表,每个 Agent 有独立 endpoint 和能力列表。编排层根据任务类型路由到不同 Agent。
4.2 agent card 的 JSON 骨架
每个 Agent 启动时要暴露一份 card,通常挂在/.well-known/agent.json:
{ "name": "researcher", "description": "负责检索与摘要的 Agent", "url": "http://127.0.0.1:8081/a2a", "version": "0.1.0", "capabilities": { "streaming": true, "pushNotifications": false }, "skills": [ { "id": "search", "name": "网页检索", "inputModes": ["text"], "outputModes": ["text"] } ], "authentication": { "schemes": ["bearer"] } }capabilities.streaming决定是否支持 SSE 流式返回,skills是能力清单,编排层靠它做路由。authentication声明认证方式,企业环境里通常还要接 OAuth,这里先用 bearer 演示。
4.3 从 MCP 迁到 A2A 时配置的对应关系
| MCP 字段 | A2A 对应 | 说明 |
|---|---|---|
| command / args | url / endpoint | 从「启动进程」变成「访问服务」 |
| env | authentication | 从环境变量传 key 变成认证声明 |
| autoApprove | capabilities | 从工具白名单变成能力声明 |
| tools/list | skills | 能力发现机制不同,语义相近 |
这张表是迁移时最容易对照的,配置字段换名之后,验证思路也要跟着换。
5. 验证请求与成功结果:从 tools/call 到 message/send
MCP 阶段验证看tools/call,A2A 阶段验证看message/send。下面给出两段可直接跑的验证请求。
5.1 验证 A2A Agent 是否可达
先拉 agent card:
curl http://127.0.0.1:8081/.well-known/agent.json返回里能看到name、skills、capabilities就说明 Agent 起来了。然后发一条 JSON-RPC 请求:
curl -X POST http://127.0.0.1:8081/a2a \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": "req-001", "method": "message/send", "params": { "message": { "role": "user", "parts": [{"type": "text", "text": "帮我检索 MCP 与 A2A 的区别"}] } } }'成功返回的结构大致是:
{ "jsonrpc": "2.0", "id": "req-001", "result": { "task": { "id": "task-abc", "status": {"state": "completed"}, "artifacts": [ {"parts": [{"type": "text", "text": "MCP 关注工具调用,A2A 关注 Agent 间通信..."}]} ] } } }看到status.state是completed且有artifacts,说明整条链路通了。如果state停在working,多半是下游 Agent 在等模型返回,检查 TaoToken 的 key 和 base_url 是否配在编排层。
5.2 验证编排层路由是否正确
编排层要能根据任务类型选对 Agent。可以发两类任务,看日志里路由到哪个 endpoint:
curl -X POST http://127.0.0.1:8080/orchestrate \ -H "Content-Type: application/json" \ -d '{"task": "写一个快速排序", "type": "code"}'如果日志显示路由到coder的 8082 端口,说明capabilities匹配逻辑生效。路由错了,通常是skills里的id和编排层的匹配规则对不上,回去检查config.toml和 agent card 是否一致。
6. 本篇常见错排查
报错一:MCP server 启动失败,提示command not found。多数是npx或node不在客户端的 PATH 里。Claude Desktop 这类 GUI 应用继承的环境变量和终端不一样,把command写成绝对路径,比如/usr/local/bin/npx,能解决大部分问题。
报错二:模型请求返回 401。检查OPENAI_API_KEY或TAOTOKEN_API_KEY是否真的注入到了进程环境。用env | grep TAOTOKEN确认,别只看配置文件里写了。另外确认 base_url 是https://taotoken.net/api,不要多加/v1之外的路径。
报错三:A2A 请求返回method not found。JSON-RPC 的方法名大小写敏感,message/send不能写成message.Send。另外确认 Agent 端实现了对应方法,有些轻量实现只支持tasks/send,看 agent card 里的声明。
报错四:agent card 拉不到,404。路径必须是/.well-known/agent.json,这是约定位置。如果你挂在别的路径,编排层要显式配置 discovery URL,不能靠默认发现。
报错五:流式返回中断。A2A 的 SSE 流式依赖capabilities.streaming为 true,且中间层不能缓冲。如果你前面挂了反向代理,确认它没有开启响应缓冲,否则 SSE 会被攒成一坨再发。
报错六:MCP 工具调用被拒。检查autoApprove白名单,写操作默认要手动确认。如果客户端弹了确认框但你没看到,可能是 UI 被遮挡,看日志里有没有approval required。
7. 下一步:把配置骨架固化成模板
MCP 到 A2A 的演进,落到工程上就是配置骨架的替换和验证动作的替换。我的做法是把两份骨架都存成模板:mcp-template.json和a2a-template.toml,新项目直接复制改字段,不重新发明。模型接入层始终指向 TaoToken,这样协议怎么换,key 和 base_url 都不用动。
如果你还在 MCP 阶段,先把settings.json跑通,用模型对话页面确认模型通道没问题;如果你已经在设计多 Agent 协作,去接入文档看 A2A 相关的客户端写法,把 agent card 和config.toml对齐;长期跑编码类 Agent 任务的话,Coding Plan 的额度模型比按次调用更划算,适合高频编排场景。配置这东西,跑通一次就存下来,下次换协议只改骨架,不改脑子。