Skip to content
MCP Shelf

Set up your app

Adding MCP servers to Codex

By Sophie Filer · Updated 1 Nov 2026

Codex keeps MCP servers in config.toml, written in TOML rather than the JSON most READMEs show. The Codex CLI, the IDE extension and the ChatGPT desktop app share that file, so you set a server up once. Here is how to add one, and how to translate any JSON config.

The short version

Local server
codex mcp add playwright -- npx -y @playwright/mcp@latest
Local server with an API key
codex mcp add firecrawl --env FIRECRAWL_API_KEY=fc-your-key -- npx -y firecrawl-mcp
Remote server
codex mcp add notion --url https://mcp.notion.com/mcp
See what is set up
codex mcp list

Everything after -- is the command that starts the server. Inside the Codex terminal UI, type /mcp to see which servers are running. Every server page on MCP Shelf has a Codex tab with the config.toml block and the command.

Where the config lives

FileApplies to
~/.codex/config.tomlYou, everywhere: the CLI, the IDE extension and the ChatGPT desktop app
.codex/config.toml (in a project)That project, once you have marked it as trusted

In the IDE extension and the ChatGPT desktop app you can also add servers without the file: open Settings (the gear menu in the extension), choose MCP servers, then Add server, and pick STDIO or Streamable HTTP. Restart when it asks.

Turning a JSON config into TOML

Each server becomes a table named [mcp_servers.NAME]. The fields keep their names, and the env object becomes its own table underneath:

What the README shows (JSON)
{
  "mcpServers": {
    "firecrawl": {
      "command": "npx",
      "args": ["-y", "firecrawl-mcp"],
      "env": { "FIRECRAWL_API_KEY": "fc-your-key" }
    }
  }
}
The same server in ~/.codex/config.toml
[mcp_servers.firecrawl]
command = "npx"
args = ["-y", "firecrawl-mcp"]

[mcp_servers.firecrawl.env]
FIRECRAWL_API_KEY = "fc-your-key"
JSONconfig.toml
"mcpServers": { "name": { ... } }[mcp_servers.name]
"command": "npx"command = "npx"
"args": ["-y", "pkg"]args = ["-y", "pkg"]
"env": { "KEY": "value" }[mcp_servers.name.env] then KEY = "value"
"url": "https://..."url = "https://..."
"headers": { "X-Key": "..." }http_headers = { "X-Key" = "..." }

Keeping keys out of config.toml

Instead of writing the key into the file, Codex can pass on a variable that is already set in the environment you start it from:

[mcp_servers.firecrawl]
command = "npx"
args = ["-y", "firecrawl-mcp"]
env_vars = ["FIRECRAWL_API_KEY"]

[mcp_servers.github]
url = "https://api.githubcopilot.com/mcp/"
bearer_token_env_var = "GITHUB_PAT"

env_vars forwards the named variables to a local server. bearer_token_env_var sends a variable as Authorization: Bearer ... to a remote one; the command-line version is codex mcp add github --url https://api.githubcopilot.com/mcp/ --bearer-token-env-var GITHUB_PAT. env_http_headers does the same for other header names.

Signing in to remote servers

After adding a URL, Codex may say the server could need a login. Run codex mcp login notion to open the browser, or add --no-browser on a machine without one, which prints the address to open elsewhere. codex mcp logout notion removes the saved sign-in. In the app and extension, the server list shows an Authenticate button instead.

Options that save you trouble

OptionWhat it does
startup_timeout_sec = 60How long Codex waits for the server to start. The default is 10 seconds, which a first npx or uvx download can miss.
tool_timeout_sec = 120How long one tool call may run. The default is 60.
enabled = falseSwitch a server off without deleting it.
enabled_tools = ["read", "search"]Only offer these tools to the model.
disabled_tools = ["delete_page"]Hide these tools, applied after enabled_tools.
default_tools_approval_mode = "writes"Ask before tools that are not marked read-only. Other values: auto, prompt, approve.
A careful database setup
[mcp_servers.postgres]
command = "docker"
args = ["run", "-i", "--rm", "-e", "DATABASE_URI", "crystaldba/postgres-mcp", "--access-mode=restricted"]
env_vars = ["DATABASE_URI"]
startup_timeout_sec = 60
default_tools_approval_mode = "prompt"

That example starts Postgres MCP Pro in Docker, in its read-only restricted mode, takes the connection string from your environment and asks before every call. See its page for the full setup.

Questions

Does ChatGPT on the web use my Codex servers?

No. ChatGPT on the web does not read config.toml; it uses remote servers added as plugins. The ChatGPT desktop app, the Codex CLI and the IDE extension share config.toml. See Using MCP servers in ChatGPT.

Codex says the server timed out on start-up. What do I change?

Add startup_timeout_sec = 60 under the server in config.toml. The first run of an npx or uvx server downloads the package, which often takes longer than the 10-second default.

Can I edit config.toml by hand and use codex mcp add as well?

Yes. codex mcp add writes the same tables you would write yourself, and codex mcp list reads them back, which is a quick way to check your TOML parses.

For bots & AI agents

Machine-readable versions of this guide and MCP Shelf. Fetch these instead of parsing this page.

This guide (.md)llms.txtllms-full.txtai.txtFull catalog (.md)API specMCP serverMCP manifestDeveloper docs