先回答一个很多朋友私下问过我的问题:你现在桌面上同时装着 Claude Code、Codex、Cursor,甚至还有 Hermes Agent,每换一个工具,是不是都要把 MCP 服务器的地址、命令参数、环境变量重新填一遍?如果还要给每个工具单独配一套技能目录,那基本就是在配置地狱里反复横跳。我前阵子把这几个 agent 的配置方式全部捋了一遍,搞了一套本机统一的方案:所有 agent 共用同一份 MCP 服务器清单,技能库也只维护一份,新增一个工具服务只需要改一个 JSON 文件,其他 agent 自动就能认到。这套东西我自己跑了快两个月,稳定性和效率都超出预期,今天把完整思路、踩过的坑和实现细节分享出来。
1. 配置地狱是怎么形成的:为什么同一个 MCP 要配四次
1.1 每个 agent 都在维护自己的“方言配置”
先说个最直观的现象。MCP(Model Context Protocol)明明是个标准协议,服务器端根本不需要知道客户端是谁,只要按协议暴露工具接口就行。但问题出在客户端这一侧:MCP 的服务器列表是配置在每个 agent 自己的配置文件里的,协议标准不负责帮你同步这份清单。
我最早同时用 Cursor 和 Claude Code 的时候,给本地加了一个向量检索服务。当时操作很机械:先在 Cursor 的设置里通过界面添加 MCP 服务器,填上启动命令和参数;然后跑到 Claude Code 那边,执行一次claude mcp add,把同样的内容再敲一遍;后来装了 Codex,发现它的配置格式是 TOML,同样的服务器信息又要换一种写法;再后来折腾 Hermes Agent,它的配置又是 YAML 风格。同一个服务的描述信息,我硬是写了四种方言。
这还只是一个服务器。当你的本地服务数量超过五个,比如数据库查询工具、浏览器自动化工具、定时任务调度器、内部 API 调试器,每次新增或者调整参数,就要把所有 agent 的配置全部过一遍。漏掉任何一个,那个 agent 里就看不到对应工具,排查起来还特别隐蔽——因为错误提示只会告诉你“工具不存在”,不会告诉你“工具在其他三个 agent 里都在用”。
1.2 MCP 协议统一了,入口却散落在各自角落
很多人以为 MCP 标准化之后,配置文件也能统一。这个误解坑了我一阵子。MCP 标准确实规定了客户端和服务器之间怎么通信、工具列表怎么暴露、调用请求怎么返回,但“每个客户端加载哪些服务器”完全是客户端自己的事。
各家的配置文件不仅格式不同,所在位置也各不相同。有的放在用户主目录下,有的放在应用数据目录里,还有的既支持全局配置又支持项目级配置。我整理过一个简单的对照表,每次想起来都觉得离谱:
| Agent 工具 | 配置文件常见位置 | 配置格式 | MCP 服务器写法特点 |
|---|---|---|---|
| Cursor | ~/.cursor/mcp.json或项目内.cursor/mcp.json | JSON | 需要mcpServers顶层键,支持 stdio 和 streamable HTTP |
| Claude Code | ~/.claude.json或项目内.claude/settings.json | JSON | 支持 CLI 命令claude mcp add,也有 marketplace 机制 |
| Codex | ~/.codex/config.toml | TOML | MCP 配置写在[mcp_servers.xxx]段落里 |
| Hermes Agent | 各发行版自定义路径 | YAML / JSON | 更像通用 agent 框架,配置项自由度大 |
这个表格不是让你背,而是想说明一个问题:协议统一解决的是“连上之后怎么办”,配置分裂解决的是“连哪些服务器”。后者恰恰是每个工具各自为政的环节。想做到 0 配置,不是去改 MCP 协议,而是要在客户端配置这一层做收敛。
1.3 技能的割裂比 MCP 更隐蔽
MCP 的问题好歹还有协议文档可查,技能(skills)的割裂就更隐蔽了。不同 agent 对“技能”的定义差别很大:有些把技能理解为一组预置 prompt,有些理解成可复用的命令脚本,有些干脆指的就是插件市场里安装的扩展包。
我之前给其中一个 agent 写了一套代码审查技能,包含审查规则、常见漏洞检查点、输出格式模板。当时只配在那一个工具里,后来想在其他 agent 里也用,发现复制过去根本没法直接用——因为不同工具对技能文件的目录结构、元信息格式、加载时机的要求都不一样。有些是 Markdown 文件约定特定 frontmatter,有些是 YAML 里写 name、description、trigger 字段,还有些要求必须是可执行脚本而不是文档。
这个问题的本质和 MCP 一样:概念是通用的,承载方式是私有的。所以后来我做统一方案的时候,没有去追求“一个格式通吃所有技能”,而是做了一个中间层,把技能按统一格式维护,再针对每个 agent 生成各自能识别的形态。这个思路下文会展开。
1.4 从配置零散到 0 配置:一条清晰的收敛路径
把问题梳理清楚之后,目标就明确了:不再去直接编辑各个 agent 的配置文件,而是维护一份“源配置”,用程序自动生成或同步所有 agent 的配置。这样你的操作只有一次:改源配置。其他 agent 的配置文件由系统负责更新。
用一句大白话说,就是给所有 agent 配一个“翻译官”。我输入的是一份标准 JSON,翻译官负责把这段 JSON 转成 Cursor 懂的 JSON、Claude Code 懂的 JSON、Codex 懂的 TOML、Hermes Agent 懂的 YAML。这个翻译官就是整个方案的核心。
当然,光有翻译还不够。如果每次改完源配置还要手动跑一遍翻译命令,那只是把“改四个文件”变成了“改一个文件再跑一次命令”,省事但不够“0 配置”。所以我在翻译层外面又加了一层文件监听,源配置一变化,自动重新生成所有目标配置文件,顺带通知各 agent 重新加载。这才是真正实现了“只改一处、全局生效”。
2. 统一配置方案的核心设计思路
2.1 先定边界:统一什么、不统一什么
设计这套方案之前,我花了不少时间想一个问题:到底哪些东西适合统一,哪些东西不适合。统一不是越彻底越好,硬把不该统一的也拉到一起,只会让整个体系变得脆弱。
我最终定的边界是这样的:MCP 服务器清单、服务器启动参数、环境变量映射、技能内容库,这四类属于“全局共享信息”,统一维护;项目级专属配置、权限控制、单个 agent 的高级调优参数,这三类不纳入统一范围。原因很简单,前面四类描述的是“本机有哪些能力可用”,后面三类描述的是“在具体场景下怎么用这些能力”,两者的变更频率和影响范围完全不同。
举个例子,数据库 MCP 服务器的地址和连接凭据,无论哪个 agent 来调都一样,必须统一;但某个项目希望 Cursor 用更严格的代码审查规则,而 Claude Code 那边保持默认,这种差异就应该留在项目级配置里,不该强行抹平。方案做好了,配置边界清晰了,后续维护才不会越搞越乱。
2.2 中心化配置库加适配层:一个源头、多端翻译
整套架构其实就两层:中心化配置库和适配层。配置库负责存放所有 MCP 服务器的原始定义,每一项都是一个独立 JSON 文件;适配层负责读取这些 JSON,按各 agent 的目标格式生成对应配置。
服务器定义文件我设计成这个样子:
{ "name": "db-query", "description": "本地数据库查询服务", "transport": "stdio", "command": "node", "args": ["/opt/agents/servers/db-query/dist/index.js"], "env": { "DB_HOST": "127.0.0.1", "DB_PORT": "5432" }, "enabled": true }字段看起来简单,但每个字段都是经过斟酌的。transport字段指定连接方式,适配层会根据这个字段决定在目标配置里写 stdio 参数还是 streamable HTTP 地址;command和args是给 stdio 型服务用的启动指令;env里放的是这个服务运行时需要的环境变量。写清楚这几个字段,任何 agent 要启动这个服务,拿到的信息都是完整的。
适配层要做的事情,用伪代码描述就是这样:
for agent in ["cursor", "claude", "codex", "hermes"]: config = load_all_servers() translated = translate(config, agent) write_config(agent, translated)实际实现里,每个 agent 的翻译逻辑都是独立的函数模块,因为它们的输出格式差异太大。Cursor 那边输出 JSON,Codex 那边要合成 TOML,Claude Code 我干脆直接调它的 CLI 命令逐条写入,这样能实时生效。这个“每个目标都独立处理”的设计虽然看起来笨,但维护起来反而最稳。
2.3 关键取舍:为什么不用插件市场替代本地配置中心
有人可能会问:Claude Code 不是有 marketplace 机制吗?直接用远程插件市场统一拉取不就行了?这个问题我在设计初期也认真考虑过,最后决定不用它作为主通道,理由有三条。
第一条,插件市场解决的是“发现和分发”,解决不了“本机私有服务”。我的很多 MCP 服务器指向的是localhost上的服务,启动脚本就在本地某个目录里,这些内容推到公共市场毫无意义。第二条,市场的更新节奏是“发布者推送、使用方拉取”,而本地配置的更新节奏是“我改完立刻生效”,两者的实时性差很远。第三条,也是最实际的,不是所有 agent 都有成熟的市场机制,Hermes Agent 这类框架更多还是靠本地配置。
本地配置中心的定位不是替代插件市场,而是作为“本机私有能力层”,市场负责的公共能力分发保持原样不动。这样两条腿走路,既能享受生态的红利,又能保证私有配置的便捷和安全,彼此的边界非常清晰。
3. 实操:从零搭建全 agent 共享配置体系
3.1 第一步:盘点本机 agent 的配置现状
动手之前,先花十分钟盘一下现状,能避免后面一大堆返工。我给自己的操作顺序是这样的:先把每个 agent 当前的配置文件目录和格式摸清楚,再确定哪些 MCP 服务器是重复配置的,哪些只在一个 agent 里配置过但其他 agent 也需要用到。
我在一个临时目录里执行了这样一组命令来摸家底:
# Cursor 全局 MCP 配置 find ~/.cursor -name "mcp.json" -maxdepth 2 2>/dev/null # Claude Code 配置文件 ls -la ~/.claude.json ~/.claude/settings.json 2>/dev/null # Codex 配置 ls -la ~/.codex/config.toml 2>/dev/null # Hermes Agent 配置 find ~/.hermes -name "*.yaml" -o -name "*.yml" -maxdepth 2 2>/dev/null跑完之后,把每个文件里已经配置的服务器名列个清单,标注来源和传输类型。这里有个很实用的技巧:用jq直接提取 JSON 配置里的键名,用grep从 TOML 里抓[mcp_servers.*]段落,不用打开编辑器慢慢看。
这份盘点结果价值很大。我当时就发现有一个数据库服务只在 Cursor 里配过,Claude Code 里一直没配,之前还总奇怪为什么那个 agent 调不到数据库工具。这种“配置遗漏”在多个 agent 并存的环境里非常常见,盘点阶段能帮你一次性补齐。
3.2 第二步:搭建统一配置根目录与服务探测脚本
盘点完之后,我建立了统一的配置根目录结构,设计成了一个很好扩展的布局:
~/agents/ ├── config/ │ ├── servers/ │ │ ├── db-query.json │ │ ├── browser-pilot.json │ │ └── api-debugger.json │ └── skills/ │ ├── code-review.md │ └──>{ "name": "db-query", "command": "node", "args": ["{{AGENT_ROOT}}/servers/db-query/dist/index.js"], "env": { "DB_HOST": "{{DB_HOST}}" } }团队成员拉取代码后,执行一次初始化脚本,脚本会提示填写AGENT_ROOT和DB_HOST等变量,自动生成本地实况配置。这套模板机制我只是在内部小范围用过,效果不错,既保持了团队统一,又兼顾了个体差异。如果你要复刻,记得把secrets.env排除在版本库之外,用.gitignore把它牢牢挡住。
4.6 针对不同 agent 版本的适配变化
Agent 工具的版本迭代非常快,配置格式经常微调。我自己遇到过 Cursor 某次升级后,对 MCP 配置里未知字段的容忍度明显变低,以前能忽略的字段现在会导致整个配置加载失败。这类问题没有一劳永逸的解法,只能靠适配器设计时预留“版本开关”。
我在每个适配器文件头部加了一个版本字典,标明“当前适配器已验证可用的 Agent 最低版本”。升级某个工具后,如果发现配置同步异常,第一件事就是查这个版本字典,确认是不是适配器跟不上新格式。如果确实是适配器问题,修复改动通常很小,改一个键名或调整一下字段结构就行。
这块的维护频率不需要太高,我两个月下来也就改过两三次,但每次改完都顺手在日志里记一条“适配变更说明”,下次再遇到类似问题直接翻日志,不用重新试错。
关于这套方案的几点真实体会
整个方案跑下来,我最大的体会是:配置统一这件事,难点从来不在写代码,而在边界划分。什么该统一、什么该保留差异,想清楚了,实现起来就是个翻译脚本加文件监听的问题。你以为会遇到很多技术障碍,实际上大多数坑都出在“没想到某个 agent 的配置文件优先级机制”或者“忘记某个服务需要特殊环境变量”这种细节上。
如果你现在也维护着多个 agent,我建议千万别一上来就搞全套适配器,先把 MCP 服务器清单一列,看看到底重复配置了多少。如果只是两三个服务,手动同步虽然烦但成本还能接受;一旦超过五个,统一配置方案的价值就很明显了。最后说个偏方:我在中心目录里专门放了一个_notes.json,记录每次同步后各 agent 的实际加载情况,看起来像是多余的配置,但排查时它救过我很多次。配置系统越复杂,越需要一个“事实来源”记录每个 agent 到底在用哪些配置,这个习惯推荐给你。