Agentic AI AcademyAgentic AI Academy

Codex as an MCP Server

Let other tools and agents call Codex

Advanced 11 minBuilder
What you'll be able to do
  • 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
At a glance

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.

  1. 1Flip the arrow: Codex as the server
  2. 2`codex mcp` vs `codex mcp-server` — don't confuse them
  3. 3The two tools Codex exposes: `codex` and `codex-reply`
  4. 4Configuring the session: the `codex` tool's parameters
  5. 5Continuing a session: `codex-reply` and the `threadId`
  6. 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 clientCodex as server
Commandcodex mcp add <name> …codex mcp-server
Who connects to whomCodex → external serverExternal client → Codex
Codex's roleCaller (uses others' tools)Callee (exposes its own tools)
Config lives in[mcp_servers] in config.tomlNone — it just runs and serves
Typical useGive Codex more capabilitiesLet 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 mcp is a command group for managing the servers Codex connects to as a client. Its subcommands are add, list, get, remove, login, and logout. These edit the [mcp_servers] tables in ~/.codex/config.toml.
  • codex mcp-server is a single top-level command — a sibling of codex 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-server as 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.
bash
# 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-server

You 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:

ToolPurposeRequired params
codexStart a new Codex sessionprompt
codex-replyContinue an existing sessionprompt, 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.

ParameterRequired?What it controls
promptYesThe initial user prompt that starts the conversation
approval-policyNoWHEN Codex pauses to ask: untrusted | on-request | never
sandboxNoWHERE Codex may act: read-only | workspace-write | danger-full-access
modelNoModel override for this session
cwdNoWorking directory; relative paths resolve against the server process
base-instructionsNoOverride Codex's default instructions for this session
configNoAn object of config settings that override $CODEX_HOME/config.toml
include-plan-toolNoWhether to include the plan tool
profileNoName 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-policy governs when Codex asks for confirmation.
  • sandbox governs 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.

jsonc
// 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.

text
  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.

jsonc
// 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 codex tool and stitches the results together.
  • The OpenAI Agents SDK can launch codex mcp-server as 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.)

bash
# 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. 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.
  2. 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.
  3. 3Codex-as-server exposes exactly two tools: `codex` to start a session (required `prompt`) and `codex-reply` to continue one (required `prompt` + `threadId`).
  4. 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`.
  5. 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).
  6. 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