Custom stdio MCP server discovered by /mcp but tools not exposed to Desktop threads

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

Summary

Codex Desktop sees a custom stdio MCP server and successfully discovers its tools via tools/list, but the tools are not exposed to Desktop threads or tool_search.

This appears to be a regression or exposure-layer bug in Desktop/App Server 0.124.0-alpha.2.

Environment

  • Codex Desktop client: 26.422.21637
  • Codex/App Server: 0.124.0-alpha.2
  • Platform: macOS
  • Server type: custom stdio MCP server
  • Config location: project-scoped .codex/config.toml

MCP config

[mcp_servers.interdomestik_qa]
command = "/bin/bash"
args = ["scripts/start-repo-qa.sh"]
cwd = "."

The wrapper script resolves the repo root, changes into it, and starts a TypeScript MCP server over stdio.

Expected behavior

The following custom MCP tools should be exposed to Desktop threads and callable via names like mcp__interdomestik_qa__project_map:

  • project_map
  • read_files
  • code_search
  • check_health
  • pr_verify
  • security_guard
  • e2e_gate

Actual behavior

  • Desktop /mcp shows the server enabled.
  • codex mcp list --json shows the server enabled.
  • Repo preflight passes, including live MCP tools/list discovery.
  • Desktop logs show the server starts and returns a ListToolsResult containing the expected custom QA tools.
  • tool_search returns 0 callable interdomestik_qa tools.
  • Thread request payloads do not include any mcp__interdomestik_qa__* tools.
  • The current thread's thread_dynamic_tools only contains generic Desktop tools such as automation_update, read_thread_terminal, load_workspace_dependencies, and install_workspace_dependencies.

Evidence collected locally

Manual/repo preflight confirms live MCP discovery works:

pnpm mcp:preflight

Desktop logs show the custom server is started and queried successfully:

  • custom QA server starts on stdio
  • client initializes against the server
  • ListToolsRequest is sent
  • ListToolsResult is received with the expected custom tools

But those discovered tools are not present in the thread/deferred tool surface.

Historical comparison from local Codex state/logs:

  • An Apr 20 thread on Codex 0.91.0 successfully called tools such as:
  • mcp__interdomestik_qa__read_files
  • mcp__interdomestik_qa__code_search
  • mcp__interdomestik_qa__project_map
  • Apr 24 threads on Codex 0.124.0-alpha.2 do not expose those tools, despite successful /mcp discovery.

I also checked whether stale Desktop workspace state was the cause. The active workspace root and thread cwd both point to the correct repo, but the custom MCP tools are still not exposed.

Suspected failure point

The failure appears to be after successful MCP tools/list discovery and before Desktop registers/indexes those tools into the per-thread/deferred tool surface.

It does not appear to be caused by the MCP server implementation, stdio transport, project config, or CLI discovery, because live tools/list discovery succeeds outside the Desktop thread tool surface.

View original on GitHub ↗

35 Comments

github-actions[bot] contributor · 4 months ago

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

  • #19304
  • #17904
  • #18527
  • #19363

Powered by Codex Action

arbenl · 4 months ago

Update after full Codex Desktop restart:

Outcome is still: Discovery works, exposure still fails.

Fresh thread details:

  • cwd: /Users/arbenlila/development/interdomestik-crystal-home
  • current thread id: 019dc0ed-8043-78b1-badb-e1a5aa5e6f02
  • tool_search for expected QA tools returned 0 tools, both initially and after rechecking.
  • codex mcp list --json shows interdomestik_qa enabled.
  • pnpm mcp:preflight passed, including live tools/list discovery.
  • thread_dynamic_tools for the current thread contains only:
  • automation_update
  • read_thread_terminal
  • load_workspace_dependencies
  • install_workspace_dependencies
  • thread_dynamic_tools contains 0 interdomestik_qa, project_map, read_files, or code_search entries.
  • Recent Desktop logs show the stdio server started and initialized as interdomestik-qa version 1.0.0.
  • Recent logs show ListToolsResult for this same thread containing the expected QA tool names.
  • Only MCP warnings found were unsupported resources/resource templates methods, not tools/list failure.

Versions after restart:

  • codex --version: codex-cli 0.124.0
  • current thread cli_version: 0.125.0-alpha.3
  • Desktop client: Codex.app 26.422.30944, build 2080

Most precise failure boundary:

Desktop/RMCP can start interdomestik_qa and receive ListToolsResult, but those tools are not persisted/indexed into the current thread's callable dynamic tools, so tool_search exposes none of them.

arbenl · 4 months ago

Reviewed the potential duplicates suggested by the bot. I do not think this is an exact duplicate, though it is likely related to the same MCP exposure/indexing area.

Comparison:

  • #19304 is the closest symptom match, but it is Windows + local MCP plugin packaging. This issue is macOS + project-scoped stdio MCP config, and the important extra evidence is that Desktop logs show ListToolsResult for the same current thread containing the expected tool names, while thread_dynamic_tools still contains no custom MCP entries.
  • #17904 is about codex exec session schema. This issue is Desktop thread/tool_search exposure.
  • #18527 is remote HTTP OAuth MCP/auth handoff. This issue is local stdio MCP with successful initialization and tools/list, so OAuth is not involved.
  • #19363 is custom model provider behavior. This issue uses the normal Desktop/App path, not a custom provider.

So the narrower failure here remains: Desktop/RMCP successfully starts the stdio server and receives ListToolsResult, but the discovered tools are not persisted/indexed into the thread's callable dynamic tools.

arbenl · 4 months ago

Additional cross-client comparison from the same local repo/machine:

Gemini/Antigravity is able to mount and use MCP tools successfully in this repo context. Verified working there:

  • mcp-context-server/project_map
  • mcp-context-server/read_files
  • context7/resolve-library-id
  • playwright/browser_tabs
  • e2e-test-generator/generate_basic_test

