Flatten MCP namespace tools for non-OpenAI Responses API providers (Ollama, LM Studio, OpenRouter)

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

When Codex runs against a non-OpenAI Responses API endpoint such as a local server (Ollama, LM Studio), a gateway (OpenRouter), or AWS Bedrock Mantle, tools provided by MCP servers are never callable by the model. Codex serializes each MCP server's tools inside a proprietary {"type": "namespace", "name": "mcp__<server>", "tools": [...]} wrapper, which is not part of the standard OpenAI Responses API. OpenAI and Azure expand the wrapper and reach the nested tools, but other Responses API backends pass it through unchanged or reject any tool whose type is not function, so the model only ever sees a single non-callable mcp__<server> tool and the MCP tools are unusable.

I have a fix implemented and tested on this branch: https://github.com/LucaCappelletti94/codex/tree/flatten-mcp-tools-for-non-namespace-providers

The fix gives providers a namespace_tools capability. An explicit namespace_tools in [model_providers.<id>] config wins, otherwise it defaults to requires_openai_auth, so OpenAI and Azure keep namespaces while other Responses API providers get flattened tools. When the capability is off, each namespace is flattened into plain function tools named mcp__<server>__<tool> instead of being dropped, and the tool registry resolves a flat call name back to its namespaced runtime so the call dispatches correctly. The resolution side also covers tool names that a proxy flattens on its own. Bedrock keeps namespaces on by default but can opt out for Mantle with namespace_tools = false.

Unit tests cover the capability resolution (auto and explicit override), namespace flattening into canonical function specs rather than dropping them, and flat-name resolution to the namespaced runtime. I also verified the change end to end against Ollama with both gpt-oss:20b and gpt-oss:120b plus a real MCP server: the request now carries the MCP tool as a flat function named mcp__<server>__<tool> with no namespace wrapper, the model calls it, and the tool executes.

Related to #23186, #19871, #20652, and #25034 (Mantle can opt out with namespace_tools = false).

View original on GitHub ↗

34 Comments

justaddcoffee · 2 months ago

+1 for this PR!

github-actions[bot] contributor · 2 months ago

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

  • #25034

Powered by Codex Action

LucaCappelletti94 · 2 months ago
Potential duplicates detected. Please review them and close your issue if it is a duplicate. * amazon-bedrock provider: namespace_tools capability breaks Bedrock Mantle (validation_error) #25034 _Powered by Codex Action_

No, that is not a related solution (and it does not work as commented by some other person). Also, this is primarily related to open models. My solution works with any open model with tooling supporting the Responses API.

MathieuBo · 2 months ago

+1 for this PR

AO33 · 2 months ago

+1 for this PR

GGBondBlueWhale · 2 months ago

+1 for this PR

SylvainWinning · 2 months ago

This seems worth framing as more than a Bedrock-specific fix. The pattern I would want maintainers to preserve is: provider capability should decide the wire shape, while Codex's internal registry should keep a stable canonical tool identity.

A few acceptance checks that would make this safer:

  • OpenAI/Azure providers that support namespace tools continue to send grouped namespace tools.
  • Custom Responses-compatible providers default to plain function tools unless they explicitly opt into namespace support.
  • Flattened MCP tools use deterministic names such as mcp__<server>__<tool> and still dispatch back to the original server/tool pair.
  • Collision handling is explicit if a real tool name already matches a flattened MCP name.
  • The model-provider capability is visible through app-server capability reads, so Desktop/other surfaces can reason about the same behavior.

That last point matters because #25034 shows one provider-specific failure mode, while this issue covers the broader compatibility problem for OpenRouter/Ollama/LM Studio-style Responses API backends. A provider-level namespace_tools capability plus registry-level flat-name resolution seems like the right boundary if the team wants to support those without making the OpenAI path regress.

blakelai · 2 months ago

+1

madarkadonk · 2 months ago

+1 - this is happening with my vLLM-hosted Qwen 3.6, spent yesterday trying to diagnose what was happening trying to use an MCP tool and this matches it exactly.

LucaCappelletti94 · 2 months ago

@madarkadonk feel free to use my fork in the meantime and do let me know whether any issue come out of it. So far it seems to work on my end.

justaddcoffee · 2 months ago

@madarkadonk also please promote this issue / PR! We feel like this really would improve codex

kaleighfilisa · 2 months ago

+1

jam8924 · 2 months ago

+1

madarkadonk · 2 months ago
@madarkadonk feel free to use my fork in the meantime and do let me know whether any issue come out of it. So far it seems to work on my end.

Thanks Luca, yes I've been using your branch for a couple days now and it definitely solves the direct problem. It seems like there are more secondary features that break. Example being, when codex prompts to allow something, if you select 'always allow', it'll add that to my config file - but then next time I launch codex it'll be unable to parse that entry. I didn't dig very deep into why, but probably related to the name rewriting. It could definitely be unrelated though, since this is my first attempt to use this specific MCP server.

sfragrance · 2 months ago

+1 for this PR

LucaCappelletti94 · 2 months ago
> @madarkadonk feel free to use my fork in the meantime and do let me know whether any issue come out of it. So far it seems to work on my end. Thanks Luca, yes I've been using your branch for a couple days now and it definitely solves the direct problem. It seems like there are more secondary features that break. Example being, when codex prompts to allow something, if you select 'always allow', it'll add that to my config file - but then next time I launch codex it'll be unable to parse that entry. I didn't dig very deep into why, but probably related to the name rewriting. It could definitely be unrelated though, since this is my first attempt to use this specific MCP server.

Yes there are many more issues on using open models with codex. In my fork I have a branch called "open codex" where I am gradually merging my fixes, which I am keeping separated in different branches in the hope that the openAI people decide that they actually want to support open models. I think that it is a very big stretch for them to currently claim they support open models.

kotakem-openai contributor · 2 months ago

Hi Luca,

Thanks for reporting this and for sharing a proposed fix.
I’m working on a fix for this issue and have attached a small manual repro script for reference.

repro_codex_issue_26234.py

drakonkat · 2 months ago

I had the same issue +1 for this PR

flakz · 2 months ago

+1

fuzziebrain · 2 months ago

+1 Do we have an ETA on when this fix might be available?

LucaCappelletti94 · 2 months ago

I just switch to using https://github.com/can1357/oh-my-pi for my open model needs and specifically I am very happy with https://unsloth.ai/docs/models/qwen3.6 for the time being.

SZCjoker · 2 months ago

+1

xyun1996 · 1 month ago

Also experiencing this with the Xunfei (讯飞) custom provider via --profile xunfei.
Setup:

  • codex-cli 0.142.5 on Windows
  • model_provider = "xunfei" with wire_api = "responses" (OpenAI-compatible endpoint)
  • Figma MCP configured as HTTP with OAuth (works perfectly with default OpenAI model)
  • Tavily MCP same issue

When using --profile xunfei:

  • All MCP tools return unsupported call
  • codex mcp list shows servers as enabled with correct OAuth status
  • list_mcp_resources and read_mcp_resource still work (resources are accessible)
  • Only tool invocation is broken

Workaround attempted: using mcp-remote as a stdio proxy — this fails for Figma because Figma's MCP server rejects non-whitelisted
OAuth clients (403 Forbidden). It works for Tavily since Tavily accepts API keys in the URL.
Current workaround: switch back to default OpenAI model when Figma access is needed, then back to xunfei for regular coding. Not
ideal.
This is the same root cause as #19871 and #19363. Has been open since April — any updates on a fix?

philippgille · 1 month ago

I messaged OpenRouter and asked them if they could create a plugin to fix these request issues. They already have a "JSON Response Healer" plugin, and it sounds like it should be possible to have a "Codex Request Healer" plugin that rewrites the Codex request JSON to match the Responses API spec.

madarkadonk · 1 month ago

openai preferred PR 28271, then closed that one in favor of 29602, then closed 29602 with no explanation. Seems like supporting third party models isn't their priority, which I guess isn't too surprising, though disappointing.

oddm643 · 1 month ago

@madarkadonk yes, exactly... this is what I've just seen right now. A bit disappointed honestly...

ajg360 · 28 days ago

+1

I am also trying to use Codex (0.146.0) with a local model, and I cannot make MCP tool calls because of this issue either.

It seems like one of the related PRs fixes this, but it was closed before it was merged in? Is there any explicit reason for this?

https://github.com/openai/codex/pull/29602

oddm643 · 28 days ago

Still waiting for a response to this

metrofun · 25 days ago

I’m the author of Swobu, a local compatibility gateway.

I reproduced this namespace failure and shipped an intermediary workaround in Swobu v1.0.0-rc.4. Swobu projects namespaced MCP tools into backend-compatible function names, keeps an attempt-scoped reverse mapping, and restores the original {namespace, name} identity before returning the tool call to Codex.

