MCP comes in: the model sees translated names
When Codex takes an external MCP, tools pass a translation layer before the model sees them: prefix, sanitize, hash on collision. The skill catalog stays up; the body arrives only when named
THE QUESTION THIS PAGE ANSWERS
ANSWER FIRSTWhat is the key idea behind “MCP comes in: the model sees translated names”?
When Codex takes an external MCP, tools pass a translation layer before the model sees them: prefix, sanitize, hash on collision. The skill catalog stays up; the body arrives only when named
Follow the handoffs, not the demo. A system becomes dependable at the boundaries between model, tools, state, permissions, and people. Read each handoff as a place where you can observe, test, and recover.
Name the input, owner, approval, and recovery action for one automated step.
A successful run that cannot explain what happened or be safely repeated.
- The connection set is published whole; existing bindings keep their own connectionruntime.rs L246
- Each shop’s tools/list is merged into one table, then handed to name translationtool_catalog.rs L153
- Give the namespace the historical prefix mcp__tools.rs L228
- Illegal characters become underscores; only letters, digits, and _ remainmcp/mod.rs L477
- Identical raw identities drop one copytools.rs L134
- After sanitizing, a namespace collision appends 12 SHA-1 hex digitstools.rs L166
- After sanitizing, a tool-name collision gets the same 12-digit hashtools.rs L193
- Over 128 bytes together, truncate then hash; protocol calls still use the original nametools.rs L226
You write codex mcp-server into Cursor’s MCP config. Cursor is the client; Codex is the server. If this tools/list also hands out internal GitHub tools, one IDE call touches internal capability. The permission boundary grows from “call Codex once” into “call internal tools directly.”
The crate splits into two. mcp-server reads lines from stdin, one JSON per line. initialize only opens tools. tools/list hardcodes two names: codex and codex-reply. codex will start_thread; the nested thread starts its own McpRuntime. codex-mcp owns the connection set; tools from external servers get a separate catalog.
Source:codex-rs/mcp-server/src/lib.rs lines 131–152; codex-rs/mcp-server/src/codex_tool_runner.rs lines 66–90; codex-rs/codex-mcp/src/runtime.rs lines 88–98
Same JSON-RPC wire protocol; the processors are not the same. Early notes often draw them as two faces of one runtime. In the current source they do not even share a MessageProcessor.
Source:codex-rs/mcp-server/src/message_processor.rs lines 274–277; codex-rs/mcp-server/src/message_processor.rs lines 336–348
Split the outward promise from inward capability — that is the usual gateway shape. In another language it is still two functions: hosted returns run / continue, external returns mcp__*. The IDE only sees the door; the session is where the external shops appear.
Both shops report search; the prefix can still split them. One is basic-server, one is basic_server. After hyphens become underscores, the namespaces collide. The model sees two same-named tools and the next call does not know which shop to enter. The API also has a byte cap.
When a server hooks up, each shop’s tools/list is first merged into one table, then sent through normalize_tools_for_model_with_prefix. The order is a fixed four steps.
1. Prefix the namespace with mcp__.
2. Illegal characters become underscores; only letters, digits, and _ remain.
3. Identical raw identities drop one copy. If namespace or tool name still collide after sanitizing, append 12 SHA-1 hex digits.
4. Over 128 bytes together, truncate then hash. The original server_name and tool.name stay on ToolInfo; protocol calls use the original names.
Source:codex-rs/codex-mcp/src/tools.rs lines 105–117; codex-rs/codex-mcp/src/tools.rs lines 134–137; codex-rs/codex-mcp/src/tools.rs lines 166–194; codex-rs/codex-mcp/src/tools.rs lines 226–227; codex-rs/codex-mcp/src/mcp/mod.rs lines 477–485
The name the model sees and the name on the wire were always two layers. One is for humans and the API; one is for addressing. Hashing to disambiguate is the usual answer to collisions. The cap number may change; this translation layer will not.
If the catalog were filtered by MCP liveness, for those cold-start seconds the model would think the skill does not exist, then it would pop up next turn. Pouring the whole manual into every turn would also eat the context.
The mention mark is $. The catalog only looks at enabled and prompt_visible. When the user names it, or the task matches the description, this turn reads the SKILL.md body. A Guardian review session returns empty injection; a $skill in the parent transcript cannot trigger a new manual.
Source:codex-rs/skills/src/mentions.rs line 41; codex-rs/ext/skills/src/catalog.rs lines 261–263; codex-rs/core/src/session/turn.rs lines 766–770; codex-rs/core/src/session/turn.rs lines 808–817
If MCP is missing, ask a person. First-party and the feature flag on is what pops Install MCP servers. Approval Never skips silently. If the user picks Continue anyway, the catalog stays; the matching tools may still be unavailable.
Source:codex-rs/core/src/mcp_skill_dependencies.rs lines 47–60; codex-rs/core/src/mcp_skill_dependencies.rs lines 268–270
Discovery and readiness are two facts. Give the index first, the full text on demand, and ask a person when a dependency is missing — do not wipe the entry from the catalog. Install or not is a config change; list or not is discovery.
DSH: only bridge tools, one plugin per server
DSH’s MCP client hardcodes the scope: connect one external server, register tools on ctx.tools, public name mcp__<serverName>__<rawName>. The clean case concatenates as-is. If characters or length were rewritten, append 12 SHA-256 hex digits. Cap is 64 characters. Uninstall disconnects, unregisters, and frees the namespace.
Source:packages/mcp/mcp-client/src/index.ts lines 1–14; packages/mcp/mcp-client/src/tools.ts lines 96–102
No elicitation, and it does not hand itself out as an MCP server. An external tool failure is still an ordinary tool failure. The hash length happens to be 12 too; the algorithm and join rules differ.
Checked against source · 2026-08-22 · DSH · MCP and extensionsClaude Code: a skill is a first-class tool
Claude Code gives the model a Skill tool. The model calls before it gets the body. A comment says only one skill runs at a time, because the tool expands the command into a full prompt.
Source:restored-src/src/tools/SkillTool/SkillTool.ts lines 331–344
An MCP prompt only enters the discovery list if it is marked loadedFrom === 'mcp' and type === 'prompt'. The direction flips: Codex skills need MCP; Claude Code MCP contributes skills. The trigger differs too. Codex scans $name and, on a hit, injects <skill> without a tool call.
Source:restored-src/src/tools/SkillTool/SkillTool.ts lines 81–94
After sanitizing, who still knows this shop
basic-server reports lookup; basic_server reports query. Write the two namespaces the model sees, and say what still sends a call back into the right shop.
Then ask: flip approval to Never and type $deploy — is the skill catalog still there? Watch is_model_visible and should_install_mcp_dependencies.
The handoffs inside “Try it first · One shop comes in: how the name changes”
“You write codex mcp-server into Cursor’s MCP config.” shows that an Agent is not defined by the model alone. Each handoff between model, context, tools, state, permissions, and people affects both progress and recovery.
Write the state before adding capability
Starting from “The crate splits into two.”, split the workflow into starting state, next action, tool result, state update, and stop condition. Debugging then means finding the first lost piece of information or authority instead of saying vaguely that the model “got worse”.
- The connection set is published whole; existing bindings keep their own connection runtime.rs L246
- Each shop’s tools/list is merged into one table, then handed to name translation tool_catalog.rs L153
- Give the namespace the historical prefix mcp__ tools.rs L228
A happy path is not reliability
Use “Then ask: flip approval to Never and type $deploy — is the skill catalog still there?” to replay one successful and one failed run. Record the context, tool result, and owner at each turn; the workflow is maintainable when a second person can follow it without the original builder.
From “Try it first · One shop comes in: how the name changes” to “Idea 1 · One list for the outside, another for the inside”
“Try it first · One shop comes in: how the name changes” grounds the problem in “One MCP server comes in: how a tool becomes a capability the model can see Play Step Reset Hookup scene Two clean shops Hyphen twins Tool-name twins The two right-hand modes collide. Flip them and see who gets…”. “Idea 1 · One list for the outside, another for the inside” then moves it toward “You write codex mcp-server into Cursor’s MCP config. Cursor is the client; Codex is the server. If this tools/list also hands out internal GitHub tools, one IDE call touches internal capability. The permission…”. Together, they show that the lesson is not just a conclusion to remember, but a claim with conditions.
Carry the judgment into the next situation
When analyzing an Agent, trace state, action, tool result, and next step in order. Each handoff should explain where information came from, who confirmed it, and where failure stops.
- “Try it first · One shop comes in: how the name changes”: One MCP server comes in: how a tool becomes a capability the model can see Play Step Reset Hookup scene Two clean shops Hyphen twins Tool-name twins The two right-hand modes collide. Flip them and see who gets…
- “Idea 1 · One list for the outside, another for the inside”: You write codex mcp-server into Cursor’s MCP config. Cursor is the client; Codex is the server. If this tools/list also hands out internal GitHub tools, one IDE call touches internal capability. The permission…
- “The closing point”: Identical raw identities drop one copy tools.rs L134
The final “The closing point” brings the discussion to “Identical raw identities drop one copy tools.rs L134”. The useful thing to carry forward is knowing which judgments must be revisited when input, scale, or risk changes.
I turned one judgment from this article into a small experiment I could run today. Knowing what to observe next is more useful than simply remembering the conclusion.
After reading this, I first looked for the conditions behind the idea instead of copying the method into a project. That order made the later trade-offs much clearer.
When this judgment reaches real work, which constraint should be added first? I am curious which step matters most between reading and the first practical attempt.
No discussion on this article yet.