Cursor provider: Codex tools only reachable via GetDynamicTools/CallDynamicTool, but native-exec denial guidance points to a top-level `exec` the model cannot see

Open
#8,132 1 comment 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
48/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Active
Tech stack
typescript

Research direction

Start with src/adapters/cursor/native-exec.ts and tool-guidance.ts to trace the denial redirect and code-mode guidance, then read src/adapters/cursor/tool-naming.ts for existing dynamic-tool handling. Check how GetDynamicTools and CallDynamicTool expose the opencodex-responses namespace; the issue gives no test path, so locate relevant coverage before changing behavior. Done means deferred tools are reachable through the guidance or registered at the top level, without claiming unavailable top-level tools.

Written by the indexing model from the issue text.

Description

catalog provider provider-compatibility tools
Client or integration

Codex App

Provider or upstream service

cursor

OpenCodex version

2.96.0 (same as main @ 684ad75)

Endpoint or capability

/v1/responses - tool calls (Cursor native-exec redirect / MCP tool registration, code mode)

Current behaviour

With Codex App (code mode) routed to cursor/claude-opus-5-5, the top-level tool list the model sees contains only Cursor-native tools (Read, Write, StrReplace, Shell, Glob, Grep, ...) plus GetDynamicTools / CallDynamicTool. The Codex client tools (exec, wait, ...) are not registered at the top level; they only appear inside the deferred dynamic namespace opencodex-responses.

Every Cursor-native call is denied (nativeLocalExec unset = "off", as designed). The redirect text from cursorCodeModeExecRedirectHint() (src/adapters/cursor/native-exec.ts) and the code-mode notes in tool-guidance.ts tell the model to "Re-issue this operation NOW through the exec tool" and that "Every other tool this turn lists remains callable at the top level as usual". The model cannot see a top-level exec, so it keeps retrying native Read/Shell/Write, and every file/shell operation fails until it happens to discover the tool through GetDynamicTools.

Once discovered, CallDynamicTool(namespace="opencodex-responses", toolName="exec", arguments={input: "..."}) works: nested tools.exec_command runs on the Codex host (git, PowerShell and network downloads all succeeded). Execution plumbing is fine; only discovery/guidance is broken.

Expected behaviour

When Cursor defers MCP tools behind GetDynamicTools/CallDynamicTool, OpenCodex should either (a) get the Codex client tools registered at the top level again, or (b) detect the deferred mode and make the denial redirect and tool guidance name the real call path, e.g. "call CallDynamicTool with namespace opencodex-responses, toolName exec", instead of a bare top-level exec.

Minimal redacted request or reproduction
# OpenCodex 2.96.0 (same as main @ 684ad75), Windows, Codex App, proxy on 127.0.0.1:10100
# ~/.codex/config.toml (redacted)
model = "cursor/claude-opus-5-5"
openai_base_url = "http://127.0.0.1:10100/v1"
model_catalog_json = "<user>/.codex/opencodex-catalog.json"
# ~/.opencodex/config.json providers.cursor: nativeLocalExec not set (default "off")

# In Codex App, ask the model to read any file in the workspace.
# 1. Model calls Cursor-native Read / Shell / Write / Glob / Grep -> all denied.
# 2. GetDynamicTools(namespace="opencodex-responses") lists exec, wait, ...
# 3. CallDynamicTool(namespace="opencodex-responses", toolName="exec",
#      arguments={input: 'text(await tools.exec_command({cmd: "git --version"}))'})
#    -> succeeds.
Actual response or error
Every Cursor-native Read/Write/Shell/Glob/Grep call returns the OpenCodex denial, which lists the catalog
("available tool names are exactly exec, wait, mcp__cua_repl__js, ...") and says
"Cursor-native Read/Glob/Grep/LS/Shell/Write/Fetch are not available in this request".
Native Shell is rejected in ~240 ms, i.e. nothing is executed.

Top-level tools actually visible to the model: Read, Write, StrReplace, Shell, Glob, Grep,
AskQuestion, GetDynamicTools, CallDynamicTool, ... (no exec / wait).
Upstream documentation

No public Cursor specification for the deferred dynamic-tool channel (GetDynamicTools / CallDynamicTool) that I know of. Related OpenCodex devlog: devlog/_fin/260711_cursor_browser_bridge/004_fix_mcp_tools_channel.md verified top-level registration via AgentRunRequest.mcp_tools with cursor/gpt-5.6-luna and cursor/claude-4.5-sonnet. This report suggests newer models (cursor/claude-opus-5-5) get MCP tools deferred instead (inference, not confirmed against Cursor docs).

Suggested mapping or implementation notes
  • src/adapters/cursor/tool-naming.ts only knows GetDynamicTools as an entry in CLAUDE_CLIENT_BARE_TOOL_NAMES (collision avoidance); no code path treats it as the route to client tools.
  • No detection in src/adapters/cursor for "client tools deferred behind a dynamic namespace" (searched GetDynamicTools, CallDynamicTool, dynamic tool, deferred tool).
  • Possible fix: when the model is in a deferred-MCP mode (by model id, or observed from the first GetDynamicTools call), switch cursorCodeModeExecRedirectHint() and the code-mode tool guidance to name CallDynamicTool + namespace opencodex-responses + toolName exec, and drop the "remains callable at the top level" sentence.
  • Not a good workaround: nativeLocalExec="on" bypasses the Codex sandbox/approval, and rejectNativeFileMutations still blocks native writes when apply_patch is advertised.
Additional context and attachments

The denial wording is consistent for models where MCP tools are top-level; the problem is specific to models where Cursor defers them. Happy to provide more traces if useful.

Checks
  • I searched existing provider and compatibility issues.
  • The request and response were redacted.
  • The expected behaviour is based on an upstream specification or a concrete client requirement.
Dominant language
TypeScript
Stars
16.9k
Forks
1.3k
Avg merge
18h 28m
Merged PRs (30d)
697

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from lidge-jun/opencodex

All issues in lidge-jun/opencodex

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.