Codex MCP: How to Add MCP Servers to OpenAI Codex (CLI, App, IDE)

Updated 2026-10-15 · by Murilo Prataviera, maker of Aki

You want Codex to open your app in a real browser and check the fix it just made. You paste a Playwright snippet into ~/.codex/config.toml, start Codex, and get MCP client for `playwright` timed out after 10 seconds. Nothing in the file looks wrong. This guide shows how MCP works in Codex today: the commands, every config key that matters, OAuth login, how it differs from Claude Code, and the three or four problems that cause most failures.

Quick answer

  • Add a local server: codex mcp add <name> -- <command>. Example: codex mcp add context7 -- npx -y @upstash/context7-mcp.
  • Add a remote server: codex mcp add <name> --url https://…/mcp. Codex detects OAuth and opens the browser, or run codex mcp login <name>.

  • Config lives in ~/.codex/config.toml under [mcp_servers.<name>]. A project can have its own .codex/config.toml, read only when you trust the project.

  • One config for everything: the Codex CLI, the IDE extension and the desktop app share it.

  • Check it: codex mcp list in the shell, /mcp inside a session.

  • Slow server? Raise startup_timeout_sec (default 10 seconds).

  • codex mcp-server is gone. Codex can no longer run as an MCP server. The replacement is the app server, which uses its own protocol.

Add a server from the command line

codex mcp has six subcommands: add, list, get, remove, login and logout.

# Local (stdio) server: everything after -- is the command Codex runs
codex mcp add context7 -- npx -y @upstash/context7-mcp

# Pass environment variables to a stdio server
codex mcp add myserver --env API_KEY=abc123 -- npx -y some-mcp-package

# Remote (streamable HTTP) server
codex mcp add linear --url https://mcp.linear.app/mcp

# Remote server with a token read from an environment variable
codex mcp add github --url https://api.githubcopilot.com/mcp/ --bearer-token-env-var GITHUB_PAT_TOKEN

# See what's configured
codex mcp list            # add --json for machine-readable output
codex mcp get github      # one server's details
codex mcp remove github

--env works only with stdio servers. --bearer-token-env-var works only with HTTP servers. codex mcp add has no scope flag: it writes to your user config, ~/.codex/config.toml.

In the desktop app and the IDE extension

Both write to the same config file the CLI uses. ChatGPT on the web doesn't read it; it uses MCP through plugins instead.

The [mcp_servers] block in config.toml

Editing the file by hand gives you every option. Each server is a table named [mcp_servers.<name>].

Local (stdio) servers

[mcp_servers.context7]
command = "npx"                       # required
args = ["-y", "@upstash/context7-mcp"]
cwd = "/path/to/project"              # optional working directory
env_vars = ["CONTEXT7_API_KEY"]       # forward these from your environment

[mcp_servers.context7.env]
MY_ENV_VAR = "MY_ENV_VALUE"           # set fixed values

One detail catches people: Codex does not pass your whole environment to a stdio server. It passes a short default list (on macOS and Linux: HOME, LOGNAME, PATH, SHELL, USER, LANG, LC_ALL, TERM, TMPDIR, TZ and a couple more), plus whatever you set in env or list in env_vars. An API key you exported in your shell won't reach the server unless you name it.

Remote (streamable HTTP) servers

[mcp_servers.figma]
url = "https://mcp.figma.com/mcp"     # required
bearer_token_env_var = "FIGMA_OAUTH_TOKEN"
http_headers = { "X-Figma-Region" = "us-east-1" }
env_http_headers = { "X-Api-Key" = "MY_API_KEY_VAR" }   # header -> env var name

bearer_token_env_var sends Authorization: Bearer <value of that variable>. http_headers sends fixed values. env_http_headers reads header values from environment variables, so the secret never sits in the file.

Options for any server

[mcp_servers.chrome_devtools]
command = "npx"
args = ["chrome-devtools-mcp@latest"]
startup_timeout_sec = 20       # default 10
tool_timeout_sec = 45          # default 60, per tool call
enabled = true                 # false turns it off without deleting it
required = false               # true: Codex refuses to start if this server fails
enabled_tools = ["navigate_page", "take_screenshot"]   # allow list
disabled_tools = ["take_screenshot"]                   # deny list, applied after
default_tools_approval_mode = "prompt"                 # auto, prompt, writes or approve

