You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Merge feat/mcp-bridging: MCP server bridging with hardened reconciliation
Bridges Claude Code MCP server definitions into Codex config.toml.
Supports stdio and HTTP transports, multi-project global ownership,
degraded discovery preservation, credential detection, and exclusions.
Iterative review (9 rounds, 14 fixes) hardened: scope-gated config
reads, disk presence verification, type validation at discovery and
translation, symlink containment for project configs, uninstall error
handling, and first-time adoption of existing bridge-managed entries.
Copy file name to clipboardExpand all lines: AGENTS.md
+7-3Lines changed: 7 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -26,7 +26,9 @@ claude-code-codex-bridge/
26
26
│ └── workflows/
27
27
├── docs/
28
28
│ ├── agent-skills-standard.md
29
-
│ └── codex-cli-reference.md
29
+
│ ├── claude-code-mcp-reference.md
30
+
│ ├── codex-cli-reference.md
31
+
│ └── mcp-bridge-mapping.md
30
32
├── src/
31
33
│ └── cc_codex_bridge/
32
34
│ ├── __main__.py
@@ -119,8 +121,10 @@ The bridge translates between two ecosystems. Authoritative reference documents
119
121
120
122
-`docs/agent-skills-standard.md` — the open Agent Skills standard (from [agentskills.io](https://agentskills.io/)): skill directory structure, `SKILL.md` format, frontmatter fields, progressive disclosure, client implementation contract, and script conventions.
121
123
-`docs/codex-cli-reference.md` — Codex CLI specifics (from [developers.openai.com/codex](https://developers.openai.com/codex/) and the [Codex source](https://github.com/openai/codex)): instructions discovery (`AGENTS.md`), skill discovery hierarchy, agent role configuration, agent file auto-discovery, and Claude Code vs Codex comparison.
124
+
-`docs/claude-code-mcp-reference.md` — Claude Code MCP server configuration format: `~/.claude.json` structure, per-project scoping, `.mcp.json` project-shared format, stdio/HTTP/SSE transports, and `headersHelper`/`oauth` fields.
125
+
-`docs/mcp-bridge-mapping.md` — MCP bridge mapping rules: how each CC MCP field maps to Codex `config.toml` format, transport-specific translation, bearer token extraction, and unsupported feature handling.
122
126
123
-
Consult these before making design decisions that depend on how Codex discovers skills, loads instructions, or defines agent roles.
127
+
Consult these before making design decisions that depend on how Codex discovers skills, loads instructions, defines agent roles, or configures MCP servers.
124
128
125
129
## Canonical Architecture
126
130
@@ -150,7 +154,7 @@ Also check `DESIGN.md` for the canonical description of the current implemented
150
154
- Review `.claude/docs/analysis/` for prior investigations and technical findings.
151
155
- Review spec documents in `.claude/docs/plans/`, such as `*-spec.md`, for the intended contract and constraints.
152
156
- Review implementation plans in `.claude/docs/plans/`, such as `*-implementation-plan.md`, for sequencing, scope, and expected milestones.
153
-
- Consult `docs/agent-skills-standard.md` and `docs/codex-cli-reference.md` for the authoritative domain references that the bridge targets. These supersede earlier research notes in `.claude/docs/research/`.
157
+
- Consult `docs/agent-skills-standard.md`, `docs/codex-cli-reference.md`, `docs/claude-code-mcp-reference.md`, and `docs/mcp-bridge-mapping.md` for the authoritative domain references that the bridge targets. These supersede earlier research notes in `.claude/docs/research/`.
154
158
- Update `DESIGN.md` whenever the implemented architecture changes materially.
155
159
- Update the relevant analysis, spec, or plan docs when the command surface, architecture, or implementation direction changes materially.
- state version (currently 9; v8 state files are migrated on read, empty migrated hashes are treated as preserve-only until a trusted hash is recorded, and the next reconcile backfills hashes for preserved or retained managed files from on-disk content when possible)
213
+
- managed MCP server names as a name-to-content-hash mapping (for project-scope MCP servers in `.codex/config.toml`)
214
+
- state version (currently 11; v8–v10 state files are migrated on read)
204
215
205
216
The global registry records:
206
217
207
218
- generated skill install directory names with content hashes and owning project roots
208
219
- generated agent `.toml` filenames with content hashes and owning project roots
209
220
- vendored plugin resource directory names with content hashes and owning project roots
221
+
- bridge-owned global MCP server names with content hashes and owning project roots
210
222
- a sorted list of all reconciled project roots (the `projects` list)
211
223
212
224
### Safety rules
@@ -243,6 +255,13 @@ The global registry records:
243
255
- stale managed outputs are removed when no longer desired
244
256
- cleanup uses the codex_home recorded in bridge state, not the caller-supplied value, to ensure registry operations target the correct global state
245
257
- project-local generated skill directories are removed as whole directories, not individual files, consistent with global skill directory ownership
258
+
- MCP entries in `config.toml` are ownership-aware: only bridge-owned entries (tracked in state or registry) are modified; user-authored entries with the same name are never touched or adopted
259
+
- user-authored MCP entries that collide with bridge-discovered servers are skipped during apply and excluded from state/registry tracking — `clean` will not remove them
260
+
- when MCP discovery is degraded (config file exists but contains malformed JSON), stale-entry removal is suppressed — previously-bridged entries survive until the file is fixed
261
+
262
+
#### Known limitation: multi-project global MCP update on first reconcile
263
+
264
+
When project B first encounters a global MCP server already created by project A with different content, B adds itself as a co-owner in the registry but cannot update `config.toml` because the entry is not in B's `owned` set. The registry records B's desired hash while the disk retains A's content. This self-heals on B's second reconcile (B is then in `previously_owned_global`) or on A's next reconcile. This is accepted because MCP servers overwhelmingly come from plugins with identical configs across projects — the scenario of two projects wanting different content for the same global MCP server name is not realistic in practice. Do not attempt to fix this without a concrete real-world use case that demonstrates the need.
246
265
247
266
## 7. Discovery Architecture
248
267
@@ -286,6 +305,22 @@ Discovery lives in `src/cc_codex_bridge/discover.py`.
286
305
- project-level commands are discovered from `<project>/.claude/commands/` as `*.md` files
287
306
- command discovery follows the same pattern as agent discovery (top-level `.md` files in a directory)
288
307
308
+
### MCP server discovery
309
+
310
+
`src/cc_codex_bridge/discover_mcp.py` reads MCP server definitions from Claude Code configuration files.
When the same server name appears at multiple scopes, highest precedence wins. SSE transport servers are skipped (unsupported in Codex). Plugin-provided MCP servers (using `${CLAUDE_PLUGIN_ROOT}`) are not discovered — standalone equivalents cover them.
319
+
320
+
Transport detection: `command` field → stdio; `type: "http"` or `url` field → HTTP.
321
+
322
+
When a source file exists but contains malformed JSON, discovery is *degraded*: servers from other valid sources are still discovered, but the `mcp_discovery_degraded` flag is set on the `DiscoveryResult`. The reconcile pipeline uses this flag to suppress stale-entry removal — previously-bridged MCP entries survive until the corrupt file is fixed and a subsequent reconcile runs normally.
323
+
289
324
### Plugin enablement
290
325
291
326
- the `claude` CLI is a hard runtime dependency for the bridge
@@ -570,6 +605,28 @@ Agent references (`plugin:agent-name`) are not rewritten because agent invocatio
570
605
571
606
User-level and plugin skills are installed to the global Codex skill registry at `~/.codex/skills/`. Project-level skills are installed to project-local `.codex/skills/` directories and tracked as managed project skill directory names in the bridge state. Both global and project skills use exact directory-snapshot comparison for change detection.
572
607
608
+
### 8.6 MCP server translation
609
+
610
+
`src/cc_codex_bridge/translate_mcp.py` converts `DiscoveredMcpServer` objects into `GeneratedMcpServer` objects.
611
+
612
+
stdio mapping: `command` → `command`, `args` → `args`, `env` → `env` (omitted when empty). The CC `type` field is stripped (Codex infers transport from field presence).
613
+
614
+
HTTP mapping: `url` → `url`, `headers` → `http_headers`. Special case: `Authorization: "Bearer ${VAR}"` headers are extracted into `bearer_token_env_var` and the header is removed.
615
+
616
+
Diagnostics (warnings, not errors): `headersHelper` (no Codex equivalent), `oauth` (user must run `codex mcp login`).
617
+
618
+
### 8.7 MCP TOML editing
619
+
620
+
`src/cc_codex_bridge/toml_config.py` provides surgical editing of Codex `config.toml` files using `tomlkit` for round-trip preservation of comments and formatting.
621
+
622
+
Key functions:
623
+
-`read_codex_config(path)` → parse or return empty doc
- config exclude subcommand handlers: discovery-backed add/remove/list for plugin/skill/agent/command exclusions
970
+
- config exclude subcommand handlers: discovery-backed add/remove/list for plugin/skill/agent/command/mcp_server exclusions
914
971
-`config_scan_commands.py`
915
972
- config scan subcommand handlers: glob-validated add/remove/list for scan paths
916
973
-`config_scope.py`
@@ -1009,6 +1066,9 @@ These are current implemented simplifications, not necessarily permanent design
1009
1066
- exclusion ids are exact-match identifiers, not wildcard/glob patterns
1010
1067
- commands are translated to native Codex prompt files (`~/.codex/prompts/`) rather than Codex skills, avoiding namespace collisions with the skill directory entirely
1011
1068
- LaunchAgent scheduling with automatic `launchctl bootstrap/bootout` is supported; watcher mode is not
1069
+
- MCP planning assumes `mcp_servers` is a TOML table when the document parses successfully — a hand-crafted scalar value (`mcp_servers = "oops"`) would pass TOML validation but crash during apply, leaving the registry inconsistent
1070
+
- MCP translation does not remap Claude `${VAR}` env-var references in non-Authorization fields — Codex may treat these as literal strings rather than expanding them at runtime; the bridge copies the syntax verbatim and relies on the host shell or Codex runtime to resolve them
1071
+
- MCP server names must match `[A-Za-z0-9_-]`; servers with dots, spaces, or other characters are skipped with a diagnostic — this is stricter than TOML's quoted-key support but required for registry key safety and Codex `mcp__<server>__<tool>` naming
1012
1072
1013
1073
Any change to these constraints should update this file.
0 commit comments