I verified the complete path on August 2, 2026 using:

  • Codex CLI 0.132.0
  • Swobu v1.0.0-rc.4
  • OpenRouter with openai/gpt-4.1-mini
  • the public Microsoft Learn MCP server

Codex successfully executed microsoft_docs/microsoft_docs_search and returned a grounded Microsoft Learn URL.

Install Swobu:

curl -fsSL https://swobu.com/install.sh | sh

Then point a Codex profile at the configured Swobu workspace:

[model_providers.swobu]
name = "Swobu"
base_url = "http://127.0.0.1:7926/c/<workspace>/v1"
env_key = "SWOBU_CLIENT_API_KEY"
wire_api = "responses"
supports_websockets = false

[profiles.swobu]
model = "<route-or-model>"
model_provider = "swobu"

The Codex-facing client key can be a placeholder; backend credentials remain configured in Swobu.

jpvelasco · 24 days ago

Additional sanitized reproduction data:

  • Environment: Codex CLI 0.146.0 on Windows, a custom OpenAI-compatible Responses endpoint, and tool-capable Qwen-family models.
  • The endpoint produces genuine function-call output when the request contains ordinary function tools.
  • With the stock Codex request containing namespace, custom, or hosted tool definitions, the same models instead emit textual tool-like markup and Codex records no command_execution event.
  • A custom provider configuration has no apparent capability setting to advertise or filter unsupported tool types.
  • Workaround: setting web_search = "disabled" and disabling the apps, plugins, multi_agent, image_generation, and tool_suggest feature groups restores genuine shell command_execution events. This was verified from fresh ephemeral processes across six served models; the verifier explicitly rejects textual imitations of tool calls.

Expected behavior: third-party Responses providers should be able to declare supported tool kinds, or Codex should filter/flatten unsupported tool definitions before sending the request.

lzp401 · 23 days ago

I reproduced this on the current stable CLI with a GLM custom Responses provider. The failure is not specific to Streamable HTTP or to a private MCP server.

Environment

  • Codex CLI: 0.146.0
  • Platform: macOS / Darwin arm64
  • Custom provider: Volcengine Ark, GLM-5.2, wire_api = "responses"
  • MCP control: codegraph, configured as an enabled STDIO server

Controlled reproduction

To avoid sending private repository data to the provider, I created a temporary synthetic Git repository containing only a marker string, CODEGRAPH_SYNTHETIC_OK.

I then ran codex --profile <glm-profile> exec with:

  • codegraph enabled and approved for read-only tool use
  • other ordinary MCP servers disabled
  • a prompt that required a real codegraph MCP call to find the marker
  • shell/file reads and generic MCP resource helpers explicitly disallowed as fallbacks

Before the model run, codex --profile <glm-profile> mcp get codegraph reported the server as enabled with transport: stdio and the expected command/arguments.

Observed model-facing state:

  • no mcp__codegraph__* tools
  • no tool_search
  • only core tools plus generic list_mcp_resources / read_mcp_resource helpers
  • no mcp_tool_call event was emitted
  • the model reported codegraph as unavailable

The relevant feature state in 0.146.0 is:

tool_search                         removed            false
tool_search_always_defer_mcp_tools   removed            true

This makes the registered STDIO MCP tools unreachable to this custom provider: they are not exposed directly, and the session has no discovery tool with which to load them.

Transport comparison and control

I observed the same missing-tool behavior with a healthy Streamable HTTP MCP server whose initialize and tools/list calls succeed, so the failure is not specific to STDIO versus Streamable HTTP.

As a compatibility control, I ran Codex 0.136.0 with the same GLM provider through a localhost adapter that only:

  1. flattens Responses namespace tools into ordinary functions named mcp__<server>__<tool>, and
  2. restores the namespace/name on returned function calls before Codex dispatch.

That control produced a real MCP tool call and a successful tool result. This is consistent with the namespace_tools = false / flattened-dispatch direction proposed in this issue.

Expected behavior

For a custom Responses provider, Codex should either:

  • provide a functional tool_search path for deferred MCP tools, or
  • fall back to directly exposed, flattened function tools when namespace/deferred discovery is unsupported.

The synthetic repository was deleted after the test. No private repository content, internal endpoint, or credential is included in this report.

mdunphy · 20 days ago

A workaround for this issue is to use a proxy to flatten the request and unflatten the response: https://gist.github.com/mdunphy/6c2cf14aefddeb0d627d79c8e5d366cd