This further suggests the MCP server/environment is not the root problem. Other MCP clients can index and call repo/context/playwright-style MCP tools on the same machine, while Codex Desktop still discovers interdomestik_qa via tools/list but does not expose the tools to the thread/tool_search surface.

One separate note: Gemini's repo-qa wrapper hit a JSON parsing/encoding issue (invalid character 'â') for some QA commands, which looks like command-output formatting inside that wrapper. That is distinct from this Codex issue, where the tools are not mounted at all despite successful ListToolsResult discovery.

arbenl · 4 months ago

Additional related issue with a useful version boundary: #19649

That report describes the same core failure class: MCP servers are registered and visible via codex mcp list / codex mcp get, but their tools are not injected into Codex threads.

Important detail from #19649:

  • known working: codex-cli 0.120.0
  • broken: codex-cli 0.122.0-alpha.13 and later
  • same config works again after downgrading to 0.120.0

That lines up with this Desktop report:

  • older Interdomestik thread on 0.91.0 had usable mcp__interdomestik_qa__... calls
  • current Desktop/App runtimes around 0.124.x / 0.125.x discover tools/list but do not expose the tools to tool_search / thread_dynamic_tools

So this issue may be the Desktop/app-server manifestation of the same regression family as #19649. This issue still adds Desktop-specific evidence: the logs show ListToolsResult for the same current thread, while thread_dynamic_tools remains missing the discovered MCP tools.

rnett · 3 months ago

This may be https://github.com/openai/codex/issues/20574, are you using a custom or older model?

arbenl · 3 months ago

Thanks. I do not think this is #20574.

In this repro I am not using a custom provider like Ollama/LiteLLM/Bifrost. The failing Desktop thread is using the normal Codex Desktop / ChatGPT path with gpt-5.5.

The failure signature is also different:

  • #20574: tool_search is present but aborts with unsupported payload when called through a non-native provider.
  • This issue: tool_search executes successfully, but returns an empty result for interdomestik_qa.
  • The same session can discover other MCP/tool sources such as Context7, Playwright, and OpenAI docs.
  • codex mcp list --json shows interdomestik_qa enabled.
  • pnpm mcp:preflight passes, including live tools/list discovery from the stdio server.
  • Desktop logs have shown ListToolsResult containing the expected interdomestik_qa tool names.
  • The missing step is still that those discovered tools are not inserted into the thread/deferred tool index, so no mcp__interdomestik_qa__... namespace becomes callable.

So this still looks like a Desktop/app-server MCP exposure/indexing issue, not the custom-provider tool_search payload bug from #20574.

arbenl · 3 months ago

Additional update: I also tested a repo-side hardening for a possible stale-workspace-root factor.

Originally the project-scoped MCP entry used a relative cwd:

[mcp_servers.interdomestik_qa]
command = "/bin/bash"
args = ["scripts/start-repo-qa.sh"]
cwd = "."

I changed it to pin the server cwd to the absolute repository root while keeping the launcher argument unchanged:

[mcp_servers.interdomestik_qa]
command = "/bin/bash"
args = ["scripts/start-repo-qa.sh"]
cwd = "/Users/arbenlila/development/interdomestik-crystal-home"

I also added a local preflight guard so pnpm mcp:preflight fails if interdomestik_qa resolves with a relative cwd or a cwd outside this repo.

Verification after that hardening:

  • codex mcp list --json resolves interdomestik_qa with the absolute repo cwd.
  • pnpm mcp:preflight passes.
  • live stdio tools/list discovery still passes and returns the expected QA tools.
  • launching the same MCP command from a different parent directory works when the child cwd is pinned to the repo.

However, this did not fix Desktop thread exposure. In the running Desktop session, tool_search still returns 0 results for interdomestik_qa / project_map / read_files / code_search.

So the absolute-cwd change is a useful repo-side mitigation that removes stale root ambiguity, but it is not a complete fix for this issue. The remaining failure is still in the Desktop/app-server exposure/indexing step after successful MCP discovery.

arbenl · 3 months ago

Additional update from the repo side: I hardened the interdomestik_qa MCP configuration to remove possible local blockers, but the Desktop exposure failure remains in the current thread.

Repo-side changes made and verified:

  • interdomestik_qa is pinned to the absolute repository cwd instead of cwd = ".".
  • The project-scoped Codex config now declares a focused enabled_tools allowlist for the core agent tools:
  • project_map
  • read_files
  • read_file_range
  • code_search
  • git_status_compact
  • git_branch_info
  • changed_files
  • scope_audit
  • check_health
  • pr_verify
  • security_guard
  • e2e_gate
  • All QA MCP tool input schemas are now strict object schemas with additionalProperties: false.
  • pnpm mcp:preflight now verifies codex mcp get interdomestik_qa --json, including the parsed enabled_tools allowlist.

Verification results:

  • codex mcp get interdomestik_qa --json shows the server enabled with the absolute cwd and the parsed enabled_tools allowlist.
  • pnpm mcp:preflight passes.
  • Live stdio tools/list discovery passes.
  • Live tools/list returns 35 tools, all with strict object schemas, and the core allowlisted tools are present.

However, this existing Codex Desktop thread still returns 0 results from tool_search for interdomestik_qa project_map read_files code_search ....

So the repo/server side is now exposure-ready: no relative cwd, no unbounded Codex tool surface, and no permissive input schemas. If a fresh Desktop thread still does not surface mcp__interdomestik_qa__..., the remaining failure is still in Desktop/app-server MCP indexing/injection after successful discovery.

arbenl · 3 months ago

Additional update from the current Desktop session after restart and after testing the local-plugin/CLI distinction.

Current state:

  • Codex Desktop now shows the Interdomestik QA plugin as available/enabled in the session metadata.
  • tool_search still returns 0 results for interdomestik_qa, project_map, read_files, and code_search.
  • There is still no callable mcp__interdomestik_qa__... namespace in the Desktop session.
  • The hyphen/underscore distinction does not appear to be the root cause: the local plugin name can be interdomestik-qa, while the MCP server id remains interdomestik_qa; Desktop can know about the plugin/server, but the tools still are not admitted into the callable tool index.

