Expose current thread ID to local stdio MCP servers

Resolved 💬 3 comments Opened Apr 28, 2026 by lilhammerfun Closed Jul 1, 2026
💡 Likely answer: A maintainer (etraut-openai, contributor) responded on this thread — see the highlighted reply below.

What feature would you like to see?

Expose the current Codex thread/session identity to local stdio MCP servers.

Today CODEX_THREAD_ID is available to shell/tool executions, but it does
not appear to be available to stdio MCP server startup. This makes it hard for
MCP servers to correlate their tool calls with the active Codex thread.

Concretely, please support one of these:

  1. Inject CODEX_THREAD_ID into local stdio MCP server processes, the same way

it is injected into shell tool executions.

  1. Add a supported dynamic MCP env source, for example:

``toml
[mcp_servers.my_server]
command = "my-server"
args = ["mcp", "serve"]
env_vars = [{ name = "CODEX_THREAD_ID", source = "thread" }]
``

  1. Expose equivalent thread/session metadata to MCP servers through another

stable mechanism.

Current behavior

Codex CLI 0.125.0 exposes CODEX_THREAD_ID in shell tool executions. For
example, inside a shell tool:

env | grep CODEX_THREAD_ID
# CODEX_THREAD_ID=019dba93-8214-7d50-a089-9690b4ce6b9e

However, a local stdio MCP server configured with:

[mcp_servers.clumsies]
command = "clumsies"
args = ["mcp", "serve"]
env_vars = ["CODEX_THREAD_ID"]

does not receive CODEX_THREAD_ID during MCP startup. The MCP server exits
when it requires this env var, and Codex reports the server as enabled but with
no tools:

/mcp

• clumsies
  • Status: enabled
  • Command: clumsies mcp serve
  • Env: CODEX_THREAD_ID=*****
  • Tools: (none)

Codex logs show the MCP process did not receive the env var:

MCP server stderr (clumsies): Error: clumsies MCP server requires a host CLI session id.

codex mcp get clumsies --json shows the config was parsed as:

{
  "transport": {
    "type": "stdio",
    "command": "clumsies",
    "args": ["mcp", "serve"],
    "env": null,
    "env_vars": ["CODEX_THREAD_ID"]
  }
}

This suggests env_vars inherits from the MCP launcher process environment,
not from the active Codex thread context.

Additional local checks

I tested whether env_vars supports a thread-context source:

codex mcp get clumsies \
  -c 'mcp_servers.clumsies.env_vars=[{name="CODEX_THREAD_ID",source="thread_id"}]' \
  --json

Codex rejects it:

unsupported env_vars source `thread_id`; expected `local` or `remote`

source = "local" parses, but appears to mean the MCP launcher local process
environment. source = "remote" parses too, but the binary contains a message
indicating it requires remote MCP stdio.

Why this matters

MCP servers that record audit logs, per-thread state, rule attestations, or
tool-call provenance need to associate MCP tool calls with the active Codex
thread. Without a stable Codex-provided thread/session id at MCP startup or
tool-call time, these servers must either:

  • invent their own session ids, which cannot be correlated with Codex hooks or

shell executions;

  • rely on workspace-global marker files, which break with concurrent sessions;
  • ask the model to pass session ids manually, which is brittle and

protocol-polluting;

  • or fail MCP startup, which leaves Codex showing Tools: (none).

This is especially visible for MCP servers that also integrate with Codex hooks:
hooks can see the current session/thread identity, while the MCP server cannot,
so hook events and MCP tool events cannot be reliably joined.

Expected behavior

There should be a supported way for local stdio MCP servers to receive the same
active Codex thread/session identity that shell tool executions receive.

Environment

  • Codex CLI: codex-cli 0.125.0
  • Platform: macOS arm64
  • MCP transport: local stdio

Related issues

  • #8923 requested programmatic session id exposure.
  • #14097 asks for stable per-agent metadata on tool/subprocess invocation.
  • #4180 shows MCP server subprocess environments can differ from normal shell

environments.

  • #4222 mentions CODEX_WORKSPACE_ROOT being injected at tool-call time, which

looks similar to the observed CODEX_THREAD_ID behavior.

View original on GitHub ↗

3 Comments

pandego · 4 months ago

I think option 1 would help, but I would be careful about making process env the only contract here.

If the stdio MCP server is long-lived, CODEX_THREAD_ID at startup can go stale as soon as the same server process is reused after a thread switch, session resume, or any future multiplexing. So startup env solves "server can boot" but not necessarily "each tool call is attributable to the correct Codex thread".

A sturdier shape would be:

  • allow startup env injection for one-thread-per-process servers, and
  • also expose thread/session identity per invocation through a stable MCP-side channel

Even a dynamic env source evaluated at call time, or request metadata attached at the MCP call boundary, would avoid freezing the first seen thread id into the server process.

Given the behavior in the report, my guess is env_vars is resolved when the stdio transport is launched, while CODEX_THREAD_ID is materialized later in the per-tool execution context. If that split is roughly right, this probably needs a fix at the MCP launcher or call boundary rather than only in config parsing.

lilhammerfun · 4 months ago
If the stdio MCP server is long-lived, CODEX_THREAD_ID at startup can go stale as soon as the same server process is reused after a thread switch, session resume, or any future multiplexing. So startup env solves "server can boot" but not necessarily "each tool call is attributable to the correct Codex thread".

That makes sense, and I agree per-call identity is the most robust shape if stdio servers can be reused across logical Codex threads.
The part I am still trying to reason through is the lifecycle premise for local stdio MCP servers. Since a stdio MCP server is launched as a child process of Codex, is there any current or plausible future architecture where that child process can outlive the Codex parent process, or be reused across unrelated Codex sessions/threads?
If such reuse is possible or planned, then startup env is clearly not enough and call-boundary metadata is the right abstraction. If local stdio servers remain scoped to a Codex process/session, startup env seems like a simpler practical contract, with per-call metadata as a future extension rather than the minimum fix.

etraut-openai contributor · 1 month ago

This feature request hasn't received enough upvotes, so it is being closed automatically. If you still feel this feature is needed, please open a new feature request with an updated title and description.