Skip to main content
← Back to Articles
mcpcodexopenaiclisetup2026config.toml

OpenAI Codex CLI MCP Server Setup 2026: config.toml Guide

Configure MCP servers in OpenAI Codex CLI: the ~/.codex/config.toml schema for stdio and Streamable HTTP servers, the codex mcp add command, env_vars forwarding, tool approval modes, and why a Cursor or Claude mcp.json block won't paste in as-is.

By Web MCP Guide•September 13, 2026•12 min read

How do you set up an MCP server in OpenAI Codex CLI? Add a [mcp_servers.<name>] table to ~/.codex/config.toml, or skip hand-editing TOML entirely and run codex mcp add <name> --env VAR=VALUE -- <command> from a terminal. Local servers need a command; remote Streamable HTTP servers need a url and, if the endpoint requires one, a bearer_token_env_var. Codex reads the file on startup — no reload command, just start a new session.

Codex CLI is OpenAI's terminal coding agent, and its MCP configuration is neither Cursor's mcp.json nor Claude Desktop's claude_desktop_config.json. It's TOML, the top-level table is mcp_servers (snake_case, not mcpServers), and several field names — env_vars, bearer_token_env_var, startup_timeout_sec — don't exist under those names anywhere else. A config block copied from another client's docs will not paste in and work; the shape is genuinely different, not just a different file extension.

Quick reference

Config file~/.codex/config.toml (global), or .codex/config.toml for a trusted project
Top-level tablemcp_servers, not mcpServers
FormatTOML, not JSON
CLI helpercodex mcp add, codex mcp list, codex mcp login
Local server required fieldcommand
Remote server required fieldurl
Default startup timeout10 seconds (startup_timeout_sec)
Default tool timeout60 seconds (tool_timeout_sec)
Shared withChatGPT desktop app and the Codex IDE extension, for the same Codex host