CLI / local stdio contrast from the same repo and machine:

  • The same MCP server config is startable from the CLI path.
  • The repo-local stdio server can be initialized, can return tools/list, and can execute tool calls.
  • Verified via a thin local bridge using the same launcher:
  • pnpm mcp:tool list returns the expected QA tools.
  • pnpm mcp:tool call read_file_range '{"file":"package.json","startLine":1,"endLine":8}' succeeds.
  • The app-bundled Codex CLI also sees interdomestik_qa as enabled with the expected command/cwd/env configuration.

So the current narrowed boundary is:

  1. MCP server startup works.
  2. MCP initialize works.
  3. MCP tools/list works.
  4. Direct stdio tool calls work.
  5. Desktop can have the local plugin/server present in session metadata.
  6. Desktop still does not insert those discovered tools into tool_search / the callable mcp__... namespace.

I also checked public issues/docs for evidence that Codex Desktop has started admitting local custom MCPs into tool_search; I did not find a confirmed fix or documented supported path for that yet. This still looks like a Desktop/app-server MCP admission/indexing bug, not a repo MCP implementation problem.

arbenl · 3 months ago

Hi OpenAI Codex team,

I’m asking for help with a Codex Desktop MCP exposure issue.

I have a repo-local MCP server named interdomestik_qa. The server is configured, startable, and discoverable, but Codex Desktop does not expose its tools as callable mcp__interdomestik_qa__... tools through tool_search.

What works:

  • codex mcp get interdomestik_qa --json shows the server enabled.
  • The server launches over stdio.
  • Live initialize works.
  • Live tools/list works.
  • pnpm mcp:preflight passes.
  • The server returns a reduced Codex-facing tool surface.
  • Tool schemas are strict object schemas with additionalProperties: false.
  • Gemini and VS Code can expose MCP tools on the same machine.

What fails:

  • In Codex Desktop, tool_search returns 0 tools for interdomestik_qa, project_map, read_files, read_file_range, and code_search.
  • No callable namespace like mcp__interdomestik_qa__project_map appears, even after restarting Codex Desktop from the repo root.

Current suspected boundary:

Codex Desktop can see/start/discover the MCP server, but the discovered tools are not admitted into the Desktop/app-server callable tool index.

Could you please clarify whether Codex Desktop currently supports exposing local custom stdio MCP servers into tool_search? If yes, what exact config/plugin shape is required? If not, is this a known limitation or regression?

This is blocking my preferred workflow because the repo MCP tools are much faster and deeper for codebase inspection than shell fallbacks.

Thank you.

HarryVu176 · 2 months ago

I'm running into same issue, this is a huge one, I think it should have been fixed by now...

Codex CLI recognize my MCP and model can make call, but Codex app does not. /cli on codex app shown the MCP server, but model not being able to call it.

CaliLuke · 1 month ago

it's absurd this bug is still open after all this time. MCP is such a key feature, why is the team not fixing something like this?

zvory · 1 month ago

I'm experiencing this issue as well.

yunusemregul · 1 month ago

I am seeing the same Desktop MCP discovery-to-exposure failure on a newer Codex build, with two independent custom Streamable HTTP MCP servers.

Environment:

  • macOS
  • Codex Desktop: 26.707.72221
  • Desktop-bundled Codex CLI/app-server: 0.144.2
  • Separately installed Codex CLI: 0.144.5
  • MCP configuration: global ~/.codex/config.toml
  • Transport: Streamable HTTP on localhost
  • Model/provider: normal Codex Desktop / ChatGPT path, not a custom or OSS provider

What works:

  • codex mcp list shows both custom servers enabled.
  • The Desktop-bundled CLI also sees the same configured servers.
  • Both servers complete MCP initialize successfully.
  • Both advertise the tools capability.
  • Direct tools/list returns their complete and valid tool definitions.
  • The tools can be called through a direct MCP client, confirming that the servers and transport are functional.

What fails:

  • New Codex Desktop threads receive no callable namespace for either server.
  • No mcp__<server>__... tools are present in the thread tool registry.
  • Generic MCP resource discovery does not expose either server.
  • Fully restarting and opening a new thread does not change the result.

This appears to fail after successful server initialization and tool discovery, but before the discovered tools are admitted into the Desktop thread callable-tool index. That matches the boundary described in this issue.

The servers are primarily tool-oriented and do not advertise MCP resources, so this may overlap with:

  • #14242 — tool-only MCP servers are not discovered/used correctly
  • #10499 — Desktop shows MCP servers but chat cannot use them while TUI/CLI behavior differs
  • #19649 — registered MCP tools not injected into threads; closed, but documents the same regression family

The older #3441 appears different because its example used the obsolete [mcp.servers] configuration shape. My configuration uses the current [mcp_servers.<name>] format and is parsed correctly by both CLI versions.

So this is still reproducible on Desktop/app-server 0.144.2, well beyond the 0.124.x versions originally reported here.

mplibunao · 1 month ago

Adding a stricter reproduction on a newer Desktop build. This server exposes both MCP resources and tools, so the failure is not limited to tool-only servers or an empty resources/list response.

Environment:

  • macOS 26.5.2, Apple Silicon
  • Codex Desktop 26.707.91948 (build 5440)
  • Desktop-bundled Codex CLI/app-server 0.144.5
  • Global ~/.codex/config.toml
  • Custom stdio MCP server
  • Fresh task and resumed task both tested

Verified working:

  • The MCP server is enabled in Codex configuration.
  • Its disabled-tool ACL is empty.
  • The configured stdio process starts and remains live.
  • MCP initialization succeeds.
  • Resource discovery succeeds; the task can read the server resource.
  • Codex telemetry for the exact fresh task records:

listed MCP server tools while building tool list server_name=RepoPromptCE tool_count=20

