Skip to content

codex exec: no way to allow MCP tool calls non-interactively without --dangerously-bypass-approvals-and-sandbox #24135

Description

@gsingal

Summary

In codex exec (non-interactive), MCP tool calls are auto-cancelled because stdin is closed and no config key I can find suppresses the approval prompt. The only working bypass is --dangerously-bypass-approvals-and-sandbox, which also disables -s read-only sandboxing. Asking: what's the right way to authorize MCP tool calls in codex exec while keeping -s read-only in place?

Environment

  • codex v0.130.0 (Homebrew, macOS arm64)
  • Auth: ChatGPT subscription via codex login

Repro

Minimal STDIO MCP server with one tool:

# /tmp/spike_mcp_server.py
from mcp.server.fastmcp import FastMCP
server = FastMCP("spike")
@server.tool()
def echo_hello(name: str) -> str:
    return f"hello {name}"
server.run()

Register it and call it from codex exec:

SPIKE_HOME=$(mktemp -d)
cp ~/.codex/auth.json "$SPIKE_HOME/"
codex --help >/dev/null  # ensure binary works

CODEX_HOME="$SPIKE_HOME" codex mcp add spike -- /opt/homebrew/bin/python3 /tmp/spike_mcp_server.py

# Verify registered
CODEX_HOME="$SPIKE_HOME" codex mcp list
# Name   Command                    Args                      Env  Cwd  Status   Auth
# spike  /opt/homebrew/bin/python3  /tmp/spike_mcp_server.py  -    -    enabled  Unsupported

# Call it
CODEX_HOME="$SPIKE_HOME" codex exec --color never \
  --skip-git-repo-check -s read-only \
  "Use the spike echo_hello tool with name=test and report what it returned." \
  </dev/null

Observed

mcp: spike/echo_hello started
mcp: spike/echo_hello (failed)
user cancelled MCP tool call

The MCP child process IS spawned (verified via RUST_LOG=info: MCP server stderr (/opt/homebrew/bin/python3): [spike_mcp_server] startup pid=...), but the tool call is auto-cancelled — presumably because stdin is closed so the approval prompt's reader gets EOF and codex interprets that as "user declined".

What I tried (none of these suppress the approval)

Tried each of these in $CODEX_HOME/config.toml:

approval_policy = "never"
default_tools_approval_mode = "never"
tools_require_approval = false
mcp_approval_policy = "never"
trusted_mcp_servers = ["spike"]

[projects."<spike-cwd>"]
trust_level = "trusted"

[mcp_servers.spike]
approval_policy = "never"

(approval_policy and default_tools_approval_mode are accepted by codex without errors — session header shows approval: never — but neither prevents the MCP-call cancellation. The other keys are silently ignored.)

I also tried --ignore-user-config + -c mcp_servers.spike.command=... CLI overrides; the MCP server didn't even register that way.

What does work

--dangerously-bypass-approvals-and-sandbox makes the call succeed:

mcp: spike/echo_hello (completed)
{"result":"hello test"}

But this flag also disables -s read-only, so it's not a viable production posture for a daemon that needs to keep filesystem reads sandboxed.

What I'm trying to do

I'm migrating a personal-AI daemon (codebase: github.com/gsingal/hanuman, issue #143) from claude -p to codex exec so it doesn't burn API credits. The general-agent layer needs to call our first-party STDIO MCP server (read-only Google tools + a frozen-URL allowlist enforced server-side in Python) while keeping -s read-only codex sandboxing so the model can't read arbitrary files outside the per-call scratch dir.

Ask

What's the supported config to authorize MCP tool calls in codex exec without --dangerously-bypass-approvals-and-sandbox?

Specifically: is there a way to say "trust this MCP server's tool calls without prompting" that works alongside -s read-only?

If this isn't currently supported, would you accept a config key proposal like [mcp_servers.<name>] auto_approve_tools = true (or a global default_mcp_tools_approval_mode = "never") for the same use case other agent-framework users will hit when calling codex non-interactively?

Why I think this matters beyond my use case

Any non-interactive use of codex exec with custom MCP servers (cron jobs, headless daemons, CI-driven agents, evaluation harnesses) hits this same wall. The --dangerously-bypass-approvals-and-sandbox flag's name (correctly) discourages using it in production, but right now it's the only path to a working non-interactive MCP-tool call.

Happy to provide more repro detail, RUST_LOG output, or test a candidate fix.

Metadata

Metadata

Assignees

No one assigned

    Labels

    CLIIssues related to the Codex CLIconfigIssues involving config.toml, config keys, config merging, or config updatesenhancementNew feature or requestexecIssues related to the `codex exec` subcommandmcpIssues related to the use of model context protocol (MCP) serverssandboxIssues related to permissions or sandboxing

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions