stacked on #17402. MCP tools returned by `tool_search` (deferred tools) get registered in our `ToolRegistry` with a different format than directly available tools. this leads to two different ways of accessing MCP tools from our tool catalog, only one of which works for each. fix this by registering all MCP tools with the namespace format, since this info is already available. also, direct MCP tools are registered to responsesapi without a namespace, while deferred MCP tools have a namespace. this means we can receive MCP `FunctionCall`s in both formats from namespaces. fix this by always registering MCP tools with namespace, regardless of deferral status. make code mode track `ToolName` provenance of tools so it can map the literal JS function name string to the correct `ToolName` for invocation, rather than supporting both in core. this lets us unify to a single canonical `ToolName` representation for each MCP tool and force everywhere to use that one, without supporting fallbacks.
codex-tools
codex-tools is intended to become the home for tool-related code that is
shared across multiple crates and does not need to stay coupled to
codex-core.
Today this crate is intentionally small. It currently owns the shared tool
schema and Responses API tool primitives that no longer need to live in
core/src/tools/spec.rs or core/src/client_common.rs:
JsonSchemaAdditionalPropertiesToolDefinitionToolSpecConfiguredToolSpecResponsesApiToolFreeformToolFreeformToolFormatToolSearchOutputToolResponsesApiWebSearchFiltersResponsesApiWebSearchUserLocationResponsesApiNamespaceResponsesApiNamespaceTool- code-mode
ToolSpecadapters andexec/waitspec builders - JS REPL spec builders
- MCP resource,
list_dir, andtest_sync_toolspec builders - local host tool spec builders for shell/exec/request-permissions/view-image
- collaboration and agent-job
ToolSpecbuilders for spawn/send/wait/close,request_user_input, and CSV fanout/reporting - discoverable-tool models, client filtering, and
ToolSpecbuilders fortool_searchandtool_suggest parse_tool_input_schema()parse_dynamic_tool()parse_mcp_tool()create_tools_json_for_responses_api()mcp_call_tool_result_output_schema()tool_definition_to_responses_api_tool()dynamic_tool_to_responses_api_tool()mcp_tool_to_responses_api_tool()mcp_tool_to_deferred_responses_api_tool()augment_tool_spec_for_code_mode()tool_spec_to_code_mode_tool_definition()
That extraction is the first step in a longer migration. The goal is not to
move all of core/src/tools into this crate in one shot. Instead, the plan is
to peel off reusable pieces in reviewable increments while keeping
compatibility-sensitive orchestration in codex-core until the surrounding
boundaries are ready.
Vision
Over time, this crate should hold tool-facing primitives that are shared by multiple consumers, for example:
- schema and spec data models
- tool input/output parsing helpers
- tool metadata and compatibility shims that do not depend on
codex-core - other narrowly scoped utility code that multiple crates need
The corresponding non-goals are just as important:
- do not move
codex-coreorchestration here prematurely - do not pull
Session/TurnContext/ approval flow / runtime execution logic into this crate unless those dependencies have first been split into stable shared interfaces - do not turn this crate into a grab-bag for unrelated helper code
Migration approach
The expected migration shape is:
- Move low-coupling tool primitives here.
- Switch non-core consumers to depend on
codex-toolsdirectly. - Leave compatibility-sensitive adapters in
codex-corewhile downstream call sites are updated. - Only extract higher-level tool infrastructure after the crate boundaries are clear and independently testable.
That means it is normal for codex-core to temporarily re-export types or
helpers from codex-tools during the transition.
Crate conventions
This crate should start with stricter structure than core/src/tools so it
stays easy to grow:
src/lib.rsshould remain exports-only.- Business logic should live in named module files such as
foo.rs. - Unit tests for
foo.rsshould live in a siblingfoo_tests.rs. - The implementation file should wire tests with:
#[cfg(test)]
#[path = "foo_tests.rs"]
mod tests;
If this crate starts accumulating code that needs runtime state from
codex-core, that is a sign to revisit the extraction boundary before adding
more here.