Skip to content

fix(codexcli): translate the MCP keys Codex reads under different names - #2608

Merged
dyoshikawa merged 3 commits into
mainfrom
resolve-issue-2496-codexcli-mcp-keys
Aug 7, 2026
Merged

fix(codexcli): translate the MCP keys Codex reads under different names#2608
dyoshikawa merged 3 commits into
mainfrom
resolve-issue-2496-codexcli-mcp-keys

Conversation

@dyoshikawa

Copy link
Copy Markdown
Owner

Summary

Implements the four MCP key-translation gaps recorded in the 2026-08-06 re-check comment on #2496. src/features/mcp/codexcli-mcp.ts translated only enabledTools / disabledTools / envVars / experimentalEnvironment; every other canonical field fell through the generic passthrough and landed in config.toml under the canonical name rather than the name Codex reads. Verified against RawMcpServerConfig at rust-v0.146.1.

  1. tools (the bug). Codex declares tools: Option<HashMap<String, McpServerToolConfig>>, so the canonical string[] is a hard type error that fails the whole server entry rather than degrading. It is now stripped on generate with a warning pointing at enabledTools / disabledTools. No tools.<name>.approval_mode authoring surface was invented — that is a design call, and the canonical tools is a reserved string[]. The same table is no longer lifted into the canonical model on import either: it is CLI-written approval state that the generate path already preserves in place, and its shape would not survive the canonical schema.
  2. headershttp_headers on generate and back on import, so an authenticated remote server actually authenticates. Codex errors with "http_headers is not supported for stdio", so on a stdio server the headers are dropped with a warning instead of failing the entry.
  3. Timeouts. timeouttool_timeout_sec and networkTimeoutstartup_timeout_sec, converting milliseconds to seconds (a sub-second remainder stays fractional; Codex reads both as f64). Codex also accepts startup_timeout_ms and prefers startup_timeout_sec when both are set, so import mirrors that precedence.
  4. Foreign keys stripped. type/transport (Codex infers the transport from command versus url), alwaysAllow, trust, and the Kiro authoring lists are dropped silently — they appear on nearly every canonical server, so warning on them would fire on every generate.

Still open on #2496

This is a slice. The parent issue keeps its design items and stays open: the [agents] / [[skills.config]] gateway-ownership question, plugin bundles, and a canonical spelling for bearer_token_env_var (which passes through under its own name today, as does env_http_headers).

Testing

  • pnpm cicheck (full: code + content)
  • npx vitest run --config vitest.e2e.config.ts src/e2e/e2e-mcp.spec.ts
  • New round-trip tests for each gap, including the fractional-seconds case and the startup_timeout_ms precedence. Two existing tests were updated to the new intent: the canonical tools array no longer reaches the file, and type is no longer written for remote servers.

Part of #2496

🤖 Generated with Claude Code

The codex MCP adapter translated only enabledTools/disabledTools/envVars/
experimentalEnvironment; every other canonical field reached config.toml under
its canonical name. Verified against Codex rust-v0.146.1 RawMcpServerConfig:

- tools: Codex declares it as a per-tool approval table, so the canonical
  string array is a serde type error that fails the whole server entry. It is
  now dropped with a warning on generate, and Codex's approval table is no
  longer lifted into the canonical model on import.
- headers is written as http_headers (and imported back), so authenticated
  remote servers actually authenticate. On a stdio server Codex rejects
  http_headers outright, so it is dropped with a warning there.
- timeout and networkTimeout are converted into tool_timeout_sec and
  startup_timeout_sec (milliseconds to seconds), both directions.
  startup_timeout_ms is imported verbatim unless the seconds spelling is also
  set, matching Codex's own precedence.
- type/transport/alwaysAllow/trust and the Kiro lists are dropped silently.

Part of #2496.
…rt on import

Addresses review findings on PR #2608:

- A negative timeout is now dropped with a warning in both directions. Codex
  builds a Duration out of tool_timeout_sec / startup_timeout_sec, and
  Duration::try_from_secs_f64 errors on a negative value, which fails the whole
  config.toml — the same failure class this PR fixes for tools.
- http_headers is shape-checked on import (a table of string values) and passed
  through omitPrototypePollutionKeys, matching the generate direction, so a
  hand-written value cannot produce a .rulesync/mcp.jsonc the schema rejects.
- Dropping the canonical type left an imported Codex server with no transport
  at all, since Codex states none of its own. A url server with no command now
  gets type: "http" restated on import, which keeps the round-trip stable for
  the adapters that branch on it.

Adds warn assertions, malformed-value cases, and a full canonical -> codex ->
canonical round-trip test.
@dyoshikawa
dyoshikawa merged commit cf2a1f1 into main Aug 7, 2026
9 checks passed
@dyoshikawa
dyoshikawa deleted the resolve-issue-2496-codexcli-mcp-keys branch August 7, 2026 08:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants