Screen MCP tool calls in Codex
Codex starts each MCP server in its configuration as a local process and talks to it over stdio. agent-chaperone goes in front of that process. It reads each tool call before the server gets it and each result before the agent does, and nothing about the server changes.
Two things about Codex differ from the JSON-configured clients, and both matter here: the configuration is TOML, and a server does not see your environment unless you forward it. This covers MCP servers only. Codex's own shell commands and patches do not go through MCP.
Install it #
npm install -g agent-chaperoneA global install matters more on Codex than elsewhere. Codex gives a server a fixed time to start, and running the proxy through npx spends part of it looking the package up.
Put a server behind it #
Servers live in ~/.codex/config.toml, one [mcp_servers.<name>] table each, and in .codex/config.toml inside a project Codex trusts. The CLI and the IDE extension read the same file. agent-chaperone wrap only edits JSON, so on Codex the change is made by hand. A server before:
[mcp_servers.filesystem]
command = "npx"
args = ["-y", "@modelcontextprotocol/server-filesystem", "/Users/me/project"]And after:
[mcp_servers.filesystem]
command = "agent-chaperone"
args = ["--server", "filesystem", "--",
"npx", "-y", "@modelcontextprotocol/server-filesystem", "/Users/me/project"]
env_vars = ["TYPESAFE_API_KEY"]
startup_timeout_sec = 30The old command moves after --, unchanged. --server names the section of the policy file that applies, and using the table's own name keeps the two easy to match. Keep any env or cwd the entry already had: they still reach the server.
Give it the API key #
Codex starts a server with a cleared environment and passes back only a short list of variables: HOME, PATH, USER, the locale and a few others. A TYPESAFE_API_KEY exported in your shell is not on that list, so without the env_vars line above the proxy never sees it and every judgment records that no model was asked.
env_vars forwards the variable by name from the environment Codex was started in, so the key is never written into the file. If Codex was started some other way and the key does not arrive, env sets it directly, at the cost of the key sitting in config.toml in plain text:
env = { TYPESAFE_API_KEY = "..." }The proxy removes its own keys before it starts the server behind it, so the server never receives TYPESAFE_API_KEY either way.
Timeouts #
startup_timeout_sec is how long Codex waits for a server to start, and tool_timeout_sec how long it waits for one call. Codex's documentation and its source disagree on the defaults, 10 and 60 seconds against 30 and 300, so set the startup one yourself rather than depend on either.
Screening adds at most one request to the model backend per call and one per result, and the benchmark method records how long those took. A tool timeout that suited the server before still suits it unless its calls were already close to the limit.
Check that it is working #
/mcp inside a Codex session, or codex mcp list from the shell, shows whether the server started. Then use the server once from the agent and read what was decided:
agent-chaperone logEach line is one call or result, with the decision and, in shadow mode, what enforcing would have done instead. A line ending in [not screened] was decided without a model, which means the key did not arrive.
What this does not cover #
- Codex's own tools. Shell commands and file patches that Codex runs itself never cross an MCP connection. Codex has hooks for them, and an adapter for those does not exist yet.
- Web search. Codex runs it as a hosted tool, not on your machine, so nothing local sees it.
- What a server does rather than what the call says. This is not a sandbox. It reads the call and the result, and a server that does something its arguments did not describe is outside it.
Next #
It starts in shadow mode, which blocks nothing. The MCP guide covers what each screen asks, how to read a shadow-mode log, and when to switch to enforce. The exact wording of every question is in the design document.