Prerequisites


  • Codex CLI installed and authenticated (codex login or an API key, depending on how your account is set up).

  • Node.js, Python, uvx, or whatever runtime the MCP server you're adding needs, if it's a local stdio server.

  • For a remote server: its URL, and an OAuth flow or a bearer token depending on what it documents.

  • Comfort editing TOML directly, or just use codex mcp add and let Codex write the file for you.
  • Step 1: Add a server the fast way — codex mcp add

    The command-line path avoids TOML syntax entirely for a first server:

    codex mcp add context7 --env LOCAL_TOKEN=your_token -- npx -y @upstash/context7-mcp
    

    Everything after the bare -- is the stdio command and its arguments, exactly as you'd type it in a terminal. Flags before the -- (like --env) configure the entry itself. Run codex mcp list afterward to confirm it registered, and codex mcp login <server-name> if the server needs an OAuth handshake rather than a static token.

    Step 2: Or edit config.toml directly

    For a reviewable, version-controllable config, edit ~/.codex/config.toml (global) or .codex/config.toml in a project root — Codex only loads the project file for projects it already trusts, so a stray config.toml dropped into an untrusted repo won't silently start executing commands.

    Local (stdio) server

    [mcp_servers.context7]
    command = "npx"
    args = ["-y", "@upstash/context7-mcp"]
    env_vars = ["LOCAL_TOKEN"]
    startup_timeout_sec = 10
    tool_timeout_sec = 60
    enabled = true
    

    command is the only required field. args is the argument list, same as any subprocess invocation. env_vars is a list of names Codex forwards from its own environment into the child process — it's not a place to put literal values. For a literal, static value instead of forwarding from your shell, use env with an inline table:

    [mcp_servers.local-db]
    command = "uvx"
    args = ["mcp-server-sqlite", "--db-path", "/path/to/database.db"]
    env = { DB_READ_ONLY = "true" }
    

    env_vars also accepts a mixed form when a variable needs to come from somewhere other than your local shell:

    env_vars = ["LOCAL_TOKEN", { name = "REMOTE_TOKEN", source = "remote" }]
    

    source = "remote" only resolves if you're running Codex against a remote executor; for a normal local CLI session, plain string names sourced from your local environment are what you want.

    Remote (Streamable HTTP) server

    [mcp_servers.figma]
    url = "https://mcp.figma.com/mcp"
    bearer_token_env_var = "FIGMA_OAUTH_TOKEN"
    auth = "oauth"
    

    url is required. bearer_token_env_var names an environment variable holding a bearer token — Codex reads the variable at connect time, so the token itself never needs to sit in config.toml. auth defaults to "oauth"; set it to "chatgpt" only for first-party OpenAI-hosted servers that expect that flow specifically. For a server that expects static custom headers instead of a bearer token, use http_headers for literal values or env_http_headers to source header values from the environment the same way env_vars does for stdio servers.

    Step 3: Control which tools Codex can call, and how

    Two more tables scope what a connected server is actually allowed to do:

    [mcp_servers.figma]
    url = "https://mcp.figma.com/mcp"
    bearer_token_env_var = "FIGMA_OAUTH_TOKEN"
    enabled_tools = ["get_file", "get_image"]
    disabled_tools = []
    default_tools_approval_mode = "prompt"
    
    [mcp_servers.figma.tools.get_file]
    approval_mode = "auto"
    output_token_limit = 4000
    

    enabled_tools is an allowlist — if set, only those tool names are exposed at all. disabled_tools is a denylist applied after the allowlist, so it can only narrow further, never widen. default_tools_approval_mode takes "auto", "prompt", "writes", or "approve", and a per-tool tools.<name>.approval_mode table overrides that default for one specific tool — useful for marking a single read-only tool as auto while leaving everything else on prompt. output_token_limit caps how much of a tool's response gets pulled into context, which matters for tools that can return large payloads (a full file listing, a large search result) that would otherwise blow through your context budget on a single call.

    Step 4: Startup behavior and failure handling

    By default, a server that's slow to start doesn't block Codex from starting a session — there's a top-level mcp_optional_startup_grace_ms setting (default 1000ms) that controls how long Codex waits on optional servers before moving on without them. If a given server is load-bearing for your workflow and you'd rather Codex fail loudly than start without it, set required = true on that server's table so a failed startup stops the session instead of silently dropping the server.

    Practical prompts once a server is connected

    Read-only lookup through a remote server:

    Use the figma server to pull the component spec for the button in file ABC123 and match its padding values in our Tailwind config.
    

    Local database inspection before a migration:

    Look at the schema through the local-db server, then write a migration that adds a nullable last_login_at column.
    

    Confirming a server actually registered before relying on it in a longer task:

    codex mcp list
    

    Run this after any config edit or codex mcp add call — a typo in a table name ([mcp_server.foo] instead of [mcp_servers.foo]) fails silently from Codex's perspective; the server just never shows up, with no parse error surfaced in the session itself.

    Troubleshooting

    A server added via codex mcp add doesn't show up in config.toml where you expect it. Confirm you're looking at the right file — global ~/.codex/config.toml versus a project-scoped .codex/config.toml. codex mcp add writes to whichever scope you're running it in; run it from inside the project directory if you meant to scope it there.

    Remote server never connects. Check bearer_token_env_var actually points at a variable that's set in the shell Codex is running in — Codex reads the name from config.toml and resolves the value at connect time, so a renamed or unset environment variable fails at connection, not at config-parse time. If the server expects OAuth instead of a static token, run codex mcp login <server-name> rather than trying to hand-carry a bearer token.

    Local server exits immediately. Run the exact command plus args combination directly in a terminal, outside Codex. If it fails there too, the problem is the server itself — missing dependency, wrong path, a required env var that isn't in env or forwarded via env_vars — not the Codex config wrapping it.

    A JSON config from Cursor or Claude Desktop "doesn't work." It won't, by design. Codex's config is TOML with a mcp_servers table (snake_case); Cursor and Claude Desktop use JSON with a mcpServers key (camelCase). Field names also diverge beyond the top-level key — Codex's env_vars forwards named variables, while Cursor's env block holds literal key-value pairs directly. Translate field by field rather than pasting a JSON block into a TOML file.

    Tool calls keep prompting for approval even though you set default_tools_approval_mode = "auto". A per-tool override under [mcp_servers.<name>.tools.<tool>] takes precedence over the server-level default. Check whether that specific tool has its own approval_mode set to something stricter than the default you configured.

    A tool call's output looks truncated. Check output_token_limit on that tool. It's there to protect your context budget from a single call returning an enormous payload, but a limit set too low will cut off legitimate output — raise it for tools you know return large, useful responses.

    Frequently Asked Questions

    Does Codex CLI use the same config format as Cursor or Claude Desktop? No. Codex uses TOML at ~/.codex/config.toml with a mcp_servers table (snake_case). Cursor and Claude Desktop use JSON with a mcpServers key. The concepts overlap — local stdio servers need a command, remote servers need a URL — but the field names and file format are different enough that a config block has to be rewritten, not copy-pasted, between them.

    What's the fastest way to add a server without learning TOML syntax? codex mcp add <name> --env VAR=VALUE -- <command> <args>. Codex writes the config.toml entry for you. Use codex mcp list to confirm it registered and codex mcp login <name> if the server needs OAuth instead of an env-based token.

    Can I scope an MCP server to just one project instead of every Codex session? Yes — put its table in .codex/config.toml in the project root instead of the global ~/.codex/config.toml. Codex only loads project-scoped config for projects it already trusts, which is a deliberate guard against an untrusted repo silently adding a server that runs arbitrary commands.

    How do I stop Codex from asking for approval on every single tool call from a server I trust? Set default_tools_approval_mode = "auto" on that server's table, or scope it tighter with a per-tool [mcp_servers.<name>.tools.<tool>] approval_mode = "auto" override so only specific read-only tools skip the prompt while writes still ask.

    Do the ChatGPT desktop app and Codex CLI share MCP servers automatically? They share configuration for the same Codex host — connecting a server through one surface makes it available across the ChatGPT desktop app, Codex CLI, and the IDE extension without reconfiguring each one separately, according to OpenAI's documentation.

    What happens if an MCP server is slow or fails to start? By default Codex waits up to mcp_optional_startup_grace_ms (1000ms) and then continues the session without that server rather than blocking. Set required = true on a specific server's table if you'd rather the session fail outright than silently start without a server your workflow depends on.

    Related guides


  • Cline MCP Server Setup (2026)

  • Claude Code MCP Server Setup (2026)

  • Gemini CLI MCP Server Setup (2026)

  • Amazon Q Developer CLI MCP Server Setup 2026 — another terminal-based AI CLI, with q mcp add and a global/workspace mcp.json pair instead of Codex's TOML config

  • Cursor IDE MCP Setup: Complete Guide

  • How to Authenticate MCP Servers: OAuth and API Keys

  • MCP Security Best Practices

  • Local vs Remote MCP Servers

  • Debug MCP Server Issues
  • Official docs cited


  • Model Context Protocol — Codex (OpenAI)

  • Related guides