MCP 2026-07-28: conforming `input_required` result on tools/call fails with "Unexpected response type", although the client declared `elicitation.url`
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 125k
- Forks
- 19.4k
- PR merge metrics
- PR metrics pending
Description
Summary
Codex declares elicitation: { url: {}, form: {} } in the per-request _meta.io.modelcontextprotocol/clientCapabilities envelope on the 2026-07-28 stateless lane — but when a server takes it at its word and answers a tools/call with a spec-conforming InputRequiredResult (MRTR, SEP-2322) carrying a url-mode elicitation/create, the tool call fails client-side with:
tool call error: tool call failed for `acme/send_message`
Caused by:
Unexpected response type
The elicitation is never surfaced to the user. In my case the input_required was a human-in-the-loop approval gate (a server-side policy requiring confirmation before a send-type action), so the practical effect was: the user never saw the approval prompt, and the agent treated the governed tool as broken and routed around it.
Environment
codex-mcp-client0.149.0-alpha.4.3 (0.147.0 behaves the same way)- Streamable HTTP, protocol
2026-07-28(stateless_metaenvelope), against a 2026-07-28-conforming MCP server - The client's envelope declared
elicitation: { url: {}, form: {} }— which is exactly what invites the server to send the url-mode ask (per MRTR server requirement #7, servers MUST NOT embed input requests the client didn't declare — so a client that did NOT declare it would have received the server's fallback carrier instead).
Wire flow
tools/call→ server-side policy requires human confirmation.- Server responds
200with (shape abbreviated):
{
"jsonrpc": "2.0",
"id": 10,
"result": {
"resultType": "input_required",
"inputRequests": {
"approval": {
"method": "elicitation/create",
"params": {
"mode": "url",
"url": "https://mcp.example.com/approve?token=…",
"message": "This action needs your approval. Review and approve it here, then it will continue."
}
}
}
}
}
- Codex errors with
Unexpected response typeinstead of presenting the URL consent flow and retrying the call.
Notably, this payload shape is essentially identical to the one your own MRTR test server emits (codex-rs/rmcp-client/src/bin/test_mcp_2026_stdio_server.rs — resultType: "input_required", inputRequests.approval.method = "elicitation/create"), and codex-rs/rmcp-client/tests/mcp_2026_mrtr.rs asserts it is handled. So the server response appears conformant by codex's own fixtures.
Where it breaks (as far as I can trace from source)
- The outer error string comes from
codex-rs/codex-mcp/src/connection_manager.rs("tool call failed for{server}/{tool}"), which calls the typedclient.call_tool(...)and converts viacall_tool_result_from_rmcp(result). - The inner
Unexpected response typeis rmcp'sServiceError::UnexpectedResponse(crates/rmcp/src/service.rs), raised by the strict typed-response match:ServerResult::CallToolResult(r) => Ok(r), _ => Err(ServiceError::UnexpectedResponse). Aninput_requiredresult is (correctly) not aCallToolResult, so the typed helper rejects it before any MRTR handling can run. - i.e. the MRTR-aware path in
codex-rs/rmcp-clientexists and is tested, but thecodex-mcpconnection-manager path used for these tool calls doesn't route through it — capability declaration and result handling are out of sync.
Why this matters more than the sibling decode issues
Related open issues hit the same UnexpectedResponse arm via decode strictness (#29002 — valid result decodes as CustomResult; #38979 — non-integer priority annotation). This one is different in kind: the client advertises elicitation.url per-request, which per spec invites servers to send url-mode input requests — and then hard-fails on the conforming response. Until the handling path catches up, declaring the capability makes behavior strictly worse than not declaring it.
A second-order safety effect worth flagging: when the human-approval elicitation errors out, the agent's natural recovery is to look for an equivalent tool that isn't behind the gate and try again — i.e. the failure mode actively steers agents around human-in-the-loop approvals.
Suggested fix directions
- Route
tools/callresults on thecodex-mcppath through the sameinput_required-aware handlingrmcp-clientalready has (or extendcall_tool_result_from_rmcpto accept the MRTR variant), or - until then, stop declaring
elicitation.urlin the_metacapabilities on paths that can't fulfill it, so conforming servers use their fallback carriers.
Happy to provide full wire captures or test against a fix.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in codex-rs/codex-mcp/src/connection_manager.rs at the typed client.call_tool path and call_tool_result_from_rmcp conversion. Compare it with the MRTR-aware handling in codex-rs/rmcp-client and codex-rs/rmcp-client/tests/mcp_2026_mrtr.rs. Done means a conforming input_required URL elicitation is surfaced and the tool call can continue instead of producing Unexpected response type.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- api, backend-api-design
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100