Observed failure:

  • The task receives no callable mcp__RepoPromptCE__* tools.
  • The task also receives no tool_search or equivalent deferred-tool retrieval bridge.
  • Desktop logs show ToolSearchAlwaysDeferMcpTools enabled.
  • Therefore the 20 successfully discovered tools are deferred/withheld, but there is no mechanism available to retrieve them.
  • A full machine reboot, restarting both applications, and creating a genuinely new task do not change the result.

Expected behavior:

When Codex defers discovered MCP tools, the task must receive tool_search; otherwise it should inject the direct MCP tools. Successfully discovered tools must not become unreachable through both paths.

This places the failure after successful tools/list and before model-visible direct/deferred tool registration, matching the boundary described in this issue. The server configuration, process, transport, resource path, and tool discovery all remain healthy.

m13v · 1 month ago

this is the discovery-vs-registration split, and it shows up wherever tool exposure is a separate layer from tool discovery. /mcp, codex mcp list, and your preflight are all reading the same fact: a tools/list round trip succeeded. none of them read the thread's tool surface, which is the thing that actually gates a call. so every green light you have is green about the wrong layer. the useful diff is the 0.91.0 thread against the alpha one, same ListToolsResult, different thread_dynamic_tools. whatever indexes discovered tools into that surface stopped consuming the result, and nothing downstream of it is built to notice the gap.

ssknaoya · 1 month ago

Additional reproduction: Windows / Streamable HTTP / Codex Desktop 0.144.5

I can reproduce this with a custom Streamable HTTP MCP server for a game
I am developing. The server exposes resources and three tools for observing
and controlling the running application.

The failure does not appear to be game-specific: Codex successfully discovers
the tools but does not expose them to the thread.

Environment:

  • Windows
  • Codex Desktop client: 26.707.91948
  • Codex runtime/session version: 0.144.5
  • Model: gpt-5.6-sol
  • MCP transport: Streamable HTTP on localhost
  • MCP server type: custom C++ server embedded in a local application

Observed behavior:

  • MCP initialization succeeds.
  • resources/list, resources/templates/list, and resources/read succeed.
  • The server returns three valid tools from tools/list.
  • Manual tools/call requests to the server succeed.
  • Codex internal logs repeatedly report:

server_name=<custom_server> tool_count=3

  • Nevertheless, none of the three tools is exposed to the model-visible

thread tools.

  • tool_search is also unavailable in the affected thread, so the deferred

tools cannot be discovered.

  • Only the generic MCP resource-reading functions are available to the model.

The discovered tools consist of:

  • one read-only observation tool
  • one ordinary control tool
  • one explicitly destructive data-editing tool

The server exposes resources as well as tools, so this is not caused by an
empty or unsupported resources/list implementation.

I reproduced the result in an independent fresh Codex task. It also reported
that none of the custom MCP tools was directly available, ruling out stale
tool state in an existing thread.

Additional diagnostic result:

codex features list reports:

tool_search_always_defer_mcp_tools removed true

Adding the following user configuration had no effect and was removed
afterward:

tool_search_always_defer_mcp_tools = false

Expected behavior:

Either:

  1. a small discovered MCP tool set should be exposed directly to the thread, or
  2. tool_search must be supplied whenever those tools are deferred.

The failure appears to occur after successful tools/list discovery but
before the tools are exposed to the thread or tool-search surface.

yunusemregul · 1 month ago

I traced this to a concrete code-mode exposure bug and have a tested patch.

Root cause: in code_mode_only, the planner retains only the code executor tools and tools marked DirectModelOnly. MCP tools are intentionally deferred to tool_search, but the cached tool_search handler itself retained normal exposure and was filtered out. The MCP server could therefore initialize and return ListToolsResult, while both access paths were unavailable: the MCP tools were deferred and the search bridge was hidden.

The patch marks tool_search as DirectModelOnly. Deferred MCP tools remain out of the initial prompt, but the model keeps the top-level search bridge, can receive the deferred namespace, and can then call the MCP tool. I added planner coverage and an end-to-end Responses Lite test for search -> deferred MCP namespace -> tool call, and also verified the patched app-server against a real configured Streamable HTTP Jira MCP server.

Review PR: https://github.com/yunusemregul/codex/pull/1
Commit: https://github.com/yunusemregul/codex/commit/dd5b8e84ca190efcd4222f2eb0460e38959a8301

OpenAI documents external Codex contributions as invitation-only, and GitHub rejected creating the PR directly against openai/codex through both GraphQL and REST. The fork PR is therefore the reviewable patch; if a maintainer invites it, the same branch can be submitted upstream directly.

Related reports: #14242, #10499, and #19649.

Woudart · 1 month ago

Thanks for the detailed report. I independently reproduced a closely matching Windows case and narrowed it to a specific Sol/Responses Lite tool-exposure path. I believe it belongs in this thread because MCP discovery succeeds, but the Desktop task does not receive a usable deferred tool surface.

Environment

  • Windows
  • Codex Desktop/App Server 0.144.5
  • Model: gpt-5.6-sol
  • Live account catalog:
  • use_responses_lite: true
  • supports_search_tool: true
  • tool_mode: direct
  • multi_agent_version: v1
  • Independent, read-only stdio MCP canary exposing one unique echo tool

Controlled live results

| Route | Only catalog change | tools/list | Successful MCP call |
|---|---|---:|---:|
| GPT-5.5, normal Responses | none | 1/1 | 1/1 |
| Sol, Responses Lite + deferred tool_search | none | 3/3 | 0/3 |
| Sol, normal Responses + deferred tool_search | use_responses_lite: true → false | 3/3 | 3/3 |
| Sol, Responses Lite + direct MCP namespace | supports_search_tool: true → false | 2/2 | 2/2 |

Every failing Sol/Lite run initialized the MCP server, received a valid one-tool tools/list result, and logged that tool in Codex’s inventory. None made tools/call; each returned the prompt’s exact TOOL_SEARCH_UNAVAILABLE fallback. All five matched Sol controls called the canary with the expected token.