(The rewrite_roles() part is not needed for fixing MCP, that was to fix something else)

thesobercoder · 19 days ago

Additional Codex Desktop reproduction through CLIProxyAPI:

  • With the same Desktop installation and gateway, GPT/Codex routes receive and successfully call app tools such as list_threads, read_thread, browser tools, and workspace tools.
  • DeepSeek, Claude, Gemini, and other non-OpenAI models behind the same OpenAI-compatible Responses endpoint do not receive those deferred app tools or a functional client-side tool_search path.
  • The MCP servers are registered correctly. The failure is in the model-visible namespace/deferred-tool representation, not MCP registration.
  • Static model catalogs, MCP imitations, and proxy-side discovery translation are not robust substitutes because Codex owns local discovery execution, namespace dispatch, schema handling, attachments, and task state.

This appears to be the same compatibility boundary addressed by closed PR #29602, whose scope explicitly included flattened namespace tools, deferred tool_search results, standalone extension tools, collision handling, and reverse dispatch. It also manifests in Codex Desktop as described in #30523.

Is there a replacement for #29602, or can its provider-capability approach be revived? Custom Responses providers need either:

  1. a supported namespace_tools / client-tool-search capability, or
  2. a Codex-side fallback that exposes deferred tools as ordinary flattened functions and restores their logical namespace during dispatch.

Without this, custom providers are nominally supported but cannot use the complete Codex Desktop tool surface.

dhar174 · 16 days ago

I'd like to note you can branch the Codex CLI and fix the problem. It
didn't play well with the Windows GUI frontend, especially while keeping my
legit OpenAI Codex stuff intact and up to date, so I also built my own GUI,
only about halfway done but functioning for basic tasks, memory, etc.
including MCP servers. With external models of the users choice - confirmed
to work with Gemma 4 e2b and e4b.

On Sun, Aug 9, 2026 at 12:12 AM Soham Dasgupta @.***>
wrote:

thesobercoder left a comment (openai/codex#26234) <https://github.com/openai/codex/issues/26234#issuecomment-5229709402> Additional Codex Desktop reproduction through CLIProxyAPI: - With the same Desktop installation and gateway, GPT/Codex routes receive and successfully call app tools such as list_threads, read_thread, browser tools, and workspace tools. - DeepSeek, Claude, Gemini, and other non-OpenAI models behind the same OpenAI-compatible Responses endpoint do not receive those deferred app tools or a functional client-side tool_search path. - The MCP servers are registered correctly. The failure is in the model-visible namespace/deferred-tool representation, not MCP registration. - Static model catalogs, MCP imitations, and proxy-side discovery translation are not robust substitutes because Codex owns local discovery execution, namespace dispatch, schema handling, attachments, and task state. This appears to be the same compatibility boundary addressed by closed PR #29602 <https://github.com/openai/codex/pull/29602>, whose scope explicitly included flattened namespace tools, deferred tool_search results, standalone extension tools, collision handling, and reverse dispatch. It also manifests in Codex Desktop as described in #30523 <https://github.com/openai/codex/issues/30523>. Is there a replacement for #29602 <https://github.com/openai/codex/pull/29602>, or can its provider-capability approach be revived? Custom Responses providers need either: 1. a supported namespace_tools / client-tool-search capability, or 2. a Codex-side fallback that exposes deferred tools as ordinary flattened functions and restores their logical namespace during dispatch. Without this, custom providers are nominally supported but cannot use the complete Codex Desktop tool surface. — Reply to this email directly, view it on GitHub <https://github.com/openai/codex/issues/26234?email_source=notifications&email_token=ABH7VG3EJ32QEZ6U22IXSTD5I722ZA5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTKMRSHE3TAOJUGAZKM4TFMFZW63VGNVQW45LBNSSWK5TFNZ2KYZTPN52GK4S7MNWGSY3L#issuecomment-5229709402>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/ABH7VG2QTXE7IP25YPIC3SL5I722ZAVCNFSNUABFKJSXA33TNF2G64TZHM4TMNJUGE2TMNBZHNEXG43VMU5TINJYGMYTOMJVGI3KC5QC> . You are receiving this because you are subscribed to this thread.Message ID: @.***>

--

---------------------------------------------

Charles Niswander II
Allegan, MI
@. @.>*

*https://charlesniswanderinnovations.com/
<https://charlesniswanderinnovations.com/>*