Skip to content

Accept MCP elicitation requests so headless MCP tool calls work - #641

Open
principalwater wants to merge 2 commits into
openai:mainfrom
principalwater:fix/accept-mcp-elicitation
Open

Accept MCP elicitation requests so headless MCP tool calls work#641
principalwater wants to merge 2 commits into
openai:mainfrom
principalwater:fix/accept-mcp-elicitation

Conversation

@principalwater

Copy link
Copy Markdown

Fixes #640.

Problem

Every MCP tool call inside a plugin-driven run (/codex:rescue, codex-companion.mjs task) fails immediately. The job log shows only:

Calling my-server/my.tool.
Tool my-server/my.tool failed.

The rollout under ~/.codex/sessions/ has the real cause:

{"type": "mcp_tool_call_end",
 "invocation": {"server": "my-server", "tool": "my.tool", ...},
 "duration": {"secs": 0, "nanos": 0},
 "result": {"Err": "user rejected MCP tool call"}}

duration is 0 — the call never leaves the client.

Cause

Codex gates MCP tool calls behind an MCP elicitation (mcpServer/elicitation/request), not the exec/patch approval channel. So the approvalPolicy: "never" that buildThreadParams already sets for every thread this client starts does not cover them.

handleServerRequest answered every server-initiated request with -32601:

handleServerRequest(message) {
  this.sendMessage({
    id: message.id,
    error: buildJsonRpcError(-32601, `Unsupported server request: ${message.method}`)
  });
}

That leaves the elicitation unresolved, and codex-rs/core/src/mcp_tool_call.rs maps a missing response to ReviewDecision::Abort, surfaced as user rejected MCP tool call. Runs driven by this client are headless, so nobody can accept interactively and every MCP tool call fails.

The user-visible symptom is misleading: the agent concludes its MCP servers are unreachable and works without them. In my case that was a memory server the agent is instructed to consult before non-trivial work — it silently proceeded without project context and reported the memory as unavailable, which sent me looking for a networking problem that did not exist.

Change

Answer mcpServer/elicitation/request with action: "accept", per McpServerElicitationRequestResponse in codex-rs/app-server-protocol. Everything else still gets -32601.

The response logic moves into an exported pure function buildServerRequestResponse() so it can be tested directly — AppServerClientBase is not exported, so there was no way to reach the old method from a test. handleServerRequest is now one line.

Verification

Unit — new tests/app-server.test.mjs, 3 cases, all passing: elicitation is accepted, unimplemented server requests still get -32601, request id type is preserved.

End to end — same plugin task calling an MCP memory server, before and after the change:

before after
Task result FAIL user rejected MCP tool call OK 1
user rejected MCP tool call in job log 3 0

Note: tests/state.test.mjs has one failing case (resolveStateDir uses a temp-backed per-workspace directory) that reproduces on pristine main and is unrelated to this change.

Note for maintainers

Independently of this fix, propagating the real error text into the job log and /codex:status would help a lot. Tool <server>/<tool> failed. gave no hint that approval was involved — diagnosing this required reading raw rollout JSONL.

Codex gates MCP tool calls behind an MCP elicitation
(`mcpServer/elicitation/request`) rather than the exec/patch approval
channel, so the `approvalPolicy: "never"` that every thread started by
this client already declares does not cover them.

`handleServerRequest` answered every server-initiated request with
JSON-RPC -32601, which left the elicitation unresolved. Core maps a
missing response to `ReviewDecision::Abort`, surfaced to the model as
"user rejected MCP tool call". Because runs driven by this client are
headless, nobody can accept interactively, so every MCP tool call in a
`task` or `review` run failed. The job log only showed
"Tool <server>/<tool> failed.", which points the user at a networking or
MCP-config problem that does not exist.

Answer the elicitation with `action: "accept"` instead. The response
logic moves into an exported `buildServerRequestResponse()` so it can be
tested directly; `AppServerClientBase` is not exported.

Fixes openai#640

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@principalwater
principalwater requested a review from a team August 13, 2026 11:21

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 36abd9cc08

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread plugins/codex/scripts/lib/app-server.mjs Outdated
`mcpServer/elicitation/request` also carries ordinary form and URL
elicitations from configured MCP servers, not just Codex tool-approval
prompts. Accepting those with empty content would hand the server bogus
consent or invalid input.

Accept only when `params._meta.codex_approval_kind` is `mcp_tool_call`
(`APPROVAL_KIND_KEY` / `APPROVAL_KIND_MCP_TOOL_CALL` in
codex-rs/protocol/src/mcp_approval_meta.rs) and decline everything else,
which a headless client can neither render nor validate.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@principalwater
principalwater force-pushed the fix/accept-mcp-elicitation branch from 3f39556 to 2fb936e Compare August 13, 2026 13:46
@principalwater

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🎉

Reviewed commit: 2fb936efb9

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@principalwater

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Swish!

Reviewed commit: 2fb936efb9

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Plugin never answers MCP tool-call approval requests, so every MCP call in a task run is denied

1 participant