`unsupported call: mcp__<server>__<tool>` for MCP tools when used with custom Responses API provider (Apps SDK + custom model)

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

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 CLI 0.142.5)
  • OS: macOS 26.5.1
  • Model provider (custom):

```toml
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

  1. Install and enable the Cowart plugin in ~/.codex/config.toml:

``toml
[plugins."cowart@personal"]
enabled = true
``

  1. 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.
``

  1. Start a Codex thread on MiniMax-M3. Send: "Open the Cowart canvas for this project."
  2. Model emits function_call for mcp__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
``

  1. The same error is produced for non-widget Cowart tools too (get_cowart_canvas_state, save_cowart_canvas_state, etc.). Every call to any mcp__cowart_mcp__* tool fails identically.

Expected

  • The widget tool should render the native Cowart canvas UI (openai/outputTemplate resolution), 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 with unsupported call: <tool>, regardless of whether the tool is an Apps SDK widget tool or a regular MCP tool.
  • Searching ~/.codex/logs_2.sqlite shows all 7 hits for this error string come from the MiniMax-M3 provider; no occurrences under gpt-* 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)

  1. 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/outputTemplate on any of its tools) instead of returning unsupported call.
  2. When a custom provider returns a function_call for a server whose tools are Apps SDK widget tools, wrap the call into the McpToolCallAppContext / mcpAppResourceUri shape so the existing widget rendering pipeline can run.
  3. 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_widget via mcpServer.registerTool (without _meta.ui.*) instead of registerAppTool. This loses the native widget UI but restores function-call dispatch.

Related

  • openai/codex#30902 — same provider (MinimaxM3), three different MCP servers all returning unsupported call. The reproduction in this issue is the same class of failure.
  • openai/codex#26977 — same error, llama.cpp provider, detailed RCA already in the report.
  • openai/codex#22970 — same error class on Windows.
  • openai/codex#21019 — Codex Desktop does not render MCP Apps inline UI resources; related but on the rendering side rather than dispatch.
  • zhongerxin/Cowart#37 — Cowart UI does not render. Different failure mode (the tool returns successfully there, Codex just doesn't render the widget).

View original on GitHub ↗

4 Comments

github-actions[bot] contributor · 1 month ago

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

  • #30902

Powered by Codex Action

fcoalcantarajr · 16 days ago

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

  • Codex CLI: 0.147.0
  • macOS on Apple Silicon
  • Custom provider: local 9Router OpenAI-compatible gateway
  • Model exposed by the gateway: github-copilot

Sanitized profile:

model = "github-copilot"
model_provider = "9router"
model_reasoning_effort = "high"
approval_policy = "on-request"
approvals_reviewer = "user"

[model_providers.9router]
name = "9Router"
base_url = "http://127.0.0.1:20128/v1"
env_key = "NINEROUTER_API_KEY_CODEX"
wire_api = "responses"

What is interesting in this repro

The MCP servers are not merely configured — Codex itself enumerates their tools successfully via /mcp.

For example, /mcp shows:

computer-use
  Tools: click, drag, get_app_state, list_apps,
         perform_secondary_action, press_key, scroll,
         select_text, set_value, type_text

node_repl
  Tools: js, js_add_node_module_dir, js_reset

playwright
  Tools: browser_click, browser_navigate, browser_snapshot,
         browser_take_screenshot, browser_type, ...

It also lists toolsets from codex_apps, notion, and openaiDeveloperDocs.

I additionally probed the Computer Use MCP binary directly over stdio JSON-RPC. initialize succeeds and tools/list returns the expected tool schemas:

serverInfo.name = "Computer Use"
capabilities.tools.listChanged = false

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 the mcp__... tools, but Codex rejects them as unsupported call before 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 of unsupported call behavior for dynamic MCP tools.

This is especially notable because /mcp in the same running thread lists those servers and their tools correctly. In other words:

MCP startup / tool enumeration          ✅
/mcp shows concrete tool schemas        ✅
direct MCP initialize + tools/list      ✅
built-in shell/tooling                   ✅
model attempts dynamic MCP invocation   ✅
Codex dispatch of mcp__... call          ❌ unsupported call

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 responses provider, 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 SkyComputerUseClient path, after which its startup error disappeared and /mcp began 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 · 9 days ago

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 the unsupported call routing 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 · 5 days ago

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!