Codex MCP server: add stdio and HTTP tools

· · 8 min read

A Codex MCP server can start as a local process over stdio or answer at a Streamable HTTP URL. The command differs, but both end up in Codex’s MCP config. I checked these steps against the OpenAI docs and Codex CLI 0.160.0 on October 4, 2026.

The shortest Codex CLI MCP route is codex mcp add, then codex mcp list. Listing confirms that Codex saved and enabled the entry; it does not prove the server started or completed an MCP handshake.

How do you add a Codex MCP server over stdio?

Use -- before the executable and its arguments. Codex starts that command as a child process when it connects to the server. OpenAI’s MCP setup docs show this form:

codex mcp add context7 -- npx -y @upstash/context7-mcp

Pass server-specific environment values before -- with --env:

codex mcp add local-tools --env API_KEY=replace-me -- python3 /path/to/server.py

The command above is a template: replace the key and path with values the server actually requires. Don’t put a secret in a public shell transcript. For a server command with a space in its path, quote the executable path as one shell argument.

I tested the add and list flow locally without launching an external server. In an isolated CODEX_HOME, codex mcp add local-example -- python3 -c 'import sys; sys.stdin.read()' returned Added global MCP server 'local-example'. The follow-up list showed its command, arguments, and enabled status. This confirms config parsing only, not a usable MCP process.

How do you add a Streamable HTTP server?

Give Codex the endpoint with --url. The local help for Codex CLI 0.160.0 identifies --url as the Streamable HTTP form; OpenAI’s MCP docs document the URL and optional auth fields.

codex mcp add my-http-server --url https://example.com/mcp

If the server requires a bearer token, provide the name of an environment variable holding it. The flag accepts a variable name, not the token itself:

codex mcp add my-http-server \
  --url https://example.com/mcp \
  --bearer-token-env-var MY_MCP_TOKEN

For OAuth servers, use codex mcp login my-http-server after adding the URL. If the authorization server needs a pre-registered client, the current docs include --oauth-client-id. To send a resource indicator during login, add the server with --oauth-resource <RESOURCE>; Codex CLI 0.160.0 lists that flag under codex mcp add --help, not under codex mcp login.

I also added http://localhost:3434/mcp as octoweb in the throwaway config. Codex accepted it and codex mcp list showed the URL and enabled; auth was Unknown. This was a config test only. Octoweb’s browser MCP server runs at that local URL when Octoweb is running, so the useful live check is to connect while the browser is open. The MCP post shows what it exposes.

Which Codex config.toml keys matter for MCP?

The CLI writes to ~/.codex/config.toml by default. According to the current Codex MCP docs, one file configures Codex in the terminal, in your editor's extension and in the ChatGPT desktop app; project-scoped .codex/config.toml files apply only to trusted projects. These are the MCP keys documented as of October 2026.

Key What it does Example Since / notes
command Starts an stdio server. command = "npx" Required for stdio.
args Arguments passed to command. args = ["-y", "@upstash/context7-mcp"] Optional for stdio.
env Sets environment values for the server process. [mcp_servers.demo.env] then API_KEY = "…" Optional; use the CLI’s --env KEY=VALUE when adding.
env_vars Allows and forwards named variables from the local or remote environment. env_vars = ["LOCAL_TOKEN"] Optional; distinct from setting a literal in env.
cwd Sets the process working directory. cwd = "/path/to/project" Optional for stdio.
url Gives a Streamable HTTP server address. url = "https://example.com/mcp" Required for HTTP.
bearer_token_env_var Reads a bearer token from a named environment variable for Authorization. bearer_token_env_var = "MY_MCP_TOKEN" Optional for HTTP.
http_headers Sets literal HTTP headers. http_headers = { "X-Region" = "us-east-1" } Optional; literal values live in TOML.
env_http_headers Reads header values from named environment variables. [mcp_servers.demo.env_http_headers] then X-Key = "MY_KEY_ENV" Optional; the TOML value is the variable name.
startup_timeout_sec Limits time for server startup. startup_timeout_sec = 20 Optional; documented default is 10 seconds.
tool_timeout_sec Limits time for a tool call. tool_timeout_sec = 45 Optional; documented default is 60 seconds.
enabled Turns a server on or off without deleting it. enabled = false Optional; disabled servers are not removed.
enabled_tools Allows only named tools. enabled_tools = ["read", "search"] Optional allow list.
disabled_tools Blocks named tools after the allow list is applied. disabled_tools = ["delete"] Optional deny list; applied after enabled_tools.
[mcp_servers.docs]
url = "https://example.com/mcp"
bearer_token_env_var = "DOCS_MCP_TOKEN"
startup_timeout_sec = 20
tool_timeout_sec = 45
enabled = true
enabled_tools = ["search", "read"]
disabled_tools = ["delete"]