This rules out the MCP process, stdio transport, tool schema, Windows helper, Codex’s MCP invocation router, a generic Sol tool-calling limitation, and random tool choice.

Sanitized final outbound request trace

I captured the final request with the real 0.144.5 executable pointed only at a loopback endpoint. No request was forwarded externally, and no raw body, header values, credentials, prompts, instructions, or tool schemas were persisted.

For the affected Sol/Lite route, the request:

  • targets POST /v1/responses;
  • carries x-openai-internal-codex-responses-lite;
  • has no top-level tools field;
  • starts with a developer-role additional_tools item; and
  • includes:
{
  "type": "tool_search",
  "execution": "client"
}

The initial body does not contain mcp__node_repl, but that is expected for a deferred namespace. Its metadata remains in Codex’s client-side search index and should be returned after a successful tool_search call.

The matched wire controls further narrow the boundary:

  • With only use_responses_lite: false, the same client-executed tool_search appears in top-level tools, and Sol succeeds 3/3.
  • With Lite still enabled but only supports_search_tool: false, additional_tools contains the direct mcp__node_repl namespace and its three child tools. Sol successfully invokes the equivalent synthetic MCP canary 2/2.

Therefore, Responses Lite can expose and invoke direct MCP namespaces. The failing sub-path is specifically the client-executed tool_search surface under Responses Lite.

Public-source check

I checked both the installed source-equivalent commit 8c68d4c and upstream main at 9ff4786. In both versions, the Lite request builder intentionally serializes tools into a leading AdditionalTools item.

The existing stdio_server_round_trip tests:

tool_search → MCP namespace → MCP call

However, it covers only normal Responses. I added a local Lite variant that asserts the wire placement and reuses the complete search/load/invoke round trip:

responses_lite_stdio_server_round_trip ... ok
stdio_server_round_trip ... ok

Formatting also passes. This confirms that the public client serializer, client-side search index, response routing, and MCP invocation path can complete a mocked Lite exchange. It does not cover the internal service transformation that determines which tools become model-visible.

Most likely remaining boundary

MCP initialize/tools/list succeeds
  → Codex builds the deferred search index
  → final Lite request contains client-executed tool_search
  → Responses Lite accepts the request
  → Sol receives no usable tool_search surface

Could a maintainer inspect a sanitized post-ingestion trace for one failing Sol request and confirm:

  1. Whether the accepted developer-role additional_tools item still contains {"type":"tool_search","execution":"client"}.
  2. Whether tool_search is registered in the model-visible tool list.
  3. Whether it is filtered by the Lite route/header, the AdditionalTools conversion, or a Sol-specific allowlist.

I have sanitized per-trial summaries, three matched request traces, and the focused regression-test patch available to attach.

For users, a fresh GPT-5.5 task is a reliable workaround. A fresh Sol task alone is not sufficient in the affected direct + Responses Lite catalog cohort. Forcing non-Lite was useful as a diagnostic, not a supported configuration recommendation.

vdasta · 1 month ago

Additional reproduction: official Linear app/plugin regressed immediately after Desktop update

I can reproduce the same discovery-to-exposure failure with the official curated Linear integration, rather than a custom MCP server.

Environment:

  • macOS, Apple Silicon
  • ChatGPT/Codex Desktop 26.707.91948 (build 5440)
  • Desktop-bundled Codex CLI/app-server 0.144.5
  • Model: gpt-5.6-sol
  • Official linear@openai-curated plugin
  • Normal ChatGPT account/provider path

Before/after boundary:

  • An archived task on the same machine/account records a successful codex_apps Linear get_issue call at 2026-07-16T02:16Z, before the Desktop update.
  • The application bundle was then updated to 26.707.91948.
  • The first fresh tasks under the new build no longer received any callable Linear tools.
  • This is therefore a tighter version/time boundary than a newly configured connector that never worked.

Verified healthy after the update:

  • The Linear plugin is installed and enabled.
  • The bundled plugin manifest still declares the official https://mcp.linear.app/mcp endpoint.
  • The Linear app connection remains linked and its local tool catalog contains the expected issue/project actions.
  • codex mcp list and codex mcp get linear show the Linear MCP server enabled with OAuth.
  • Re-running codex mcp login linear completes successfully.
  • The official Linear MCP endpoint is reachable and completes OAuth negotiation.
  • OpenAI and Linear status pages show no active service incident.

Observed failure:

  • Fresh Desktop tasks receive no callable codex_apps Linear tools.
  • The affected task also receives no tool_search bridge.
  • A fresh isolated codex exec probe cannot call get_issue and reports the Linear tool unavailable.
  • A direct resource probe can fail with unknown MCP server linear even though codex mcp list/get report it enabled.
  • Reauthorization and full Desktop restarts do not restore the tool surface.

This appears to be the same post-discovery exposure failure described above, but it also affects a first-party curated plugin whose app connection and OAuth state are healthy. The update did not merely break a custom server configuration; it made a previously working official connector unreachable from new tasks.

The current release notes say existing app connections should remain unaffected by the App Directory to Plugin Directory migration, so this behavior appears to be an unintended regression.

All identifiers, account details, local paths, OAuth data, issue content, and workspace-specific values have been intentionally omitted.

CaliLuke · 1 month ago

it's really crazy that a bug of this magnitude goes ignored for so long considering the development is done primarily by agents. What is going on? Don't OpenAI have auth tests for MCP in the testing harness? I have that in my own hand rolled framework!

CaliLuke · 1 month ago

please contribute to the discussion https://github.com/openai/codex/discussions/33682 to raise visibility with the team. The MCP bug reports are very clearly being ignored right now.

jonnywilliamson · 1 month ago

Additional reproduction: Solo orchestration MCP / resources visible, action tools unreachable

I can reproduce this with Solo's local stdio MCP server. This is especially confusing because Solo correctly reports Codex as connected, and Codex can use Solo's resource APIs, while Solo's orchestration/action tools remain unreachable.

