codex - 💡(How to fix) Fix codex exec: no way to allow MCP tool calls non-interactively without --dangerously-bypass-approvals-and-sandbox

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

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?

Root Cause

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?

Code Example

# /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()

---

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

---

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

---

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"

---

mcp: spike/echo_hello (completed)
{"result":"hello test"}
RAW_BUFFERClick to expand / collapse

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.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

codex - 💡(How to fix) Fix codex exec: no way to allow MCP tool calls non-interactively without --dangerously-bypass-approvals-and-sandbox