The docs also define auth, required, default_tools_approval_mode, per-tool approval_mode and output_token_limit, and http_headers_helper. Add them only when you need those behaviors; the official MCP config reference documents each one. For a custom header, codex mcp add does not currently expose a general --header flag, so place http_headers or env_http_headers in TOML. The openai/codex header discussion gives an env_http_headers example and calls it safer than http_headers.

How do you check or remove an MCP server in Codex?

Run codex mcp list to inspect entries and status. Use codex mcp get <name> for one entry, and codex mcp remove <name> to remove it. get and remove are in the local Codex 0.160.0 help output; OpenAI’s MCP docs document list.

codex mcp list
codex mcp get my-http-server
codex mcp remove my-http-server

My local list showed the stdio server under a command table and the HTTP server under a URL table. Both were enabled. Auth: Unknown on the local HTTP entry means the list command did not establish whether an authentication step is needed. Open Codex or use its MCP status view to check the running connection and available tools.

What fixes common Codex MCP errors?

Start with the exact failure and server type. Don’t raise timeouts to hide a command that never launches.

Symptom Check Fix
timed out after 30 seconds during startup Does the server need more startup time than Codex allows? Set startup_timeout_sec to a measured startup time plus headroom. A 2026 GitNexus issue shows repeated 30-second timeouts on codex-cli 0.153.4 with no startup_timeout_sec set, while Codex’s docs give a 10-second default, so measure instead of trusting the default. Investigate repeated starts too; a larger timeout won’t correct a broken process.
command not found, ENOENT, or an stdio process that exits immediately Is the executable installed and visible to Codex’s child process? Can it run from the chosen cwd? Try the command directly in the same shell, use an absolute executable path, and check the environment variables the server needs. A 2025 Windows issue reported missing inherited variables for Docker and npx on CLI 0.41.0, so treat it as a platform/version-specific lead, not proof of a current general bug.
HTTP OAuth login succeeds but the server returns 401 Unauthorized Does the authorization server require an OAuth resource indicator? Re-add the server with --oauth-resource https://your-server.example (a codex mcp add option), then run codex mcp login <name> again. An openai/codex issue reports Codex leaving resource out of the authorize request; its workaround is a manual OAuth flow plus --bearer-token-env-var. For bearer-token auth, confirm the variable name is correct and the token is available to the process; the config reference distinguishes OAuth from bearer_token_env_var.

For local stdio servers, check that the server writes only MCP messages to stdout and sends logs to stderr, as the MCP transport spec requires. Then use codex mcp get <name> to catch a wrong command, URL, or auth field. If list says enabled but no tools appear, investigate startup and handshake logs rather than re-adding the same entry.

What is the end state?

You should see the stdio entry and HTTP URL in codex mcp list, both enabled. To prove they work, start a Codex session and confirm the server connects and exposes its expected tools; a saved config alone is not that proof.

I build Octoweb, so weigh that accordingly. Its MCP server is an HTTP endpoint at http://localhost:3434/mcp, and Octoweb starts it with the browser. The local Codex config accepted that URL in the same --url form described above.

The browser MCP server reference covers client setup and tool details.

Don Karter

Don Karter

CEO & Co-founder at Muvon

20+ years in software engineering, the last decade deep in AI systems. Builds Octoweb — a keyboard-first AI browser for macOS on WebKit and Rust. Writes from the trenches: native browser engineering, agents driving real pages over MCP, and what breaks when every action has to be one keystroke away.

Octoweb is free and open source, for macOS.

Install it →