Codex as an MCP Server
Let other tools and agents call Codex
- Distinguish Codex *as MCP client* (it consumes tools) from Codex *as MCP server* (other tools drive it), and place `codex mcp-server` correctly as a top-level sibling of `codex mcp`
- Run `codex mcp-server` and explain that it speaks JSON-RPC over stdio and exits when the client disconnects
- Name the two tools Codex exposes — `codex` and `codex-reply` — and recall their required and key optional parameters
- Use the `threadId` returned in `structuredContent.threadId` to continue a session across turns
- Embed Codex inside a larger multi-agent or SDK-driven system as a delegated coding sub-agent
- Explain why read-only MCP tools advertising `readOnlyHint` can run in parallel
Most lessons treat Codex as the agent that *calls* tools. This one flips the arrow: `codex mcp-server` runs Codex itself as an MCP server over stdio, so any MCP-aware client — another agent, an orchestrator, Claude Desktop, the OpenAI Agents SDK — can delegate a coding task to Codex as a tool. You'll learn the two tools it exposes (`codex` to start a session, `codex-reply` to continue one), the key parameters, and how the returned `threadId` lets a caller hold a stateful multi-turn conversation.
- 1Flip the arrow: Codex as the server
- 2`codex mcp` vs `codex mcp-server` — don't confuse them
- 3The two tools Codex exposes: `codex` and `codex-reply`
- 4Configuring the session: the `codex` tool's parameters
- 5Continuing a session: `codex-reply` and the `threadId`
- 6Why this exists: embedding Codex in larger systems
Flip the arrow: Codex as the server
Everywhere else in this module, Codex is the MCP client: you point it at a server with codex mcp add, and Codex calls that server's tools — Context7 for docs, Figma for designs, a database connector for SQL. The arrow points outward from Codex.
This lesson flips the arrow. With one command, Codex becomes an MCP server, and other software connects to it. Now the arrow points inward: a parent agent, an orchestrator script, Claude Desktop, Zed, or the OpenAI Agents SDK launches Codex and calls it as a tool to get coding work done.
Think of it like hiring. As a client, Codex is the manager hiring specialist contractors (the MCP servers). As a server, Codex is the contractor — a self-contained coding agent that some larger system hires to read a repo, make a change, run the tests, and report back. The whole point is delegation: you embed a full Codex agent inside a bigger system without re-implementing planning, editing, sandboxing, or approvals.
| Codex as client | Codex as server | |
|---|---|---|
| Command | codex mcp add <name> … | codex mcp-server |
| Who connects to whom | Codex → external server | External client → Codex |
| Codex's role | Caller (uses others' tools) | Callee (exposes its own tools) |
| Config lives in | [mcp_servers] in config.toml | None — it just runs and serves |
| Typical use | Give Codex more capabilities | Let another agent delegate coding to Codex |
Keep these two directions separate in your head. They use different commands and solve opposite problems, and the names are deliberately close enough to confuse you if you're not careful.
Key insight
One sentence to remember
As a client, Codex calls tools. As a server, Codex is the tool — a coding agent that other agents call to delegate work.
`codex mcp` vs `codex mcp-server` — don't confuse them
The single most common mistake here is conflating two commands whose names differ by one hyphenated word. They are not the same family.
codex mcpis a command group for managing the servers Codex connects to as a client. Its subcommands areadd,list,get,remove,login, andlogout. These edit the[mcp_servers]tables in~/.codex/config.toml.codex mcp-serveris a single top-level command — a sibling ofcodex mcp, not a subcommand of it. It runs Codex itself as a server.
From the CLI reference, codex mcp-server is described as:
Run Codex as an MCP server over stdio so that other tools can connect. This command inherits global configuration overrides and exits when the downstream client closes the connection.
Unpack that one sentence — every clause matters:
- "over stdio" — Codex speaks JSON-RPC over standard input/output. There is no port, no URL. The client launches
codex mcp-serveras a child process and talks to it through the process's stdin/stdout pipes. - "other tools can connect" — any MCP-aware client (an orchestrator, an SDK, a desktop app) can be that parent.
- "inherits global configuration overrides" — flags and config you'd pass to the CLI still apply to the server process.
- "exits when the downstream client closes the connection" — the server's lifecycle is bound to the client. You don't start and stop it yourself; the client owns it. Close the client, the server process dies.
# Manage servers Codex connects TO (client role)
codex mcp add context7 -- npx -y @upstash/context7-mcp
codex mcp list
# Run Codex itself AS a server (server role) — usually launched BY a client, not by hand
codex mcp-serverYou will rarely type codex mcp-server directly at a prompt — there's nothing to see, because it's waiting to speak JSON-RPC to a parent, not to a human. It's the command your client config points at.
Watch out
`mcp-server` is top-level, not a subcommand
It's codex mcp-server, a sibling of codex mcp — there is no codex mcp server subcommand. The hyphen is load-bearing. codex mcp manages outbound connections; codex mcp-server is the inbound one.
The two tools Codex exposes: `codex` and `codex-reply`
When Codex runs as a server, it advertises exactly two MCP tools to whatever client connects. That's the entire surface area — and it maps cleanly onto how a conversation works:
| Tool | Purpose | Required params |
|---|---|---|
codex | Start a new Codex session | prompt |
codex-reply | Continue an existing session | prompt, threadId |
That's it. You begin a turn-based, multi-turn coding session by calling codex once, then drive every subsequent turn with codex-reply. The first tool opens the conversation; the second keeps it going.
Under the hood, calling codex spawns a Codex session (via ThreadManager in codex-core), streams progress to the client as MCP notifications while the turn runs, and returns the final response when the turn completes. So the client both gets live updates and a clean final answer — exactly what an orchestrator needs to show progress and then act on the result.
The mental model is a phone call. codex dials — it opens the line and you say your first thing. codex-reply is every sentence after that on the same call. The thing that ties them together — the "line" you stay on — is the threadId, which we'll get to next.
Note
Two tools, not a dozen
Codex deliberately keeps its server surface tiny: start a session, continue a session. All the richness — planning, file edits, sandboxing, approvals, model choice — is configured through the codex tool's parameters, not through extra tools.
Configuring the session: the `codex` tool's parameters
The codex tool takes a single required parameter, prompt, plus a set of optional parameters that let the calling client configure the delegated session exactly as if it were launching the CLI itself.
| Parameter | Required? | What it controls |
|---|---|---|
prompt | Yes | The initial user prompt that starts the conversation |
approval-policy | No | WHEN Codex pauses to ask: untrusted | on-request | never |
sandbox | No | WHERE Codex may act: read-only | workspace-write | danger-full-access |
model | No | Model override for this session |
cwd | No | Working directory; relative paths resolve against the server process |
base-instructions | No | Override Codex's default instructions for this session |
config | No | An object of config settings that override $CODEX_HOME/config.toml |
include-plan-tool | No | Whether to include the plan tool |
profile | No | Name of a config profile to load |
Two of these deserve emphasis because they're the same two independent controls you've learned throughout Codex — and they remain independent here:
approval-policygoverns when Codex asks for confirmation.sandboxgoverns where Codex is allowed to act.
They are orthogonal. A parent agent delegating an automated, unattended task will typically pair a permissive approval policy with a tight sandbox — e.g. approval-policy: never with sandbox: read-only for a code-review delegation, so Codex can read and reason but cannot touch the filesystem and never blocks waiting on a human who isn't there.
// A client's MCP tool call to start a read-only review session
{
"tool": "codex",
"arguments": {
"prompt": "Review the diff on the current branch for security issues. Report findings only.",
"approval-policy": "never",
"sandbox": "read-only",
"cwd": "/repos/payments-api"
}
}Note the kebab-case parameter names (approval-policy, base-instructions, include-plan-tool). That's the MCP tool schema; it's distinct from the snake_case keys you'd write in config.toml.
Watch out
Volatile: model names and the default model
Don't hard-code a model string. The model parameter accepts whatever identifiers Codex currently supports, and the default Codex model changes frequently. Check the live list at developers.openai.com/codex/models rather than memorizing a name.
Tip
Approvals and sandbox are still independent
approval-policy (when it asks) and sandbox (where it can act) are separate knobs in the server interface, exactly as they are in the CLI. Set them deliberately — a permissive approval policy with a locked-down sandbox is the safe default for unattended delegation.
Continuing a session: `codex-reply` and the `threadId`
A single codex call runs one turn and returns. To have a conversation — ask a follow-up, request a fix, iterate — the client uses codex-reply, which takes two required parameters:
prompt— the next user message.threadId— the identifier of the session to continue.
Where does the threadId come from? When the initial codex call completes, the tool-call response includes it in structuredContent.threadId. The client reads it from there and passes it back on every codex-reply. That single string is what makes the session stateful: it tells Codex which conversation — with its accumulated context, files read, and plan — to resume.
client Codex (mcp-server)
│ call codex(prompt=…) │
│ ───────────────────────────────► │ starts session, runs turn
│ ◄─── notifications (progress) ── │ (streamed events)
│ ◄─── result + structuredContent │
│ .threadId = "abc123" │
│ │
│ call codex-reply( │
│ prompt=…, threadId="abc123") │
│ ───────────────────────────────► │ resumes SAME session
│ ◄─── result (+ same threadId) ── │The pattern is always the same: codex once to open, codex-reply N times to continue, threading the same threadId through each follow-up. Lose the threadId and you can't continue that session — calling codex again starts a fresh one with no memory of the first.
// Turn 2: continue the session from the previous response
{
"tool": "codex-reply",
"arguments": {
"prompt": "Now fix the highest-severity issue you found and run the tests.",
"threadId": "abc123" // pulled from the first call's structuredContent.threadId
}
}Tip
Where to read the thread ID
Always pull the value from structuredContent.threadId on the codex tool's response, then echo it back unchanged on every codex-reply. Don't try to construct or guess it.
Note
`conversationId` is a deprecated alias
Older integrations passed conversationId instead of threadId. It's kept only for backward compatibility — write new code against threadId.
Why this exists: embedding Codex in larger systems
The reason to run Codex as a server is delegation inside a bigger system. Any MCP-aware host can now treat a full Codex coding agent as just another tool in its toolbox:
- A multi-agent orchestrator routes tasks to specialists: a planning agent decomposes the work, then hands each coding sub-task to Codex via the
codextool and stitches the results together. - The OpenAI Agents SDK can launch
codex mcp-serveras a subprocess and call it as a tool, so an SDK-built agent gains real repo-editing, command-running, sandboxed coding ability for free — no need to rebuild planning, editing, or safety. - Desktop / editor clients (Claude Desktop, Zed) that speak MCP can wire Codex in as a connected tool.
This is also the conceptual bridge to the SDK and multi-agent material that follows: once you understand that Codex exposes a clean, two-tool MCP interface with a threadId for continuity, the SDK integration is just a more ergonomic wrapper over exactly this protocol.
One capability worth calling out because it affects throughput: read-only MCP tools that advertise the readOnlyHint capability are allowed to run in parallel. A tool flagged readOnlyHint promises it won't mutate state, so there's no correctness risk in firing several at once. For an orchestrator fanning out read-only lookups, that hint is what unlocks concurrency instead of forcing everything to serialize. (Note: this is a property of the MCP tool layer broadly — it's the same hint Codex honors when it's the client calling read-only tools.)
# What a client's MCP config points at to embed Codex as a tool
# (the client launches this subprocess and speaks JSON-RPC to it)
command = "codex"
args = ["mcp-server"]And remember codex mcp-server is distinct from codex app-server --stdio, a separate, richer app-server integration surface. For the "call Codex as a tool over MCP" use case in this lesson, codex mcp-server is the one you want.
Key insight
The bridge to the SDK
Codex-as-server is the protocol; the OpenAI Agents SDK is the ergonomic wrapper. Learn this two-tool interface and threadId here, and the SDK lesson becomes a thin layer on top of it.
Try it: Drive Codex as a server: start a session and continue it with `threadId`
Goal: see Codex serve as a delegated coding agent and chain a multi-turn session. 1) Confirm the command exists. Run codex mcp-server --help (and codex mcp --help) and note that mcp-server is a top-level command, not a subcommand of codex mcp. 2) Wire it into an MCP client. In any MCP-aware client you have (a custom script using an MCP SDK, the OpenAI Agents SDK, or a desktop client that supports MCP), register a server whose launch command is codex with args ["mcp-server"]. The client will spawn it and speak JSON-RPC over stdio. 3) Start a session. Call the codex tool with a real prompt against a small repo, e.g. prompt: "List the files in src/ and summarize what this project does.", plus approval-policy: never and sandbox: read-only so the unattended call neither blocks nor writes. 4) Capture the thread. In the tool-call response, find structuredContent.threadId and copy the value. 5) Continue the session. Call codex-reply with a follow-up prompt — e.g. "Now find the largest source file and explain its main function." — and the threadId from step 4. Confirm the second turn has context from the first (it should reference what it already learned). 6) Prove statefulness. Call codex again (a fresh session, new threadId) with the same follow-up and observe that it has no memory of the earlier turn. 7) Write three sentences: which call started vs. continued the session, where you read the threadId, and why pairing approval-policy: never with sandbox: read-only is the right default for unattended delegation. This builds the instinct the SDK and multi-agent lessons assume — that Codex is a two-tool MCP server you can embed and drive.
Key takeaways
- 1`codex mcp-server` runs Codex itself AS an MCP server over stdio (JSON-RPC); it's a top-level sibling of `codex mcp`, is usually launched by a client, and exits when that client disconnects.
- 2Don't confuse the two: `codex mcp` (add/list/get/remove/login/logout) manages servers Codex connects to as a client; `codex mcp-server` makes Codex the server other tools connect to.
- 3Codex-as-server exposes exactly two tools: `codex` to start a session (required `prompt`) and `codex-reply` to continue one (required `prompt` + `threadId`).
- 4The `codex` tool configures the delegated session via optional params — `approval-policy` (WHEN it asks) and `sandbox` (WHERE it can act) stay independent, plus `model`, `cwd`, `base-instructions`, `config`, `include-plan-tool`, and `profile`.
- 5The `threadId` returned in `structuredContent.threadId` is what makes a session stateful — echo it back on every `codex-reply` to continue the same conversation (`conversationId` is a deprecated alias).
- 6Running Codex as a server lets multi-agent orchestrators and the OpenAI Agents SDK delegate coding to it; read-only tools advertising `readOnlyHint` can run in parallel.
Quiz
Lock in what you learned
Check your understanding
0 / 4 answered
1.Your colleague runs `codex mcp add figma --url https://mcp.figma.com/mcp` and says 'now Codex is running as an MCP server.' What's wrong with that statement?
2.A parent orchestrator calls the `codex` tool, gets a result, and now wants Codex to make a follow-up change in the SAME session. What must it do?
3.You want to delegate an UNATTENDED code review to Codex via the `codex` tool: it should read and reason but never modify files and never block waiting on a human. Which parameter combination fits?
4.Which statement about `codex mcp-server` is correct?
Go deeper
Hand-picked sources to keep learning
Authoritative source for the `codex mcp-server` command and the `codex mcp` add/list/get/remove/login/logout subcommands and flags.
Documents Codex as an MCP server and the `codex` / `codex-reply` tool schemas — the primary source for the two tools' parameters.
The client side: `codex mcp add`, stdio vs streamable-HTTP transports, the `/mcp` TUI command, and TOML examples.
Full `[mcp_servers]` config keys, tool gating, timeouts, and the global MCP OAuth options.
The Rust Codex CLI source, including the codex-mcp-server crate and codex-core ThreadManager.
Verify volatile facts: current CLI version, the rmcp client library, parallel readOnly tool support, and per-server env targeting.