MCP 接进来:模型看见翻译过的名字
外部 server 的工具要先过一层翻译才进模型眼睛。skill 目录常在,缺 MCP 时另问人。
本页解决的问题
先给结论「MCP 接进来:模型看见翻译过的名字」要解决的关键问题是什么?
外部 server 的工具要先过一层翻译才进模型眼睛。skill 目录常在,缺 MCP 时另问人。
跟着交接处走,不要只看 Demo。 系统是否可靠,往往取决于模型、工具、状态、权限和人的交接处。把每次交接都当成可以观察、测试和恢复的地方。
为一个自动化步骤写清输入、负责人、审批和恢复动作。
一次运行成功了,却说不清发生了什么,也无法安全重放。
- 连接集整份发布,已有 binding 继续拿自己那份连接runtime.rs L246
- 各家 tools/list 汇成一张表,再交给命名翻译tool_catalog.rs L153
- 给命名空间加上历史前缀 mcp__tools.rs L228
- 非法字符洗成下划线,只留字母数字和下划线mcp/mod.rs L477
- 完全相同的原始身份丢掉一份tools.rs L134
- 清洗后命名空间撞车,末尾加 12 位 SHA-1tools.rs L166
- 清洗后工具名撞车,同样加 12 位哈希tools.rs L193
- 合起来超过 128 字节就截断再哈希,协议调用仍走原名tools.rs L226
你把 codex mcp-server 写进 Cursor 的 MCP 配置。Cursor 当 client,Codex 当 server。若这一次 tools/list 把内部 GitHub 工具一并交出去,IDE 调一次就摸到内部能力。权限边界从「调一次 Codex」扩成「直接调内部工具」。
crate 拆成两套。mcp-server 从 stdin 读行,一行一条 JSON。initialize 只打开 tools。tools/list 写死两个名字:codex 和 codex-reply。codex 会 start_thread,nested thread 再起自己的 McpRuntime。codex-mcp 管连接集,外部 server 的工具另做一份目录。
出处:codex-rs/mcp-server/src/lib.rs 第 131 至 152 行;codex-rs/mcp-server/src/codex_tool_runner.rs 第 66 至 90 行;codex-rs/codex-mcp/src/runtime.rs 第 88 至 98 行
同一份 JSON-RPC 线协议,处理器不是同一个。早期资料常把它们画成同一个 runtime 的两张脸。当前源码里它们甚至不共享 MessageProcessor。
出处:codex-rs/mcp-server/src/message_processor.rs 第 274 至 277 行;codex-rs/mcp-server/src/message_processor.rs 第 336 至 348 行
对外承诺和对内能力分开,是网关的通用形状。换语言也是两个函数:hosted 返回 run / continue,external 返回 mcp__*。IDE 只看见入口,会话里才看见外部店。
两家店都报 search,前缀还能分开。一家叫 basic-server,一家叫 basic_server,连字符洗成下划线之后,命名空间会撞。模型看见两个同名工具,下一次调用就不知道进哪家店。API 还有字节上限。
server 接进来,先把各家 tools/list 汇成一张表,再走 normalize_tools_for_model_with_prefix。顺序是固定的四步。
1. 给命名空间加上 mcp__ 前缀。
2. 非法字符洗成下划线,只留字母、数字和 _。
3. 完全相同的原始身份丢掉一份。清洗后命名空间或工具名还撞,就在末尾加 12 位 SHA-1。
4. 合起来超过 128 字节,截断再哈希。原始 server_name 和 tool.name 留在 ToolInfo 上,协议调用走原名。
出处:codex-rs/codex-mcp/src/tools.rs 第 105 至 117 行;codex-rs/codex-mcp/src/tools.rs 第 134 至 137 行;codex-rs/codex-mcp/src/tools.rs 第 166 至 194 行;codex-rs/codex-mcp/src/tools.rs 第 226 至 227 行;codex-rs/codex-mcp/src/mcp/mod.rs 第 477 至 485 行
给模型看的名字和协议上的名字本来就是两层。一层给人读、给 API 用,一层用来寻址。哈希消歧是撞名问题的通用答法。上限数字会变,这层翻译不会变。
若按 MCP 存活过滤目录,冷启动那几秒模型会以为 skill 不存在,下一轮又突然出现。说明书整份灌进每一轮,上下文也会被吃光。
点名记号是 $。目录只看 enabled 和 prompt_visible。用户点了名,或者任务和描述对得上,这一轮才读 SKILL.md 正文。Guardian 评审会话直接返回空注入,父 transcript 里的 $skill 不能再触发新说明书。
出处:codex-rs/skills/src/mentions.rs 第 41 行;codex-rs/ext/skills/src/catalog.rs 第 261 至 263 行;codex-rs/core/src/session/turn.rs 第 766 至 770 行;codex-rs/core/src/session/turn.rs 第 808 至 817 行
缺 MCP 时另问人。first-party 且功能开关开,才弹出 Install MCP servers。审批是 Never 就静默跳过。用户选 Continue anyway,目录还在,对应工具可能仍不可用。
出处:codex-rs/core/src/mcp_skill_dependencies.rs 第 47 至 60 行;codex-rs/core/src/mcp_skill_dependencies.rs 第 268 至 270 行
发现和就绪是两件事。索引先给,全文按需再给,缺依赖问人,不要把条目从目录里抹掉。装不装是配置变更,列不列是发现。
DSH:只桥 tools,一条插件对一台 server
DSH 的 MCP 客户端把范围写死:连一台外部 server,工具注册到 ctx.tools,公开名是 mcp__<serverName>__<rawName>。干净情况原样拼接。字符或长度被改过,就在末尾加 12 位 SHA-256。上限 64 字符。卸载就断连、注销、放命名空间。
出处:packages/mcp/mcp-client/src/index.ts 第 1 至 14 行;packages/mcp/mcp-client/src/tools.ts 第 96 至 102 行
没有 elicitation,也不把自己交出去当 MCP server。外部工具失败仍按普通 tool 失败处理。哈希长度碰巧也是 12,算法和拼接规则不同。
已核对源码 · 2026-08-22 · DSH · MCP 与扩展Claude Code:skill 是一等 tool
Claude Code 给模型一个 Skill tool。模型 call 才拿正文。注释写明同一时间只跑一个 skill,因为 tool 会把命令展开成整份 prompt。
出处:restored-src/src/tools/SkillTool/SkillTool.ts 第 331 至 344 行
MCP 上的 prompt 要标成 loadedFrom === 'mcp' 且 type === 'prompt',才进发现列表。方向相反:Codex 是 skill 需要 MCP,Claude Code 是 MCP 贡献 skill。触发器也不同。Codex 扫 $name,命中就注入 <skill>,不经过一次 tool call。
出处:restored-src/src/tools/SkillTool/SkillTool.ts 第 81 至 94 行
清洗之后谁还认得这家店
basic-server 报 lookup,basic_server 报 query。写出模型看见的两个命名空间,并说明调回去时凭什么还能进对的店。
再问一问:把审批改成 Never,打 $deploy 的时候,skill 目录还在不在。观察点在 is_model_visible 和 should_install_mcp_dependencies。
「先玩一遍 · 一家店接进来,名字怎么变」的能力藏在每次交接里
「你把 codex mcp-server 写进 Cursor 的 MCP 配置。Cursor 当 client,Codex 当 server。若这一次 tools/list 把内部 GitHub 工具一并交出去,IDE 调一次就摸到内部能力。权限边界从「调一次 Codex」扩成「直接调内部工具」」说明,Agent 的表现不只由模型决定。模型、上下文、工具、状态、权限和人之间的每次交接,都会改变任务能否继续以及出了问题能否恢复。
先写清状态,再增加能力
从「crate 拆成两套。」出发,可以把流程拆成起始状态、下一步动作、工具返回、状态更新和停止条件。这样调试时找的是第一处丢失信息或权限的位置,而不是笼统地说“模型变笨了”。
- 连接集整份发布,已有 binding 继续拿自己那份连接 runtime.rs L246
- 各家 tools/list 汇成一张表,再交给命名翻译 tool_catalog.rs L153
- 给命名空间加上历史前缀 mcp__ tools.rs L228
成功路径不能代表系统可靠
用「再问一问:把审批改成 Never ,打 $deploy 的时候,skill 目录还在不在。观察点在 is_model_visible 和 should_install_mcp_dependencies」重放一次成功和一次失败,记录每一轮真正传入的上下文、工具结果和负责人;只要第二个人能复述这条链,系统才有可维护性。
从「先玩一遍 · 一家店接进来,名字怎么变」走到「思路一 · 对外一份清单,对内另一份」
「先玩一遍 · 一家店接进来,名字怎么变」先把问题落在「一个 MCP server 接进来:工具怎么变成模型看得见的能力 播放 单步 重置 接入场景 干净两家 连字符双胞胎 工具名双胞胎 右边两档会撞名。切一下,看清洗之后谁被加上哈希。 第二家店 门外 · 原始 tools/list 进门 0 还没接任何人。 模型眼前 · 翻译后的名字 可见 0 清单空着。 逻辑轨迹 · 动画每一步对应源码里的哪一段 连接集整份发布,已有 binding 继续拿自己那份连接 runtim…」上;到了「思路一 · 对外一份清单,对内另一份」,讨论继续推进到「你把 codex mcp-server 写进 Cursor 的 MCP 配置。Cursor 当 client,Codex 当 server。若这一次 tools/list 把内部 GitHub 工具一并交出去,IDE 调一次就摸到内部能力。权限边界从「调一次 Codex」扩成「直接调内部工具」」。两段连起来,重点就不只是记住一个结论,而是看清它成立所依赖的条件。
把这条判断带到下一个场景
分析 Agent 时,沿着状态、动作、工具结果和下一步的顺序走一遍;每次交接都要能说明信息从哪里来、由谁确认、失败时停在哪里。
- 「先玩一遍 · 一家店接进来,名字怎么变」:一个 MCP server 接进来:工具怎么变成模型看得见的能力 播放 单步 重置 接入场景 干净两家 连字符双胞胎 工具名双胞胎 右边两档会撞名。切一下,看清洗之后谁被加上哈希。 第二家店 门外 · 原始 tools/list 进门 0 还没接任何人。 模型眼前 · 翻译后的名字 可见 0 清单空着。 逻辑轨迹 · 动画每一步对应源码里的哪一段 连接集整份发布,已有 binding 继续拿自己那份连接 runtim…
- 「思路一 · 对外一份清单,对内另一份」:你把 codex mcp-server 写进 Cursor 的 MCP 配置。Cursor 当 client,Codex 当 server。若这一次 tools/list 把内部 GitHub 工具一并交出去,IDE 调一次就摸到内部能力。权限边界从「调一次 Codex」扩成「直接调内部工具」
- 「最后的要点」:完全相同的原始身份丢掉一份 tools.rs L134
最后的「最后的要点」把讨论落到「完全相同的原始身份丢掉一份 tools.rs L134」。回看这条线索时,最值得保留的是:当输入、规模或风险改变,哪些判断需要重新做一遍。
我把这篇文章里的一个判断改写成了今天可以验证的小实验。比记住结论更有用的是,知道下一步要观察什么。
读完以后我先回头找它成立的条件,而不是直接把方法搬进项目。这个顺序让后面的取舍清楚很多。
如果把这个判断放到真实工作里,最先需要补的约束是什么?我想知道从阅读到第一次实践之间,哪一步最值得先做。
还没有这篇文章的讨论。