Repository navigation
Description
Summary
When Codex is configured with a custom model provider that uses wire_api = "responses" (for example, MiniMax-M3 against api.minimaxi.com/v1, or llama.cpp with the Responses adapter), calls to MCP tools — including Apps SDK / UI widget MCP servers like Cowart — are rejected by Codex's tool dispatcher with the literal error:
error=unsupported call: mcp__<server>__<tool>
The MCP servers themselves are healthy and respond normally when invoked directly outside Codex. The failure happens before the MCP child process is reached. This blocks every MCP-driven plugin for non-OpenAI providers.
Environment
-
Codex Desktop:
26.623.141536(Codex CLI0.142.5) -
OS: macOS 26.5.1
-
Model provider (custom):
model_provider = "custom" model = "MiniMax-M3" [model_providers.custom] name = "minimax" base_url = "https://api.minimaxi.com/v1" wire_api = "responses" requires_openai_auth = true experimental_bearer_token = "<token>"
-
MCP server used in the reproduction: Cowart
v0.1.11(Apps SDK / UI widget MCP,registerAppTool+_meta.ui.resourceUri+openai/outputTemplate = ui://widget/cowart/canvas.html).
Reproduction
- Install and enable the Cowart plugin in
~/.codex/config.toml:[plugins."cowart@personal"] enabled = true
- Run the Cowart MCP probe outside Codex to confirm the server is healthy:
$ cd ~/.codex/plugins/cache/personal/cowart/0.1.11 $ node ./scripts/probe-mcp.mjs OK: Cowart MCP tools and native widget resource are available. - Start a Codex thread on
MiniMax-M3. Send: "Open the Cowart canvas for this project." - Model emits
function_callformcp__cowart_mcp__render_cowart_canvas_widget. Codex logs show:dispatch_tool_call_with_code_mode_result{ otel.name = mcp__cowart_mcp__render_cowart_canvas_widget tool_name = mcp__cowart_mcp__render_cowart_canvas_widget call_id = "call_019f3a99811d726095284eed" aborted = false }:dispatch_tool_call_with_terminal_outcome: error = unsupported call: mcp__cowart_mcp__render_cowart_canvas_widget - The same error is produced for non-widget Cowart tools too (
get_cowart_canvas_state,save_cowart_canvas_state, etc.). Every call to anymcp__cowart_mcp__*tool fails identically.
Expected
- The widget tool should render the native Cowart canvas UI (
openai/outputTemplateresolution), and - Non-widget Cowart tools should execute against the MCP child process and return their
structuredContent.
Actual
- Every
mcp__cowart_mcp__*call is rejected at the Codex dispatcher withunsupported call: <tool>, regardless of whether the tool is an Apps SDK widget tool or a regular MCP tool. - Searching
~/.codex/logs_2.sqliteshows all 7 hits for this error string come from theMiniMax-M3provider; no occurrences undergpt-*models in the same time window.
Root cause (best guess, from Codex CLI binary strings)
The error is emitted by the dispatcher at core/src/tools/router.rs:185 (dispatch_tool_call_with_terminal_outcome). The function only knows how to route tool calls that match a known tool-kind arm; for everything else it falls through to unsupported call: <name>.
For Apps SDK widget MCP servers, Codex has a separate context type McpToolCallAppContext (with mcpAppResourceUri) and a corresponding dispatch path. When the model provider is OpenAI-native, the framework rewrites / re-emits Apps SDK tool calls into that path. With custom wire_api = "responses" providers, that rewrite is skipped — the model returns a plain function_call payload (e.g. call_id = "call_019f3a99..."), which the dispatcher does not recognize and rejects with unsupported call.
This explains why:
- Widget MCP tools (Cowart, Canva, Computer Use, …) all fail.
- Non-widget MCP tools on the same server also fail when registered by an Apps MCP server, because the whole server is treated as an Apps namespace.
- The probe script (
node scripts/probe-mcp.mjs) succeeds — the failure is purely on the Codex dispatch side, not on the MCP child process. - The error is provider-specific: switching back to the default OpenAI model in the same Codex build makes identical MCP calls succeed.
Related symptoms observed in ~/.codex/logs_2.sqlite under the same provider:
| tool_name | provider |
|---|---|
mcp__cowart_mcp__render_cowart_canvas_widget |
MiniMax-M3 |
mcp__cowart_mcp__get_cowart_canvas_state |
MiniMax-M3 |
mcp__node_repl__js |
MiniMax-M3 |
mcp__codex_apps__github___search |
MiniMax-M3 |
multi_agent_v1__close_agent |
MiniMax-M3 |
Suggested fix (in order of preference)
- In
core/src/tools/router.rs:185, fall through to the Apps SDK dispatch path whenever the MCP server exposes an Apps SDK resource (openai/outputTemplateon any of its tools) instead of returningunsupported call. - When a custom provider returns a
function_callfor a server whose tools are Apps SDK widget tools, wrap the call into theMcpToolCallAppContext/mcpAppResourceUrishape so the existing widget rendering pipeline can run. - As a longer-term fix, distinguish "Apps SDK MCP server" from "regular MCP server" at server-spawn time (not per-tool), so the dispatcher picks the right arm up front.
Workarounds
- Switch the thread model back to a default OpenAI model: Cowart renders correctly.
- Patch Cowart locally to register
render_cowart_canvas_widgetviamcpServer.registerTool(without_meta.ui.*) instead ofregisterAppTool. This loses the native widget UI but restores function-call dispatch.
Related
- MCP unsupported call #30902 — same provider (
MinimaxM3), three different MCP servers all returningunsupported call. The reproduction in this issue is the same class of failure. - MCP tools return 'unsupported call' with custom Responses API provider (llama.cpp) #26977 — same error, llama.cpp provider, detailed RCA already in the report.
- [Bug] MCP dynamic tool proxy returns unsupported call for all MCP tools #22970 — same error class on Windows.
- Codex Desktop does not render MCP Apps inline UI resources even when tool result includes mcp_app_resource_uri #21019 — Codex Desktop does not render MCP Apps inline UI resources; related but on the rendering side rather than dispatch.
- does not render the Cowart/tldraw UI. zhongerxin/Cowart#37 — Cowart UI does not render. Different failure mode (the tool returns successfully there, Codex just doesn't render the widget).
Activity
github-actions commentedon Jul 7, 2026
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
docs(codex): document MCP tool 'unsupported call' bug with custom pro…
fcoalcantarajr commentedon Aug 11, 2026
I can reproduce this on a newer Codex CLI with a different custom Responses provider path, and the evidence points to the same dispatcher-side failure.
Environment
0.147.0github-copilotSanitized profile:
What is interesting in this repro
The MCP servers are not merely configured — Codex itself enumerates their tools successfully via
/mcp.For example,
/mcpshows:It also lists toolsets from
codex_apps,notion, andopenaiDeveloperDocs.I additionally probed the Computer Use MCP binary directly over stdio JSON-RPC.
initializesucceeds andtools/listreturns the expected tool schemas:So the MCP server binary is healthy and tool discovery works outside the model-dispatch path.
Failure
When the custom-provider thread is asked to use Computer Use (for example, open Calculator and type
123 + 456), the model attempts MCP calls such as themcp__...tools, but Codex rejects them asunsupported callbefore the requested UI action reaches the MCP server.The same session also encountered this with
mcp__node_repl__js; earlier attempts involving Browser/Playwright hit the same class ofunsupported callbehavior for dynamic MCP tools.This is especially notable because
/mcpin the same running thread lists those servers and their tools correctly. In other words:That makes this look much more like the flat/dynamic MCP call is not being resolved back to the registered MCP runtime under the custom
responsesprovider, rather than an MCP startup/configuration issue.Computer Use-specific details
I also corrected an unrelated path issue first: the Computer Use MCP command now points to the absolute
SkyComputerUseClientpath, after which its startup error disappeared and/mcpbegan exposing its tools normally. The remaining failure is the dispatcher rejecting the tool invocation.Native-provider comparison limitation
I have not been able to run the final A/B comparison against the native OpenAI provider on this machine because my current Codex/OpenAI usage quota is exhausted, and I am not adding credit right now. So I am not claiming a fresh native-vs-custom comparison from this environment; the useful signal here is that the custom-provider thread has healthy MCP discovery and a healthy MCP server, but invocation still dies at dispatch.
This seems consistent with the issue's current RCA and also broadens the repro beyond MiniMax/llama.cpp to an OpenAI-compatible local gateway (9Router) on Codex CLI
0.147.0.madmax24-ubuntu commentedon Aug 18, 2026
For the llama.cpp/custom-Responses side of this class of failure, I published a compatibility bridge here: https://github.com/madmax24-ubuntu/codex-proxy-llama.cpp
The important part is that it does not only flatten
mcp__...tools on the request. It also restores the namespace/name mapping on returned function calls before Codex sees them, which avoids theunsupported callrouting failure for regular MCP tools in local-model sessions.It is currently tested with Codex + llama.cpp + Qwen and also bridges native
apply_patch, tool-history replay, SSE framing, reasoning events, and compaction. This will not fix Apps SDK widget rendering semantics by itself, but it may help people hitting the same dispatcher failure with ordinary MCP tools under a custom Responses provider.madmax24-ubuntu commentedon Aug 23, 2026
Thanks for reproducing this — that matches what I was seeing on my side.
I also have a working proxy implementation that may be useful for debugging or as a possible reference for the per-provider flattening approach:
https://github.com/madmax24-ubuntu/codex-proxy-llama.cpp
The main relevant part is flattening Codex/MCP namespace tools into regular function-style tools for llama.cpp, then mapping the tool calls back on the Responses API side.
I built this specifically to make Codex work reliably with local llama.cpp backends. It may be useful to compare the tool transformation there with what is currently happening in the Ollama/llama.cpp provider path.
Thanks again for digging into this!
harness-watch: scheduled harness-version automation + capability cove…
mikkihugo commentedon Sep 8, 2026
Additional repro (2026-09-08): codex-cli 0.154.0-alpha.3 (npm), custom provider against a self-hosted OpenAI-compatible gateway (CentralCloud llm-gateway, wire_api = "responses"), MCP server via streamable HTTP (http://mcp-gateway.svc/mcp, a Go router advertising 88 tools).
Same signature: MCP startup + tools/list succeed (the model sees the mcp____ names in its tool list), the MCP server itself is healthy (direct curl initialize + tools/list + tools/call all work, protocol 2025-11-25), but every dispatch fails with
error=unsupported call: mcp__<server>__<tool>from codex_core::tools::router — before the request reaches the MCP server. Affects all gateway tools including the routed mcp_tool_call. No chat-completions fallback available on this gateway (only /responses). Happy to provide more logs or test a patch.NghiaNguyenTT commentedon Sep 24, 2026
Fixed this end-to-end on Windows 11 with a company gateway (LiteLLM-style Responses API in front of Qwen chat-completions models). Sharing the recipe — no code changes needed, the fix is entirely in which hop you put between Codex and the gateway.
Tested: Codex CLI 0.158.0-alpha.3 · ChatGPT Desktop 26.917.62051 · CC Switch 3.20.4
Root cause (matches @ericyanpek's datapoint in #20652)
The gateway's Responses shim returns
function_callitems without thenamespacefield (or flattened intoname). Codex's router does strictToolName{namespace, name}matching →unsupported call: mcp__…. Pointingbase_urldirectly at any gateway that mutates the Responses function-call shape fails the same way, regardless of MCP server type.Fix: let a responses→chat bridge flatten AND restore the mapping
CC Switch's built-in local proxy does exactly what @madmax24-ubuntu's bridge does — flattens namespaced tools on the request and re-maps
function_callitems back on the response. The key is routing through the proxy, not the gateway, and letting it own auth:Two gotchas that cost me a day
web_search = "disabled"is not optional for gateways — the built-in hosted tool is aweb_search_20250305schema and third-party gateways reject it (tools[...].input_schema Field required), which kills the whole request before any MCP tool can land.supports_search_tooland[features] tool_search = truemust move together.truein the catalog without the feature = everymcp__*tool silently vanishes from the session (this is the "tools disappear" symptom in Codex Desktop starts configured MCP server successfully, but does not expose its tools to the model #21881 / Codex App shows MCP servers enabled, but current session only receives a subset of MCP tools #21654, so it may explain several of those reports). With both flags on, MCP tool defs are deferred behindtool_searchand discovered on demand — measured 115k → 45k tokens for a trivial Jira lookup on a Qwen-class backend.Verify
After changing anything: fully quit + relaunch the Desktop app (the embedded app-server keeps the old provider/session config alive — restarting the window is not enough).
If the fix sticks, the remaining upstream ask is what #20652 already proposes: have the router un-flatten
mcp__<server>__<tool>(and tolerate a missingnamespace) instead of requiring a middlebox to restore shape that Codex itself defined.