## Why We already plan to remove the shell-tool MCP path, and doing that cleanup first makes the follow-on `shell-escalation` work much simpler. This change removes the last remaining reason to keep `codex-rs/exec-server` around by moving the `codex-execve-wrapper` binary and shared shell test fixtures to the crates/tests that now own that functionality. ## What Changed ### Delete `codex-rs/exec-server` - Remove the `exec-server` crate, including the MCP server binary, MCP-specific modules, and its test support/test suite - Remove `exec-server` from the `codex-rs` workspace and update `Cargo.lock` ### Move `codex-execve-wrapper` into `codex-rs/shell-escalation` - Move the wrapper implementation into `shell-escalation` (`src/unix/execve_wrapper.rs`) - Add the `codex-execve-wrapper` binary entrypoint under `shell-escalation/src/bin/` - Update `shell-escalation` exports/module layout so the wrapper entrypoint is hosted there - Move the wrapper README content from `exec-server` to `shell-escalation/README.md` ### Move shared shell test fixtures to `app-server` - Move the DotSlash `bash`/`zsh` test fixtures from `exec-server/tests/suite/` to `app-server/tests/suite/` - Update `app-server` zsh-fork tests to reference the new fixture paths ### Keep `shell-tool-mcp` as a shell-assets package - Update `.github/workflows/shell-tool-mcp.yml` packaging so the npm artifact contains only patched Bash/Zsh payloads (no Rust binaries) - Update `shell-tool-mcp/package.json`, `shell-tool-mcp/src/index.ts`, and docs to reflect the shell-assets-only package shape - `shell-tool-mcp-ci.yml` does not need changes because it is already JS-only ## Verification - `cargo shear` - `cargo clippy -p codex-shell-escalation --tests` - `just clippy`
4.8 KiB
@openai/codex-shell-tool-mcp
Note: This MCP server is still experimental. When using it with Codex CLI, ensure the CLI version matches the MCP server version.
@openai/codex-shell-tool-mcp is an MCP server that provides a tool named shell that runs a shell command inside a sandboxed instance of Bash. This special instance of Bash intercepts requests to spawn new processes (specifically, execve(2) calls). For each call, it makes a request back to the MCP server to determine whether to allow the proposed command to execute. It also has the option of escalating the command to run unprivileged outside of the sandbox governing the Bash process.
The user can use Codex .rules files to define how a command should be handled. The action to take is determined by the decision parameter of a matching rule as follows:
allow: the command will be escalated and run outside the sandboxprompt: the command will be subject to human approval via an MCP elicitation (it will run escalated if approved)forbidden: the command will fail with exit code1and an error message will be written tostderr
Commands that do not match an explicit rule in .rules will be allowed to run as-is, though they will still be subject to the sandbox applied to the parent Bash process.
Motivation
When a software agent asks if it is safe to run a command like ls, without more context, it is unclear whether it will result in executing /bin/ls. Consider:
- There could be another executable named
lsthat appears before/bin/lson the$PATH. lscould be mapped to a shell alias or function.
Because @openai/codex-shell-tool-mcp intercepts execve(2) calls directly, it always knows the full path to the program being executed. In turn, this makes it possible to provide stronger guarantees on how Codex .rules are enforced.
Usage
First, verify that you can download and run the MCP executable:
npx -y @openai/codex-shell-tool-mcp --version
To test out the MCP with a one-off invocation of Codex CLI, it is important to disable the default shell tool in addition to enabling the MCP so Codex has exactly one shell-like tool available to it:
codex --disable shell_tool \
--config 'mcp_servers.bash={command = "npx", args = ["-y", "@openai/codex-shell-tool-mcp"]}'
To configure this permanently so you can use the MCP while running codex without additional command-line flags, add the following to your ~/.codex/config.toml:
[features]
shell_tool = false
[mcp_servers.shell-tool]
command = "npx"
args = ["-y", "@openai/codex-shell-tool-mcp"]
Note when the @openai/codex-shell-tool-mcp launcher runs, it selects the appropriate native binary to run based on the host OS/architecture. For the Bash wrapper, it inspects /etc/os-release on Linux or the Darwin major version on macOS to try to find the best match it has available. See bashSelection.ts for details.
MCP Client Requirements
This MCP server is designed to be used with Codex, as it declares the following capability that Codex supports when acting as an MCP client:
{
"capabilities": {
"experimental": {
"codex/sandbox-state": {
"version": "1.0.0"
}
}
}
}
This capability means the MCP server honors requests like the following to update the sandbox policy the MCP server uses when spawning Bash:
{
"id": "req-42",
"method": "codex/sandbox-state/update",
"params": {
"sandboxPolicy": {
"type": "workspace-write",
"writable_roots": ["/home/user/code/codex"],
"network_access": false,
"exclude_tmpdir_env_var": false,
"exclude_slash_tmp": false
}
}
}
Once the server has processed the update, it sends an empty response to acknowledge the request:
{
"id": "req-42",
"result": {}
}
The Codex harness (used by the CLI and the VS Code extension) sends such requests to MCP servers that declare the codex/sandbox-state capability.
Package Contents
This package currently publishes shell binaries only. It bundles:
- A patched Bash that honors
EXEC_WRAPPER, built for multiple glibc baselines (Ubuntu 24.04/22.04/20.04, Debian 12/11, CentOS-like 9) and macOS (15/14/13). - A patched zsh with
EXEC_WRAPPERsupport for the same supported target triples.
It does not currently include the Rust MCP server binaries.
See the README in the Codex repo for details.