[mcp_servers.chrome_devtools.tools.navigate_page]
approval_mode = "approve"
output_token_limit = 30000

startup_timeout_ms also exists as an alias of startup_timeout_sec, which is why vendor docs show either one. At the top level, mcp_optional_startup_grace_ms (default 1000) is how long Codex waits for optional servers while it builds the tool list. Set it to 0 to wait for each server's full timeout.

Per-project servers

Put the same [mcp_servers.<name>] blocks in .codex/config.toml at the project root. Codex reads it only for trusted projects. Use it for servers that only make sense in one repo, such as a database for that app.

OAuth: codex mcp login

Most hosted servers (Linear, Figma, Vercel, Notion, Sentry) use OAuth. When you add one with --url, Codex detects OAuth support and opens the browser. To log in again later, or for a server you added by hand:

codex mcp login linear
codex mcp login linear --scopes read,write     # request specific scopes
codex mcp login linear --no-browser            # print the URL instead (SSH, devbox)
codex mcp logout linear

For a provider that needs a pre-registered app, add --oauth-client-id (and --oauth-client-secret for a confidential client). Codex stores the secret in config.toml, so keep that file private. If the provider needs a fixed callback, set mcp_oauth_callback_port at the top level, or oauth.callback_port on one server. Where tokens are stored is controlled by mcp_oauth_credentials_store (auto, file or keyring).

Check it with /mcp

Inside a Codex session, type /mcp to list active servers and their tools. If a server is missing:

  1. Run codex mcp list to confirm the name and that it's enabled.
  2. Run the server's command yourself in a terminal. If it errors or downloads for a long time, that's your problem.
  3. Restart Codex. Sessions already open don't pick up new servers.

Can Codex itself be an MCP server?

Not anymore. OpenAI's docs say the codex mcp-server command and the standalone codex-mcp-server binary have been removed, along with the old Agents SDK examples built on them. The suggested path is the Codex app server, which speaks its own JSON-RPC protocol. It is not an MCP server, and OpenAI marks it experimental. Many older tutorials still show codex mcp-server; on a current Codex the command doesn't exist.

Claude Code still has the equivalent: claude mcp serve.

Codex vs Claude Code: MCP side by side

Codex Claude Code
Add a local server codex mcp add name -- cmd args claude mcp add name -- cmd args
Add a remote server codex mcp add name --url URL claude mcp add --transport http name URL
Config format TOML JSON
User-wide config ~/.codex/config.toml ~/.claude.json (--scope user)
Per-project config .codex/config.toml (trusted projects) .mcp.json in the repo (--scope project), approved on first use
Choose scope when adding No flag; edit the project file by hand --scope local, project or user
OAuth login codex mcp login <name> /mcp or claude mcp login <name>
Secrets in config env_vars, bearer_token_env_var, env_http_headers ${VAR} expansion in .mcp.json
Startup timeout startup_timeout_sec per server (default 10 s) MCP_TIMEOUT environment variable
Limit tools enabled_tools, disabled_tools, approval modes Permission rules
Run as an MCP server Removed claude mcp serve

Moving a server from one to the other is mostly a format change. A .mcp.json entry with command, args and env maps one to one onto a TOML table with the same keys.

Useful servers, with the Codex command

These are the commands the vendors publish for Codex. For what each server is good at and the Claude Code versions, see the best MCP servers for Claude Code and Codex.

Server Codex command Auth
Playwright codex mcp add playwright npx "@playwright/mcp@latest" None
Chrome DevTools codex mcp add chrome-devtools -- npx chrome-devtools-mcp@latest None
Context7 codex mcp add context7 -- npx -y @upstash/context7-mcp --api-key YOUR_API_KEY API key
GitHub codex mcp add github --url https://api.githubcopilot.com/mcp/ --bearer-token-env-var GITHUB_PAT_TOKEN Token
Figma codex mcp add figma --url https://mcp.figma.com/mcp OAuth
Linear codex mcp add linear --url https://mcp.linear.app/mcp OAuth
Vercel codex mcp add vercel --url https://mcp.vercel.com OAuth
Sentry codex mcp add sentry --url https://mcp.sentry.dev/mcp OAuth

Notes:

Common problems

"MCP client for … timed out after 10 seconds". The server took longer than startup_timeout_sec (10 seconds by default). Codex's own message tells you to raise that key. The usual cause is npx downloading the package on first run. Raise the timeout to 20–30 seconds, or install the package globally and call it directly.

Works in the terminal, fails in the app or IDE. Codex passes its own PATH to the server. On a Mac, an app opened from the Dock may not have the PATH your shell gets from .zshrc (nvm, Homebrew, ~/.local/bin). Use the full path from which npx as command.

The server starts but says the API key is missing. Codex didn't forward the variable. Add it to env_vars or set it under env.

Windows. Recent Codex versions find npx.cmd on their own. If a server still fails, Chrome DevTools MCP's docs suggest starting it through cmd, passing the system variables and raising the timeout:

[mcp_servers.chrome-devtools]
command = "cmd"
args = ["/c", "npx", "-y", "chrome-devtools-mcp@latest"]
env = { SystemRoot = "C:\\Windows", PROGRAMFILES = "C:\\Program Files" }
startup_timeout_ms = 20_000

Watch backslashes: in a double-quoted TOML string, "C:\Users" is invalid. Write "C:\\Users", 'C:\Users' or forward slashes. One bad escape breaks the whole file, not just that server.

OAuth login never finishes. You're probably on a remote machine. Use codex mcp login <name> --no-browser and open the URL locally, or set a fixed mcp_oauth_callback_port and forward it.

Where Aki fits

Aki is a free Mac app with a local MCP server that Codex can use. You press ⇧⌘A, point at something on screen (an element in Chrome, an area, a line in a terminal), write what should change, and send it. Codex reads those marks through MCP instead of a screenshot.

In Aki, Settings → Agents → Connect next to Codex runs this for you:

codex mcp add aki -- /Applications/Aki.app/Contents/MacOS/Aki mcp

That's the same as:

[mcp_servers.aki]
command = "/Applications/Aki.app/Contents/MacOS/Aki"
args = ["mcp"]

The server exposes read_annotations, wait_for_annotations, get_annotation_image (only when the request is visual), resolve_annotation and delete_annotation. Marks are filtered by the worktree Codex runs in. Everything stays on your Mac, and Aki's local server listens on 127.0.0.1 only. Sessions already open see the server after a restart.

Limits: Mac only (Apple Silicon, macOS 14+). Aki is free and source-available, with the code at >github.com/muriloprataviera/aki.

FAQ

How do I add an MCP server to Codex?

Run codex mcp add <name> -- <command> for a local server or codex mcp add <name> --url <url> for a remote one. You can also add a [mcp_servers.<name>] table to ~/.codex/config.toml, or use Settings → MCP servers in the Codex app.

Where is the Codex MCP config file?

In ~/.codex/config.toml. A project can add servers in its own .codex/config.toml, which Codex reads only for trusted projects. The CLI, the IDE extension and the desktop app share the same config.

How do I see which MCP servers Codex loaded?

Type /mcp inside a session, or run codex mcp list (or codex mcp get <name>) in the terminal.

How do I fix "MCP client timed out after 10 seconds" in Codex?

Raise startup_timeout_sec for that server (the default is 10 seconds), check that the command runs on its own in a terminal, and use the full path to npx if Codex can't find it.

Can I run Codex as an MCP server for Claude Code or the Agents SDK?

No. OpenAI removed codex mcp-server. The replacement is the experimental Codex app server, which uses its own JSON-RPC protocol rather than MCP.

Can I limit which tools a Codex MCP server exposes?

Yes. Use enabled_tools as an allow list and disabled_tools as a deny list. default_tools_approval_mode and tools.<tool>.approval_mode decide when Codex asks before calling a tool.

Sources