Skip to content

fix(mcp): deliver team MCP servers to Codex in project scope (#954) - #956

Merged
jeff-r2026 merged 5 commits into
Tencent:mainfrom
SaulMoro:fix/954-codex-project-mcp
Oct 3, 2026
Merged

jeff-r2026 merged 5 commits into
Tencent:mainfrom
SaulMoro:fix/954-codex-project-mcp

Conversation

@SaulMoro

@SaulMoro SaulMoro commented Oct 1, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

In project scope, a pull never delivered team MCP servers to Codex. #252 left the built-in codex entry without mcpProject on the assumption that Codex has no project-scope MCP. In fact Codex reads <project>/.codex/config.toml once the project is trusted.

 codex: {
   skills: '.codex/skills',
   settings: '.codex/hooks.json',
   agents: '.codex/agents',
   mcp: '.codex/config.toml',
+  mcpProject: '.codex/config.toml',
 }

The reconcile, ownership records, git-exclude protection, mcp list, mcp remove, uninstall and the MCP servers delivered to codex check already handled a Codex project file, so they needed no change.

Codex skips an untrusted project without saying so, so doctor gets a read-only check for that case:

buildCodexProjectTrustCheck              (project scope, `codex` only)
  only if .codex/config.toml holds a server managed-mcp.json records for codex
  read <toolRoots.codex or ~/.codex>/config.toml → projects table
  first entry with a trust_level, by real path:
    checkout → main checkout             (an entry without trust_level decides nothing)
  "trusted"  → pass
  otherwise  → fail, with the manual fix:
               trust the project when Codex asks, or add
               [projects."<main checkout>"] trust_level = "trusted"

The check never writes Codex trust (projects.* or hooks.state); #955 owns that. codex-internal and tcodex are left as they are because their project paths are unverified.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature causing existing behavior to change)
  • Documentation only
  • Refactor / internal cleanup

Test Plan

  • npx tsc --noEmit passes
  • npm run lint passes
  • npx vitest run passes after rebasing onto origin/main (bc800ef8): 371 files, 7493 passed, 1 skipped.
  • Added/updated tests for the change
    • mcp-reconcile.test.ts: with the built-in defaults, a project pull targets and writes .codex/config.toml, keeps the existing content, and removes only its own block once the server leaves mcp.yaml. Before the fix this failed with expected undefined to be '<root>/.codex/config.toml'.
    • doctor-mcp-delivery.test.ts adds 9 cases for the trust check:
      • fails with no entry
      • passes when the real path is trusted
      • fails when the entry is untrusted
      • in a linked worktree:
        • passes when the main checkout is trusted
        • a worktree entry without trust_level falls through to the main checkout
        • an untrusted worktree entry decides
      • reads the config under toolRoots.codex
      • reports an unparsable config
      • is not built while the file holds no team server
    • tool-roots.test.ts: the Codex entry now carries mcpProject, which stays on the project root under a relocated CODEX_HOME.
  • npm run test:e2e -- project-scoped-delivery: 5 passed (comment-only change there).

Real-CLI e2e (built dist/, codex-cli 0.159.3)

Recorded before the rebases onto bae48e5c and then bc800ef8. The only conflict in the second rebase was the ./types.js import in src/doctor-delivery.ts, where #945 added resolveToolBaseDir and scopedToolPaths; it was resolved by importing both sides. Otherwise git range-diff shows only context lines from main, and the only later change drops the skill note review asked to remove, so it was not re-run.

The sandbox was /tmp/tai954, with its own HOME, a local git team repo whose mcp/mcp.yaml has one stdio server team-docs, and a business repo biz plus a linked worktree biz-wt. CLAUDE_CONFIG_DIR and CODEX_HOME were unset, so Codex used $HOME/.codex. Trust was written by hand as a test fixture.

$ teamai init https://git.example.com/demo/team954.git --provider git --agent claude,codex --scope project --force
$ mkdir .claude .codex && teamai pull
ℹ MCP: 2 change(s) across 1 server(s). Restart your AI tool session to load them.
⚠ Pull finished, but 1 check(s) failed:
⚠   ✖ Codex trusts this project, so it loads its team MCP servers
    → /private/tmp/tai954/biz/.codex/config.toml holds team MCP servers (team-docs), but Codex loads a project's
      .codex/config.toml only in a trusted project, and /tmp/tai954/home/.codex/config.toml does not trust
      /private/tmp/tai954/biz. Open Codex in /private/tmp/tai954/biz and trust the project when it asks, or add a
      [projects."/private/tmp/tai954/biz"] table holding trust_level = "trusted" to /tmp/tai954/home/.codex/config.toml.
      Trusting the main checkout covers every worktree of it.

$ cat .codex/config.toml
[mcp_servers.team-docs]
command = "echo"
args = ["hi"]

$ teamai mcp list
  team-docs  [stdio]
    installed: claude, codex
  codex            /private/tmp/tai954/biz/.codex/config.toml

$ codex mcp list                      # untrusted
No MCP servers configured yet.

# fixture: [projects."/private/tmp/tai954/biz"] trust_level = "trusted" in $HOME/.codex/config.toml
$ codex mcp list
team-docs  echo     hi    -    -    enabled  Unsupported
$ teamai doctor
  ✔ MCP servers delivered to codex
  ✔ Codex trusts this project, so it loads its team MCP servers

# linked worktree, main checkout trusted only
$ cd ../biz-wt && teamai init … --scope project && teamai pull && codex mcp list
team-docs  echo     hi    -    -    enabled  Unsupported
$ teamai doctor
  ✔ MCP servers delivered to codex
  ✔ Codex trusts this project, so it loads its team MCP servers

# Codex trust semantics the check mirrors, observed with codex mcp list in biz-wt (main trusted):
#   [projects."<biz-wt>"] with no trust_level    → server listed (falls through)
#   [projects."<biz-wt>"] trust_level="untrusted" → nothing listed (worktree entry decides)

$ cd ../biz && teamai mcp remove team-docs
  removed  claude/team-docs
  removed  codex/team-docs
$ cat .codex/config.toml               # empty
$ codex mcp list
No MCP servers configured yet.

Related Issues

Fixes #954
Related: #955 (setting Codex project trust, which clears this check)

Notes for Reviewers

  • Door: two-way. Reverting removes the default and the check. Servers already written stay in .codex/config.toml until teamai mcp remove runs, or a pull on the reverted build cleans them up.
  • Blast radius: Codex project-scope members. A project pull now edits <project>/.codex/config.toml by text splice; content outside the team's blocks stays byte-identical. Every pull in an untrusted project now ends with a failing doctor check. That is deliberate: until the project is trusted the servers are inert, and [bug] Codex never runs teamai hooks: they need manual trust, and a pull invalidates it #955 is what clears the check automatically.
  • HTTP-backed teams: the local agent's install_mcp for codex in project scope now writes to the same file, where before it threw "has no MCP config path". Whether the trust check fires for those installs was not verified.
  • Skills unchanged: skill-data/ is left as is, per review. The doctor check prints the manual fix itself.
  • toolPaths overrides: a team whose teamai.yaml sets toolPaths replaces the defaults whole. Such a team must add mcpProject: .codex/config.toml itself; the docs note says so.
  • Bare-repository worktrees: the main-checkout key comes from git worktree list, and how it compares with Codex's repository-root key there is unverified.

@jeff-r2026 jeff-r2026 self-assigned this Oct 2, 2026
@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown

No findings.

The PR description documents sufficient testing, including a representative real-CLI end-to-end run for the runtime behavior change. I did not run tests or execute PR code, as requested.

@SaulMoro
SaulMoro force-pushed the fix/954-codex-project-mcp branch from cc5cd9d to 48c7740 Compare October 2, 2026 05:07
@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown

No findings.

The PR description documents sufficient testing, including a representative real-CLI end-to-end run for the runtime behavior change. I did not run, build, or execute PR code, as requested.

Comment thread skill-data/core/references/troubleshooting.md Outdated
@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown

No findings.

The PR description documents sufficient testing, including a representative real-CLI end-to-end run for the runtime behavior change. I did not run, build, install, or execute PR code, as requested.

@SaulMoro
SaulMoro requested a review from jeff-r2026 October 2, 2026 19:53
…ent#954)

Codex reads mcp_servers from <project>/.codex/config.toml once the project
is trusted. Tencent#252 left the codex entry without mcpProject on the assumption
that Codex has no project-scope MCP, so a project pull wrote nothing for it.
The reconcile, ownership and git-exclude paths already handle a Codex
project file; only the built-in mapping was missing.
…vers (Tencent#954)

Codex loads <project>/.codex/config.toml only in a trusted project and skips
an untrusted one without a word, so delivered team servers sit inert. Doctor
now reads the projects table of the Codex user config (honoring toolRoots),
takes the first entry for the checkout or its main checkout by real path, as
Codex does, and fails with the manual fix. Read-only: it never writes trust.
…able fixes (Tencent#954)

Review follow-up. An entry without trust_level decides nothing in Codex
(checked with codex mcp list: a bare worktree entry falls through to the
trusted main checkout), so the check skips it instead of reporting
trust_level = "undefined". The fix text names a [projects."<dir>"] table
rather than printing two TOML lines on one, drops the Codex-asks advice for
an entry already marked untrusted, and tells an unreadable config from an
unparsable one. Docs note that a pull reports the failure too.
…skill (Tencent#954)

Review asked to leave the skill unchanged. The doctor check already
prints the manual fix.
@SaulMoro
SaulMoro force-pushed the fix/954-codex-project-mcp branch from bd13c2a to 2526c14 Compare October 3, 2026 06:14
@github-actions

github-actions Bot commented Oct 3, 2026

Copy link
Copy Markdown

No findings.

The PR description documents sufficient testing, including a representative real-CLI end-to-end run for the runtime behavior change. Earlier reviews also reported no findings, and no previously raised issue remains to reassess. I did not run, build, install, or execute PR code, as requested.

@jeff-r2026
jeff-r2026 merged commit 40f6ecd into Tencent:main Oct 3, 2026
12 of 13 checks passed
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.

[bug] Codex gets no team MCP servers in project scope

2 participants