Environment:

  • macOS 15.7.4, Apple Silicon
  • Codex CLI/session runtime 0.144.5
  • Model gpt-5.6-sol, medium reasoning
  • Solo Desktop 0.9.3
  • MCP transport: local stdio
  • Global configuration:
[mcp_servers.solo]
command = "/Applications/Solo.app/Contents/MacOS/mcp"

Verified working:

  • codex mcp get solo shows the server enabled.
  • Solo completes MCP initialization.
  • Codex can call generic MCP resource discovery for server="solo".
  • resources/list returns Solo scratchpads and todos.
  • A direct MCP tools/list round trip returns Solo's complete action-tool catalog, including:
  • whoami
  • list_agent_tools
  • spawn_agent
  • send_input
  • get_process_output
  • timer tools
  • Direct manual MCP calls through a thin stdio client work.

Observed failure:

  • The fresh Codex thread receives only generic MCP resource helpers.
  • It receives no callable mcp__solo__... action tools.
  • It also receives no tool_search bridge.
  • Consequently, the documented Solo reviewer workflow cannot call list_agent_tools, spawn_agent, send_input, or timers even though Solo is connected and advertises them successfully.

Restart/update test:

  • The original process used Codex 0.144.4.
  • Codex was fully restarted and came back on 0.144.5.
  • A genuinely fresh thread reproduced the same result.
  • codex features list reports:
tool_search                         removed  false
tool_search_always_defer_mcp_tools removed  true
  • Writing tool_search_always_defer_mcp_tools = false to config.toml has no effect on the reported effective state.

Expected behavior:

Either Solo's discovered action tools should be injected directly, or the thread must receive tool_search so the deferred tools can be loaded. A healthy connection plus resource access should not leave every action tool inaccessible.

This matches the code_mode_only / DirectModelOnly root cause and proposed patch described in the comment above.

bbingz · 1 month ago

Analysis (community)

Residual analysis for #19425 (custom stdio MCP discovered by /mcp but tools not exposed to Desktop threads) under docs/contributing.md — invitation-only. Complements our earlier residual note on #32590 (OAuth refresh path); this is a different layer. No unsolicited PR.

Root-cause hypothesis

/mcp and the thread's model-visible tool surface use different connection sets and different failure modes: /mcp can fall back to a tool catalog cache, while capture_binding_with_metadata silently skips servers whose client is not ready and never falls back. When search_tool_enabled is true, MCP tools are also marked Deferred, so a skipped server is missing from both initial specs and tool_search.

Tracing the exposure path at HEAD (4c43465133) to add a code-anchored complement to the OAuth-refresh thread (#32590). I believe there are two distinct bugs here, and only one is token-refresh.

Discovery->exposure gap, separate from auth. The /mcp status path and the Desktop thread's model-visible tool list read from different connection sets. /mcp (codex-rs/codex-mcp/src/mcp/mod.rs:406-429) builds a fresh McpConnectionSet and calls list_all_tools (connection_manager/tool_catalog.rs:60-125), which falls back to the 30-min McpToolCatalogCache (rmcp_client.rs:526-539) and skips tool_is_model_visible. The thread's binding (connection_manager/tool_catalog.rs:131-217, capture_binding_with_metadata) requires client.client().await to be Ok, silently continues on Err with no cache fallback (:149-151), and drops non-model-visible tools (:185-186). So a server that /mcp lists can be silently absent from the thread - exactly the symptom arbenl, xy6859, dionisokan report, with healthy OAuth (and, for several reporters, no OAuth at all - stdio).

Deferral compounds it. mcp_tool_exposure.rs:35-39 marks every MCP tool Deferred when search_tool_enabled is true (spec_plan.rs:333-335), so even tools in the binding are omitted from the initial specs (spec_plan.rs:258-268) and reachable only via tool_search - whose index is built from that same per-thread slice (spec_plan.rs:971-976). If the server was silently skipped, tool_search is empty too, and the tool is unreachable by either path. Woudart's A/B here (supports_search_tool: true->false, 0/3 -> 2/2) is direct causal evidence that deferral is the proximate cause. c53b1dae09 (#29486) is the version-boundary commit; the --enable/--disable flags are Stage::Removed no-ops (features/src/lib.rs:491-493), which matches dionisokan's finding.

Suggested minimal fix: (1) give capture_binding_with_metadata the same listed_tools cache fallback list_all_tools already has, for stdio servers; (2) when search_tool_enabled is true but the deferred-tool search index is empty, fall back to Direct exposure for those namespaces (or emit a tools_changed event) instead of silently swallowing them; (3) emit an exposure-failure event on every silent skip so /mcp and the UI can reconcile - this would also address #26196 (tools disappear after reconnect) and give #16607's resume path an invalidation hook.

Fail-first tests I'd add: custom stdio tool appears in /mcp but is absent from the thread's model-visible specs; long-running thread drops a tool after server reconnect with no event; deferred tool unreachable when search index is empty.

Separately - the frustration voiced in discussion #33682 is fair. The MCP path is under active refactoring (25+ commits May-Jul 2026, including the McpRuntime centralization #34930 and McpConnectionSet split #34708), so this is a good moment to land the parity fix before the divergent code paths get baked in further. If the outline aligns, would an invited PR with the fail-first tests above be welcome? I will not open an unsolicited PR.

Cross-links (related residual, not duplicates of this path): #30922, #30343, #26196, #16607, #33593; OAuth-refresh residual remains #32590.

Happy to refine. No unsolicited PR from me.

TeaShaman-cyber · 25 days ago

Additional reproduction: Windows / Streamable HTTP / PAT-authenticated remote MCP

I can reproduce the same discovery-to-exposure failure on Windows with the official remote GitHub MCP server.

Environment and configuration:

  • Codex Desktop on Windows, build 26.727.51351.
  • Project-scoped .codex/config.toml initially contained two MCP servers:
  • an unauthenticated project-scoped Gramps Streamable HTTP server;
  • the remote GitHub Streamable HTTP server with bearer_token_env_var = "GH_TOKEN".
  • The project is trusted.

Control comparison:

  • The project-scoped Gramps MCP server is visible and callable in the Desktop thread.
  • Therefore project-local MCP configuration is being loaded and project MCP tools can reach the thread surface.

GitHub MCP verification outside the Desktop tool manifest:

  • codex mcp list and codex mcp get github report the server enabled with transport = streamable_http and bearer_token_env_var = GH_TOKEN.
  • A direct MCP client completes initialize with HTTP 200.
  • tools/list succeeds.
  • get_me succeeds and returns the expected GitHub account.
  • A read-only search_issues call succeeds and returns results.

The GitHub entry was then moved from the project config to the global ~/.codex/config.toml, followed by a full Codex Desktop restart and a fresh thread. The result did not change:

  • codex mcp list still reports GitHub enabled and authenticated by bearer-token binding.
  • The Gramps tools remain visible in the Desktop session.
  • No GitHub MCP namespace or issue/repository tools appear in the current Desktop tool manifest.
  • No search_issues, issue_read, get_me, or repository tools are callable from the Desktop thread.

This separates the failure from:

  • project trust or project-config loading;
  • the GitHub endpoint;
  • PAT authorization;
  • MCP initialization;
  • tools/list discovery;
  • the GitHub MCP server implementation.

The observed boundary remains:

MCP initialize/tools/list succeeds
  -> Codex CLI registry shows the server enabled
  -> Desktop thread receives no GitHub MCP tools

The Gramps control is important: an unauthenticated project MCP is exposed normally, while the authenticated remote HTTP GitHub MCP is not. This looks like a Desktop/app-server exposure or admission problem for this remote/authenticated MCP path, rather than a generic project-config problem.

No credentials, token values, or private repository data are included here.

TeaShaman-cyber · 25 days ago

Human context and attribution

This report was prepared collaboratively by Semyon Poklad and Lad, an AI engineering agent, based on a user-requested reproduction and verification.

The practical impact is larger than this single missing tool namespace. We have repeatedly had to fall back to wrappers, shell probes, browser routes, and manual transport checks because the native Codex GitHub integration and the Codex Desktop MCP tool surface do not provide a reliable path to ordinary development operations.

GitHub MCP itself works when called through a direct MCP client, and another AI client in the same environment is able to use comparable GitHub/MCP functionality natively. The failure is specifically in the Codex Desktop integration: the server is configured, authenticated, discovered, and listed by codex mcp, but its tools are still unavailable to the active Desktop thread.

This creates disproportionate user friction around a basic development capability: reading and updating issues and repositories. After enough cycles of configuration checks, wrappers, restarts, and fallback routes, users can lose track of the actual engineering task entirely.

We are asking for a reliable end-to-end contract:

configured MCP server
→ authenticated connection
→ successful tools/list
→ tools registered in the Desktop thread
→ callable issue/repository operation

Attribution: prepared collaboratively by Semyon Poklad and Lad, an AI engineering agent. The initial report was published before the final manual review step; this addendum is being submitted to correct the attribution and explain the user impact.

rkcrawf-lang · 23 days ago

Open Design is listed as enabled by codex mcp list, but @open-design
does not appear in Codex Desktop's mention picker after a full app restart.
Open Design 0.17.0; Codex Desktop 26.727.51351; codex-cli 0.145.0.

bbingz · 22 days ago

@TeaShaman-cyber's control comparison is the most useful new datum here: two Streamable HTTP servers in the same trusted project, one visible in the Desktop thread (Gramps), one not (remote GitHub). Transport and auth are therefore not the discriminator, which fits the binding-layer skip traced above rather than a GitHub/PAT problem.

Recap of that split: capture_binding_with_metadata (codex-rs/codex-mcp/src/connection_manager/tool_catalog.rs:131-217) requires client.client().await to be Ok and silently continues on Err (:149-151) with no cache fallback, while /mcp and codex mcp list go through list_all_tools, which does fall back to the 30-min McpToolCatalogCache (rmcp_client.rs:526-539). A server that is enabled, authenticated and listed can therefore be absent from the thread — which is exactly what both of you are seeing.

@rkcrawf-lang's mention-picker symptom is the same slice: the picker is built from the per-thread binding, so a server skipped there never reaches it.

To separate the skip from the deferral half, both of you can A/B supports_search_tool: true → false. Woudart's earlier A/B (0/3 → 2/2) isolates deferral (mcp_tool_exposure.rs:35-39, spec_plan.rs:333-335). If the tools appear with search off, it is deferral; if they still do not, it is the silent skip.

Still no unsolicited PR — the parity fix outlined above (cache fallback in the binding, plus an exposure-failure event on every silent skip) is available if a maintainer wants it.

wxy954072132 · 21 days ago

Current macOS reproduction on a newer Desktop/App Server build (2026-08-07).

Environment

  • ChatGPT Desktop: 26.803.41515
  • Bundled Codex: codex-cli 0.147.0-alpha.6.5
  • Platform: macOS
  • Five independent user-configured external STDIO MCP servers

Observed

  • Standalone MCP discovery succeeds for all five servers: initialize and tools/list complete successfully, returning 47, 30, 1, 1, and 2 tools respectively.
  • In a newly created Desktop thread, none of the corresponding mcp__<server>__* namespaces are present in the effective tool registry.
  • That thread also has no deferred tool loader capable of recovering those missing namespaces.
  • Managed HTTP connectors and the bundled node_repl server are exposed in the same thread. The missing set is specifically the user-configured external STDIO servers.
  • features.code_mode.excluded_tool_namespaces and features.code_mode.direct_only_tool_namespaces are both empty.
  • No conflicting duplicate provider is currently configured.

This also reproduced on the previous Desktop/App Server combination:

  • ChatGPT Desktop: 26.730.61639
  • Bundled Codex: 0.147.0-alpha.1.2

Control comparison on that build:

  • codex exec using the same bundled binary and shared MCP configuration successfully called a read-only tool from one of the STDIO servers with both gpt-5.6-sol and gpt-5.5.
  • A fresh Desktop thread using gpt-5.5 still returned zero matching tools for the same namespace, including an exact namespace selection.

This rules out MCP protocol health, downstream authentication, the selected model, stale thread state, and an explicit namespace exclusion. The remaining failure boundary is still between successful MCP catalog discovery and registration of those tools in the Desktop thread's effective/direct-or-deferred tool surface.

Expected

After an enabled STDIO MCP server completes tools/list, its tools should either be callable directly, discoverable through the deferred tool mechanism, or accompanied by a visible exposure error explaining why they were rejected.

No credentials, command arguments, environment values, internal service names, or private payloads are included in this report.

TeaShaman-cyber · 20 days ago

Follow-up: Windows AppX / CLI control test

I ran a bounded reproduction on Windows with the current Codex Desktop Store/AppX build 26.730.8199.0 and the current global Codex configuration.

Observed:

  • the project-root .env contains a working GH_TOKEN; the token value was loaded only into a child process and was not printed or persisted;
  • gh repo view TeaShaman-cyber/theseus-research succeeds as a read-only control;
  • a direct GitHub Streamable HTTP MCP client completes initialize, establishes a session, and completes tools/list;
  • codex mcp get github reports the server as enabled with transport = streamable_http and bearer_token_env_var = GH_TOKEN;
  • an isolated codex exec --ignore-user-config run with only the GitHub MCP server and an explicitly injected GH_TOKEN successfully performs one read-only search_repositories call;
  • an ordinary codex exec run without explicit environment injection reports GH_TOKEN not set, showing that the project-root .env is not automatically loaded into the MCP child process;
  • the current Desktop thread exposes no mcp__github__* tools in its native tool manifest;
  • the local runtime audit reports no unavailable-MCP-server events, but this does not establish that the server was exposed to the Desktop thread.

This separates the working parts from the remaining failure boundary:

.env / credential
  -> GitHub authorization
  -> MCP initialize
  -> tools/list
  -> Codex CLI tool call: PASS

Desktop/AppX
  -> native thread tool exposure: FAIL

The remaining problem is therefore not GitHub authorization, the GitHub MCP endpoint, MCP initialization, tools/list, or stdio transport. It is the Desktop/AppX registration or exposure path, with launch-time environment inheritance as a separate possible factor.

A plain restart with unchanged configuration and unchanged launch conditions is not a meaningful control for this reproduction. We are currently using the working CLI route as the operational fallback.

TeaShaman-cyber · 20 days ago

Follow-up: Current AppX build still reproduces the exposure gap

After Codex Desktop updated, I fully restarted the application and repeated the bounded Windows reproduction.

Current environment:

  • Codex Desktop Store/AppX build: 26.803.5235.0;
  • the running ChatGPT.exe and bundled codex.exe are loaded from the new AppX package path;
  • the GitHub MCP entry remains enabled as Streamable HTTP with bearer_token_env_var = "GH_TOKEN";
  • no Codex configuration, project .env, WSL environment, or wrapper was changed for this comparison.

Observed after the update and restart:

  • the project-root .env still provides a working GH_TOKEN when explicitly loaded into a child process;
  • the direct GitHub MCP control path still completes initialize and tools/list;
  • the isolated CLI control still performs a read-only GitHub MCP call successfully when GH_TOKEN is explicitly present in the child environment;
  • codex mcp get github still reports the server as enabled;
  • the local runtime audit remains OK, with no unavailable-server events;
  • the fresh Desktop process still exposes no mcp__github__* tools in the native thread tool manifest.

This update/restart therefore does not change the observed boundary:

configured → authenticated → initialized → tools/list succeeds, but Desktop thread tool exposure still fails.

The reproduction now covers a newer AppX build and a fresh process, so the missing GitHub namespace is not explained by a stale pre-update Desktop process. The working CLI route remains available as the operational fallback.

bbingz · 20 days ago

@TeaShaman-cyber thanks — the AppX 26.803.5235.0 restart control is the right pin.

Your split still matches the earlier binding-layer read:

configured → authenticated → initialize → tools/list (and CLI tool call) PASS, but Desktop thread tool exposure of mcp__github__* still FAIL on a fresh process.

So this is not a stale Desktop session and not GitHub auth/transport. Launch-time env inheritance for bearer_token_env_var remains a secondary factor for auto-spawned MCP children; the primary gap is still the Desktop thread registration/exposure path. CLI fallback remains the workable route until that lands.

TeaShaman-cyber · 20 days ago

Control comparison after restart: Gramps exposed, GitHub unavailable

After a full restart of the current Codex Desktop build (26.803.5235.0), the live Gramps MCP control became available in the same Desktop context:

  • 57 mcp__family_gramps__* tools appeared in the native manifest;
  • a read-only mcp__family_gramps__get_metadata call succeeded;
  • the GitHub server remained absent from the native manifest;
  • the runtime audit now reports github in unavailable_servers.

This control comparison rules out a generic inability to refresh the Desktop manifest after restart. The refreshed Desktop can expose and call one external MCP server, while the configured GitHub MCP server remains unavailable. The remaining boundary is therefore GitHub-specific admission, authentication, transport handling, or exposure rather than a universal stale-manifest problem.

No credentials or private payloads are included here.

bbingz · 20 days ago

@TeaShaman-cyber the Gramps vs GitHub control after the same restart is the decisive pin:

  • Gramps: 57 mcp__family_gramps__* tools in the native manifest + live call OK
  • GitHub: still absent from the manifest; now also listed under unavailable_servers

That rules out a universal stale-manifest / “Desktop never re-binds external MCPs” story. Remaining failure is GitHub-specific admission (auth/env inheritance for bearer_token_env_var, transport handling, or exposure), not Desktop MCP plumbing in general. CLI path with explicit GH_TOKEN remains the working fallback.