Ability to disable built-in tools for MCP-only execution
Problem Statement
When running codex exec in headless/automated environments, there is currently no way to restrict the agent to only use MCP (Model Context Protocol) tools. This creates potential security and control concerns when you want to limit the agent's capabilities to a specific set of custom tools.
Proposed Solution
Add a configuration option (CLI flag or config setting) to disable Codex's built-in tools while keeping MCP tools available. This would enable:
- Minimum requirement: Ability to disable shell command execution
- Ideal solution: Ability to disable all built-in tools (shell, file operations, plan, apply_patch) for true MCP-only mode
Use Cases
- Running codex exec in production/headless environments with restricted capabilities
- Enforcing security policies that prevent arbitrary shell execution
- Custom workflows that rely exclusively on carefully designed MCP tools
- Better control over agent behavior in automated systems
Suggested Implementation
A --disable-builtin-tools flag (or similar) that:
- Disables built-in tools (shell, file operations, plan, apply_patch)
- Keeps MCP tools, web_search, and view_image available
- Provides clear feedback when disabled tools are attempted
Related
This request is based on PR #5001 which was closed as community contributions are not currently being accepted. However, the functionality would be valuable for users who need greater control over agent capabilities in production environments.
Thank you for considering this feature request!
3 Comments
Codex app-server native-tool allowlist contract
Problem
OpenClaw stateless research supplies exactly two dynamic tools:
web_searchandweb_fetch. Codex app-server 0.144.4 still registers the nativeupdate_planhandler unconditionally in
core/src/tools/spec_plan.rs, even when the threadhas no environments and every configurable native feature is disabled.
This means OpenClaw cannot enforce an exact two-tool model-visible surface with
the current app-server protocol. Prompt instructions and downstream rejection
are not sufficient because the unwanted tool is still advertised to the model.
Required protocol
Add a sticky app-server thread setting:
Semantics:
null: preserve the existing default native-tool behavior;[]: expose and register no Codex-native tools;dynamicToolsare independent and are never filtered bynativeTools;wrappers, shell/patch/image tools, collaboration tools, tool search, and core
utilities such as
update_planare all native for this contract;registry are built, so a filtered tool cannot be invoked by name;
canonical name is explicitly listed;
narrowed; turn settings such as
cwdorenvironmentscannot widen it;caller-supplied restriction (intersection semantics).
App-server
initializemust advertise a machine-readable capability such as:Clients must not infer support from a version string.
Canonical planner implementation
In
codex-rs/core/src/tools/spec_plan.rs, distinguish Codex-native sources fromcaller-provided
dynamic_tools. Apply the native allowlist to every nativeruntime and hosted spec before building
ToolRegistryand model-visible specs,then append the dynamic tools unchanged. Avoid a denylist and avoid special
casing
update_plan; the allowlist must automatically cover future nativetools.
Required regression test
Add a planner/app-server integration test equivalent to:
Additional required cases:
cwd/environment changes cannot widen an empty sticky allowlist;selecting the wrong handler.
OpenClaw integration after Codex ships the capability
initialize.capabilities.nativeToolAllowlist === truefor research.nativeTools: []onthread/start.environments: []and the current feature/MCP restrictionsas defense in depth, not as the authoritative boundary.
web_searchandweb_fetch.Codex versions.
@openai/codexpin only after a stable npm release containsthe capability and the upstream regression tests.
Upstream issue path
Do not open a disconnected feature request. Extend the existing upstream issue
openai/codex#6049, “Ability todisable built-in tools for MCP-only execution,” with the app-server protocol and
exact registered/visible-tool test above. Cross-reference
openai/codex#21952, whichdocuments the same class of app-server tool-capability mismatch for hosted image
generation and already links #6049.
The smallest correct upstream PR is the generic native allowlist. A dedicated
disable_planflag would unblock this one caller but would regress whenever anew unconditional native utility is added, so it is not an adequate long-term
contract.
Adding a threat-model angle: fully tool-free mode for untrusted-content review (prompt-injection safety)
We hit this need from a different direction — using
codex execas an independent cross-vendor auditor (a plan/diff authored by one model is reviewed by Codex for independence). For that, the reviewer must run fully tool-free over content that may be attacker-influenced, because the audited material itself can carry prompt-injection.The gap:
--sandbox read-onlygates tool effects but doesn't remove tools — the model still gets a shell and, per the still-open #12459 (which references #8396), read access in read-only mode isn't bounded to the workspace (a readable$HOME). So injected text in the reviewed content can reach shell execution or read credentials. We want the equivalent of Claude'sclaude -p --tools "": zero tools — no shell, no file ops, no MCP.Two things worth linking to this "disable all built-in tools" request:
tool_freeempty tool-router (validated to send zero tools), but it's scoped to helper-thread hygiene and not surfaced as a CLI flag.--disable-builtin-toolsforcodex exec(closed for contribution-policy reasons, not on merit).Ask: surface a fully tool-free mode on
codex exec(empty tool-router; ideally assertable — the init handshake reporting zero tools) so Codex can be a safe headless reviewer of untrusted content. Happy to help test.Adding an independent app-server use case: controlled automated sessions sometimes need a non-empty, exact subset of Codex-native tools—not MCP-only and not fully tool-free.
I reproduced the current gap on
codex-cli/app-server 0.145.0. The generatedThreadStartParamsschema exposes additivedynamicTools, while neitherthread/startnorturn/startprovides a restrictive native-tool selector.InitializeResponsealso exposes no machine-readable native-tool restriction capability or effective set. Current upstreammain, checked at84ccb2938bfeee481e9481244f073d27d3c672cf, retains that protocol shape.Current
mainnow includes #35054, which addstools.update_plan.enabledand verifies that disabling it removesupdate_planfrom both the model-visible and registered tool sets. That is useful progress, but a per-tool opt-out does not provide an exact non-empty subset or fail closed when future native tools are added.The
nativeToolscontract proposed in the July 15 comment above would meet this use case if it filters both advertised specifications and registered handlers, keepsdynamicToolsindependent, advertises support plus the effective native set, and remains sticky across resume and fork without allowing a turn to widen it.A concrete regression case is: request only
exec_command,apply_patch, andwrite_stdin; prove every other native tool is absent from model-visible specifications and rejected by dispatch before side effects; then prove resume and fork preserve or narrow that exact set. Without a server-enforced allowlist, clients must either refuse the session or rely on weaker post-hoc detection, which cannot guarantee restriction before side effects.Would maintainers confirm whether this generic allowlist fits the intended app-server architecture? If so, would you explicitly invite a focused external PR under the repository contribution policy? I can prepare the protocol/schema change, tool-planner and registry filtering, persistence behavior, and regression tests.