Expose server-level MCP approval defaults in codex mcp add

Open 💬 7 comments Opened May 31, 2026 by VrtxOmega
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

Summary

mcp_servers.<id>.default_tools_approval_mode is supported in config, but codex mcp add cannot set it. That leaves scripted/noninteractive setups hand-editing TOML, and JSON readbacks do not expose the server-level default.

Proposed change

Add:

codex mcp add <name> --default-tools-approval-mode <auto|prompt|approve> -- <command> [args...]

The flag would persist the existing default_tools_approval_mode field. codex mcp get --json and codex mcp list --json would include it so setup scripts can verify the result. Existing defaults and runtime approval precedence are unchanged.

Ready patch

I prepared and tested a minimal branch:

I tried to open this as a pull request, but GitHub shows: "An owner of this repository has limited the ability to open a pull request to users that are collaborators on this repository." Filing this issue so the tested patch is visible and easy to cherry-pick or recreate.

Tests run

PATH=/home/rage/.cargo/bin:$PATH just test -p codex-cli --test mcp_add_remove
PATH=/home/rage/.cargo/bin:$PATH just fix -p codex-cli
git diff --check
PATH=/home/rage/.cargo/bin:$PATH cargo fmt --check -- --config imports_granularity=Item

The targeted CLI integration test passed, including valid persistence/readback and invalid-mode rejection. cargo fmt --check exited 0, with stable rustfmt warning that imports_granularity = Item is nightly-only.

Note: just fmt completed the Rust formatting phase, then failed in the Python SDK ruff phase because openai-codex-cli-bin==0.132.0 has no Linux glibc wheel for this platform. No SDK files were changed.

Related: #24135 and #13476. This is a narrow CLI/config surface improvement, not a complete resolution of all runtime MCP approval behavior.

View original on GitHub ↗

7 Comments

github-actions[bot] contributor · 1 month ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #24135

Powered by Codex Action

rpelevin · 1 month ago

I would add the flag, but keep the readback clear that this is a server-level default policy, not a persisted approval for any specific tool call.

Three things should stay separate:

  • server default approval mode;
  • explicit per-tool override;
  • one-shot runtime approval decision for a proposed call.

For codex mcp get --json / codex mcp list --json, I would expose both the value and the source:

  • server default: auto, prompt, or approve;
  • whether it was explicitly set or inherited;
  • per-tool overrides;
  • effective approval mode per tool if requested.

Acceptance tests:

  1. codex mcp add with default prompt persists default_tools_approval_mode.
  2. JSON readback shows the server default.
  3. adding a per-tool override does not erase the server default.
  4. updating the server command/args does not silently convert prior runtime approvals into a blanket approval.
  5. removing the default flag leaves explicit per-tool overrides intact unless explicitly cleared.

That keeps scripted setup ergonomic without turning a convenient default into hidden authority for future tool calls.

VrtxOmega · 1 month ago

Thanks, that separation makes sense. I updated the branch to keep the server-level default distinct from per-tool overrides and runtime approvals.

What changed:

  • codex mcp get --json / codex mcp list --json still include default_tools_approval_mode for compatibility.
  • They now also include default_tools_approval_mode_source and server_default_tools_approval: { mode, source }, where an unset server default reads back as inherited auto.
  • Configured per-tool overrides are exposed under tools.<name> with approval_mode, approval_mode_source, and effective_approval_mode.
  • codex mcp add preserves existing mcp_servers.<id>.tools.* overrides when updating command/args or changing/removing the server default.
  • Runtime approval state was not changed.

Updated branch: https://github.com/VrtxOmega/codex/tree/codex/mcp-add-default-approval-mode
New commit: https://github.com/VrtxOmega/codex/commit/04c91754e9
Compare: https://github.com/openai/codex/compare/main...VrtxOmega:codex/mcp-add-default-approval-mode

Tests:

  • PATH=/home/rage/.cargo/bin:$PATH just test -p codex-cli --test mcp_add_remove (13/13 passed)
  • PATH=/home/rage/.cargo/bin:$PATH just fix -p codex-cli
  • cd codex-rs && PATH=/home/rage/.cargo/bin:$PATH cargo fmt --check -- --config imports_granularity=Item (passes with stable rustfmt warnings about the nightly-only option)
  • git diff --check

just fmt still completes the Rust formatting phase and then hits the existing Python SDK wheel issue for openai-codex-cli-bin==0.132.0 on this Linux glibc platform; no SDK files changed.

rpelevin · 1 month ago

Nice update. This lands the important split.

The source fields are the part that matters most: scripts can distinguish "this server explicitly defaults to approve" from "this server inherited the normal default." That keeps setup automation ergonomic without turning a config convenience into hidden runtime authority.

One regression I would add before this gets picked up:

  1. add a server with --default-tools-approval-mode approve;
  2. add a per-tool override, e.g. one tool stays prompt;
  3. update the same server command/args without the default flag, so the server default falls back to inherited auto;
  4. verify the per-tool override is still present and the effective mode for that tool is still prompt;
  5. verify no prior runtime approval is represented in either JSON readback.

That proves the boundary: server config can narrow or remove the default without erasing explicit tool policy, and runtime approval remains outside persisted config.

VrtxOmega · 1 month ago

Added that regression in f381bed525:

  • starts with codex mcp add docs --default-tools-approval-mode approve -- docs-server;
  • adds a configured per-tool search override set to prompt;
  • updates the same server with codex mcp add docs -- docs-server-v2, intentionally without the default flag;
  • verifies persisted server default falls back to inherited auto;
  • verifies both get --json and list --json keep tools.search as explicit/effective prompt;
  • verifies the JSON readbacks do not expose runtime approval state.

No runtime approval code changed; this is test coverage for the config/readback boundary.

Updated branch: https://github.com/VrtxOmega/codex/tree/codex/mcp-add-default-approval-mode
Commit: https://github.com/VrtxOmega/codex/commit/f381bed525

Verification:

  • PATH=/home/rage/.cargo/bin:$PATH just test -p codex-cli --test mcp_add_remove (14/14 passed)
  • cd codex-rs && PATH=/home/rage/.cargo/bin:$PATH cargo fmt --check -- --config imports_granularity=Item (passes with stable rustfmt warnings about the nightly-only option)
  • git diff --check
rpelevin · 1 month ago

Yes, that regression is the one I would want.

The important thing it proves is the full lifecycle, not just the readback shape: explicit server default -> explicit per-tool override -> server update without the default flag -> inherited server default again, while the tool override stays explicit/effective prompt and runtime approval never leaks into persisted JSON.

I would keep the test close to that name and shape. It tells future maintainers this is an authority-boundary regression, not just a CLI serialization case. Nothing else from me.

VrtxOmega · 1 month ago

Thanks, this was genuinely helpful. The authority-boundary framing made the important regression much clearer than the original CLI/config test shape.

I folded that into the branch and will leave it here unless there’s anything else you’d want changed. Appreciate the careful review.