MCP elicitation: auto-approve sends content={} even when requested schema requires fields (follow-on to #9053 / PR #9196)
What variant of Codex are you using?
Codex Desktop macOS (CLI 0.131.0-alpha.9, bundle 26.513.31313)
What issue are you seeing?
When a tool is configured with approval_mode = "approve" (e.g. after the user
picks "always allow" in the desktop UI), Codex auto-accepts anyelicitation/create request that tool issues. It sends:
{ "action": "accept", "content": {} }
…regardless of whether the requested schema has required fields. For schemas
that do require fields, MCP servers reject the response and the tool call
fails.
This is a follow-on to #9053. PR #9196 fixed content: None by hardcodingSome(json!({})), which works for empty-properties approval prompts but not
for schemas with required fields. The same json!({}) literal was then copied
into codex-rs/codex-mcp/src/elicitation.rs's make_sender auto-approve
branch, propagating the limitation.
Steps to reproduce
- Run any MCP server that exposes a tool which calls
ctx.elicitwith a
schema that declares required properties — e.g. FastMCP's dict-of-options
syntax, which generates:
``json``
{
"type": "object",
"properties": {
"value": {
"type": "string",
"oneOf": [
{"const": "a", "title": "A"},
{"const": "b", "title": "B"}
]
}
},
"required": ["value"]
}
- In
~/.codex/config.toml, set the tool to auto-approve:
``toml``
[mcp_servers.<server>.tools.<tool>]
approval_mode = "approve"
(Equivalent to picking "always allow" in the Desktop UI.)
- Trigger the tool. Codex's auto-approve path returns
{action: "accept", content: {}}.
- The MCP server (FastMCP 3.3.x in our case) rejects it with:
> Elicitation response missing required 'value' field.
…because content.value is not populated.
Captured payload (verified)
Server-side log of the actual elicitation round-trip:
[elicit/req] is_raw=True schema={"type":"object","properties":{"value":{"oneOf":[{"const":"use_rewrite","title":"Proceed with compliant version"},{"const":"modify_rewrite","title":"Modify the rewrite"},{"const":"cancel","title":"Cancel"}],"type":"string","title":"Compliance choice","description":"Choose how Codex should proceed."}},"required":["value"]}
[elicit/resp] action=accept content={}
Expected behavior
For a schema with required fields, auto-approve should not silently fabricate
an accept response. Options I see (any of which would be spec-conformant):
- Return
action: "decline"(no content needed). - Skip auto-approval entirely when
requested_schema.requiredis non-empty
and prompt the user instead.
- Surface a structured error so the server can fall back to a non-elicit code
path.
Pointer to source
codex-rs/codex-mcp/src/elicitation.rs — make_sender's auto-approve branch:
if mcp_permission_prompt_is_auto_approved(...) && can_auto_accept_elicitation(&elicitation) {
return Ok(ElicitationResponse {
action: ElicitationAction::Accept,
content: Some(serde_json::json!({})),
meta: None,
});
}
can_auto_accept_elicitation already gates onrequested_schema.properties.is_empty() on main, but the observed behavior
in 0.131.0-alpha.9 fires this branch for non-empty schemas — either the check
is bypassed in the alpha build, or another reviewer/auto-approve path in the
desktop bundle reaches the same json!({}) literal.
Why this matters
MCP elicitation is the standard way for a tool to surface a multi-choice
prompt to the user. When users do the normal thing ("always allow this tool"),
the gate silently breaks.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