Skip to content

Refresh MCP headers before Codex Apps tool calls#15132

Open
ychhabria wants to merge 9 commits intomainfrom
ychhabria/pr15011-mcp-header-followups
Open

Refresh MCP headers before Codex Apps tool calls#15132
ychhabria wants to merge 9 commits intomainfrom
ychhabria/pr15011-mcp-header-followups

Conversation

@ychhabria
Copy link
Copy Markdown

@ychhabria ychhabria commented Mar 19, 2026

Summary

  • refresh Codex Apps MCP request headers again immediately before each tool call
  • keep the scope narrow so only Codex Apps tools/call requests pick up the refreshed headers
  • add unit and integration coverage for the active-turn refresh path and the real apps MCP HTTP flow

Problem

PR #15011 snapshots the Codex Apps MCP request headers at turn start.

That is usually fine for session_id and turn_id, but TurnMetadataState can enrich the x-codex-turn-metadata payload later in the same turn after async git/workspace inspection completes. When a tool call happens after that enrichment, the MCP tools/call request can still carry the old turn-start snapshot instead of the enriched metadata.

In practice, that means downstream MCP services can miss workspace/git context that became available after the turn started.

Example scenario

A realistic sequence looks like this:

  1. A turn starts inside a git repo.
  2. Codex snapshots the Codex Apps MCP headers immediately, so x-codex-turn-metadata initially contains only basic fields like turn_id and sandbox.
  3. In the background, async git/workspace inspection finishes and enriches the turn metadata with workspaces information.
  4. The model then decides to call a Codex Apps tool.
  5. Before this follow-up, the MCP tools/call request still used the stale step-2 header, so the tool call missed the workspace metadata discovered in step 3.

That exact sequence occurs in the integration test added here: the turn starts in a temp git repo, enrichment picks up workspace metadata, and the later Apps tool call is expected to forward it.

Fix

Refresh the Codex Apps MCP request headers again immediately before Session::call_tool(...) forwards the tools/call request.

This preserves the original behavior for which requests get headers, but makes the header contents current at tool-call time instead of freezing them at turn start.

Before / After proof

I verified this with the same realistic apps-flow integration scenario on both branches:

Before: untouched pr-15011

I ran the same runtime probe against the original PR branch in a clean worktree. The MCP tools/call request only carried:

{
  "sandbox": "seatbelt",
  "turn_id": "..."
}

workspaces was missing, so the later git/workspace enrichment did not make it into the tool-call header.

After: this follow-up branch

Running the same scenario on this branch passes, and the MCP tools/call request contains enriched workspace metadata in x-codex-turn-metadata.

Testing

Targeted local validation

  • cargo fmt --all --check --manifest-path /Users/ychhabria/repos/codex/codex-rs/Cargo.toml
  • cargo test -q -p codex-core --lib call_tool_refreshes_codex_apps_request_headers_from_active_turn --manifest-path /Users/ychhabria/repos/codex/codex-rs/Cargo.toml
  • cargo test -q -p codex-core --test all search_tool --manifest-path /Users/ychhabria/repos/codex/codex-rs/Cargo.toml
  • cargo test -q -p codex-core apps_mcp_tool_call_uses_enriched_turn_metadata_header --test all --manifest-path /Users/ychhabria/repos/codex/codex-rs/Cargo.toml

Before/after reproduction

  • Before: cargo test -q -p codex-core apps_mcp_tool_call_uses_enriched_turn_metadata_header --test all --manifest-path /Users/ychhabria/repos/codex-pr15011-base/codex-rs/Cargo.toml
    • failed on the untouched PR branch because workspaces was absent from the MCP tools/call header
  • After: same command against this branch
    • passed with enriched workspace metadata present

Notes

The current PR CI still shows unrelated failures:

  • cla: CLA signature requirement
  • build-test: missing/downloadable native artifacts from a referenced workflow

I did not find a code-level CI failure attributable to this MCP header refresh change.

nicholasclark-openai and others added 9 commits March 17, 2026 18:14
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Set Codex Apps MCP request headers once per active turn and clear them on turn end,
instead of threading request-scoped headers through every tool call. Keep RMCP
header injection limited to streamable HTTP tools/call requests so list/init
paths stay unchanged and concurrent tool calls on the same client are not
serialized.

Co-authored-by: Codex <noreply@openai.com>
Add the new request_headers test fixture state, update the streamable HTTP
recovery test to pass the new client constructor argument, and satisfy the
argument comment lint for clearing turn-scoped MCP request headers.

Co-authored-by: Codex <noreply@openai.com>
@github-actions
Copy link
Copy Markdown
Contributor


Thank you for your submission, we really appreciate it. Like many open-source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution. You can sign the CLA by just posting a Pull Request Comment same as the below format.


I have read the CLA Document and I hereby sign the CLA


You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot.

@ychhabria ychhabria marked this pull request as ready for review March 19, 2026 01:48
Base automatically changed from nicholasclark/tool-call-task-headers to main March 19, 2026 04:29
@etraut-openai etraut-openai added the oai PRs contributed by OpenAI employees label Mar 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

oai PRs contributed by OpenAI employees

3 participants