Connecting External Tools via MCP: Giving Codex "External Interfaces"
📚 Series Navigation: The previous article [19 Memory System (Memories and Chronicle)] covered letting Codex "remember things across sessions"—which is feeding memory inward. This article changes direction to connect outward: by default, Codex can only touch your local files and command line, and cannot reach your databases, Figma, or third-party documentation. MCP is the unified protocol for connecting it to a bundle of external tools and data sources at once. The next article [21 Subagents] covers how to split tasks among a team of subagents with independent contexts to run in parallel.
Let's talk about a pitfall I stumbled into when I first connected MCP, which is quite typical.
I came over from Claude Code, where I had built up muscle memory—to add a server, I would run claude mcp add --scope user xxx, where --scope determines which projects it takes effect in. Switching to Codex, I typed a similar command without thinking, adding a --scope, and the terminal immediately threw an unrecognized parameter error. My first reaction was "outdated version," so I upgraded, but it didn't help; then I suspected a spelling mistake and modified the command back and forth several times—still unrecognized.
After struggling for nearly twenty minutes, I flipped through the official docs and realized: Codex has no concept of --scope at all. It centralizes all MCP configurations into a single config.toml file, and "which projects it takes effect in" is decided by where that file is placed—placing it globally at ~/.codex/config.toml makes it active everywhere, while placing it locally at .codex/config.toml makes it active only in that project. I was trying to apply Claude Code commands to Codex, naturally hitting walls everywhere.
I tell you about this pitfall to save you those twenty minutes of detour: the MCP protocol itself is the same on both sides, but how Codex configures it is a different story. Today, we will explain the Codex system in detail, and finally guide you to connect a real server yourself.
By reading this article, you will get:
- An explanation of what MCP is and how it fills a gap in Codex capabilities
- The distinction between the two server types (local STDIO and remote Streamable HTTP), summarized in a table
- The two configuration paths—the imperative
codex mcp addvs. manually editingconfig.toml, and how the configuration file location determines "global vs. project-level" - How fields like
enabled,disabled_tools, anddefault_tools_approval_moderestrict tools and permissions for a server - A hands-on exercise with expected output: connecting to the Context7 documentation server and verifying it in minutes
⚠️ Any commands, configuration options, and default values mentioned below are subject to the official Codex documentation. Package names and model names that change with updates are subject to what is actually displayed on your local system, and will not be hardcoded here.
01 Understand First: What Gap Does MCP Fill in Codex?
The bottom line: Codex is a local-only assistant by default, and MCP is the unified interface to connect it to external tools and data sources.
Think back to what Codex has been doing in the first dozen articles—reading your files, modifying your code, and running your commands. All local stuff. No matter how smart it is, it cannot touch designs on Figma, query the latest API docs of a library, or control your browser to click a page. It cannot reach these things, so you have to copy-paste, take screenshots, and describe them to it yourself.
Analogy: Plugging a multi-port adapter into your phone. Modern phones might only have a single Type-C port, so if you want to plug in a flash drive, connect an HDMI display, or read photos from an SD card, you can't plug them in directly. What do you do? You buy a multi-port adapter—one end plugs into the phone, and the other exposes USB, HDMI, and card readers. MCP (Model Context Protocol, an open standard for how AI calls external tools) acts as this adapter for Codex: connect it once, and a bundle of external tools appears before it.
The official definition is straightforward:
Model Context Protocol (MCP) connects models to tools and context. Use it to connect Codex to third-party documentation, or let it interact with developer tools like your browser and Figma.
Here is a keyword—standard. MCP is not a proprietary protocol designed by OpenAI behind closed doors; it is an open specification. The benefit is "configure once, use anywhere": an MCP server you write for one tool can be used by Codex, as well as other MCP-supported clients (Claude Code, Cursor, etc.). The same MCP protocol is recognized by Codex, but configured differently (which is where I stumbled, as detailed in Section 03).
Here is a Codex-specific detail worth noting: Codex reads the instructions (description) field returned by a server during initialization, treating it as the "user guide" for that server—which typically includes workflows, constraints, and rate limit warnings for the server's tools. Simply put, a good server comes with its own user manual, which Codex will read.
When should you think of MCP? The rule of thumb is simple: whenever you find yourself copying text from another tool and pasting it into Codex, you should connect a server. Some common scenarios:
- "Modify the layout of this login page based on the new Figma design"—it reads the design itself, saving you from taking screenshots.
- "Rewrite this code using the latest API version of that library"—it queries the latest documentation directly, saving you from worrying about outdated code patterns.
- "Open the browser and take a screenshot of this page under mobile viewports"—it drives the browser directly, saving you from clicking manually.
💡 Summary in one sentence: By default, Codex can only touch local files and commands, unable to reach your designs, latest docs, or browser; MCP is the unified interface that connects these tools, and it reads the server's
instructionsas a user guide.

Diagram: Codex can only touch files and commands locally; MCP acts as a USB hub, plugging into Codex on one end and connecting external servers like GitHub, databases, and Figma on the other.
02 Two Server Types: Running Locally vs. Connecting to the Cloud
MCP servers are not all the same. Understanding their differences tells you where to write your configuration. The core question: is this server running on your own machine, or is it hosted at a URL?
Analogy: Appliances in your home—some draw power from wall outlets, while others connect via Wi-Fi. Lamps and fans plug into your wall outlets and reside locally in your room; smart speakers must connect to cloud servers to check weather and play music. MCP servers are split into these two categories—one runs as a local process on your machine, and the other is hosted remotely for you to connect to.
The official documentation supports two server types:
| Type | Runs Where | How to Start | Suitable For |
|---|---|---|---|
| STDIO (local process) | On your own machine, launched by a command | Providing a startup command (e.g., npx ...) | Servers that directly read local files, control local browsers, or connect local tools |
| Streamable HTTP (remote hosted) | At a URL | Providing a URL | Cloud services, remotely hosted docs, or design servers, requiring authentication |
Here are several points beginners should watch out for:
The essence of a STDIO server is its "startup command." It is basically "Codex launching a small program in the background"—you provide a command (like npx -y @upstash/context7-mcp), and Codex runs the server using this command when starting a session. Therefore, it runs only if the corresponding environment exists on your machine (e.g., using npx requires Node.js installed). You can also pass environment variables (--env or env in configuration) to STDIO servers to supply tokens.
HTTP servers connect to cloud services, supporting two authentication methods. The official docs specify that Streamable HTTP servers support:
- Bearer token: Specifying the environment variable name holding the token in configuration.
- OAuth (Authorized Login): Running
codex mcp login <server-name>to go through authorization flows for OAuth-supported servers.
Remote servers like Figma or cloud doc servers connect simply via a URL and authentication, without requiring anything installed locally.
A difference to watch out for: some tools (like Claude Code) still support deprecated SSE transports, while the official Codex documentation only lists STDIO and Streamable HTTP, keeping it clean. You only need to remember these two.
Let's illustrate how these two types connect Codex to the external world:

This diagram shows: Codex's built-in capabilities only reach local files and commands on the left; the MCP interface uses STDIO (launching a local process) and Streamable HTTP (connecting to a URL with authentication) to link external tools on the right that it otherwise cannot reach.
💡 Summary in one sentence: Local tools use STDIO (launched by a command, requiring the environment installed locally), while cloud services use Streamable HTTP (using a URL, authenticated via Bearer token or by running
codex mcp loginfor OAuth); Codex supports only these two types.
03 How to Add a Server: Commands vs. Manually Editing config.toml
Now that we know the types, let's look at configuration. Codex offers two paths, and remember this key rule: all MCP configurations are saved in config.toml.
The official documentation states:
Codex stores MCP configuration alongside other Codex configuration in
config.toml. By default, this is at~/.codex/config.toml, but you can also use a.codex/config.tomlto scope MCP servers to a specific project (trusted projects only).
This reveals the major difference between Codex and Claude Code—the pitfall I stumbled into: Claude Code uses the --scope parameter to define server scopes, while Codex does not have it, relying instead on the location of the configuration file:
| Configuration Location | Projects Impacted | Concept |
|---|---|---|
~/.codex/config.toml (Global) | All your projects | "Tools I use daily across projects" |
Project .codex/config.toml | Current project only (must be trusted) | "Tools dedicated to this project" |
The docs emphasize: the CLI and IDE extensions share this configuration. An MCP server configured in your terminal is immediately active in the Codex VS Code extension, saving you from re-configuration.
"Trusted projects" is a concept from Codex safety mechanisms (covered in Articles 15 and 16 on permissions and security). Project-level
.codex/config.tomlis only loaded if you trust the directory, preventing cloned repositories from launching hidden servers on your machine.
Path 1: Using codex mcp Commands (Fastest)
To add a STDIO server, use codex mcp add, noting that the server startup command follows --:
codex mcp add <server-name> --env VAR1=VALUE1 -- <stdio startup command>An official example—adding Context7 (a free MCP server dedicated to querying developer docs):
codex mcp add context7 -- npx -y @upstash/context7-mcpThe npx -y @upstash/context7-mcp following -- is the startup command, where -y instructs npx to skip confirmation prompts and install directly. Run codex mcp --help to list all mcp commands. For OAuth-supported HTTP servers, follow up with codex mcp login <server-name> to log in.
In the session (TUI), check currently active MCP servers by running:
/mcpPath 2: Manually Editing config.toml (Finer Control)
For finer controls (limiting tools, adjusting timeouts, setting permissions), edit config.toml directly. Configure each server as a [mcp_servers.<server-name>] table.
A STDIO server block looks like this (matching the Context7 example):
[mcp_servers.context7]
command = "npx"
args = ["-y", "@upstash/context7-mcp"]The fields are straightforward—command is the startup executable, and args is the argument array. STDIO servers also support optional fields: env (environment variables), cwd (working directory), and env_vars (declaring which host environment variables to forward).
A Streamable HTTP server uses url, with authentication configured as needed (this is the official Figma example):
[mcp_servers.figma]
url = "https://mcp.figma.com/mcp"
bearer_token_env_var = "FIGMA_OAUTH_TOKEN"url is the required server endpoint; bearer_token_env_var specifies the environment variable name holding the Bearer token—do not write tokens directly in configuration files (keep credentials out of configs and Git). You can also use http_headers (static values) and env_http_headers (extracted from variables) for custom headers.
ℹ️ This
config.tomlis the same configuration file covered in Article 18 config.toml Configuration Guide. MCP is just one of its tables (mcp_servers). Both paths modify the same file—codex mcp addwrites this table for you, and manual edits let you write it yourself.
💡 Summary in one sentence: All Codex MCP configurations are in
config.toml—there is no--scopeparameter, and scope is decided by global~/.codex/vs. project.codex/paths (project paths require trust); add servers usingcodex mcp add(with the command following--) or manually writing[mcp_servers.<name>]tables. CLI and IDE share this configuration.
04 Restricting a Server: Switches, Tool Whitelists, and Permissions
Adding a server doesn't mean granting it free rein. Codex provides keys in config.toml to restrict individual servers—which tools can be used, timeouts, and whether calls require approval.
Analogy: Setting permissions on an access card for a new intern. You wouldn't give an intern a master key to the entire building—you check "allowed in these conference rooms, blocked from the server room," "expires after hours," and "requires confirmation before entering finance." Configuring MCP tool permissions is the same: a server brings a bundle of tools, and you specify which are allowed, which are blocked, and which prompt for approval.
The most common fields are listed below:
| Config Field | Role | Default / Value |
|---|---|---|
enabled | Temporarily disables a server (without deleting configuration) | Set false to disable |
enabled_tools | Tool whitelist (only allow these) | Allows all if unset |
disabled_tools | Tool blocklist (applied after whitelist) | — |
default_tools_approval_mode | Default approval behavior for server tools | auto / prompt / approve |
startup_timeout_sec | Server startup timeout (seconds) | Default is 10 |
tool_timeout_sec | Individual tool execution timeout (seconds) | Default is 60 |
Key behaviors to watch out for:
Whitelist applies before blocklist. The official docs specify that disabled_tools is "applied after enabled_tools." This means you can "use the whitelist to select a group, and then use the blocklist to exclude specific dangerous tools." The official Chrome DevTools example shows this: setting enabled_tools = ["open", "screenshot"] releases two tools, and then disabled_tools = ["screenshot"] excludes screenshot, leaving only open active.
default_tools_approval_mode has three values (do not mix them up with sandbox modes):
auto: Let Codex decide using standard approval logicprompt: Prompts you for confirmation on every callapprove: Approves automatically (equivalent to trusting the server)
You can also override these per-tool using tools.<tool-name>.approval_mode. For example: "allow this server's tools automatically, except for the one that deletes data, which must prompt me every time."
The timeout defaults: 10 seconds for startup, and 60 seconds for tool execution. I was once tripped up by a slow local Python server—its cold startup took about 15 seconds, and the default 10-second timeout aborted it before it was ready. I assumed the server was broken, but adjusting startup_timeout_sec resolved it:
[mcp_servers.slow_server]
command = "python"
args = ["-m", "slow_server"]
startup_timeout_sec = 30 # Adjust for slow startup
tool_timeout_sec = 120 # Adjust for long-running toolsA comprehensive HTTP server configuration example:
[mcp_servers.chrome_devtools]
url = "http://localhost:3000/mcp"
enabled_tools = ["open", "screenshot"]
disabled_tools = ["screenshot"] # Blocked after whitelist, leaving only open
default_tools_approval_mode = "prompt" # Prompt for all tools by default
startup_timeout_sec = 20
enabled = true
[mcp_servers.chrome_devtools.tools.open]
approval_mode = "approve" # Override: open is approved automatically💡 Summary in one sentence: Manually editing
config.tomlallows fine control of servers—enabledswitches it on/off,enabled_tools/disabled_toolsselect allowed/blocked tools,default_tools_approval_mode(auto/prompt/approve, overrideable per-tool) manages approvals, and startup/execution timeouts default to10/60seconds.
05 Trust Issues with Third-Party Servers: Inspect Before Connecting
This section is short but critical—connecting to the core message of Article 16 Security and Risk Boundaries.
The principle is simple: MCP servers are third-party code; OpenAI does not perform security audits on them. Connecting to a STDIO server runs a program written by someone else on your machine; connecting to an HTTP server fetches external content into Codex's view. Think carefully about both.
Analogy: Installing a third-party package in a production project. You wouldn't run npm install for an unknown package with an anonymous maintainer on your production servers—you check who maintains it, how many people use it, and its reputation. An MCP server is a third-party dependency: check its origin before installing, especially if it fetches external content (web pages, tickets, docs).
Why are servers fetching external content higher risk? Because they are hotbeds for prompt injection (malicious instructions in content masquerading as your commands)—covered in Article 16. Briefly: web pages or documents fetched by a server can hide instructions written for the AI, which might mislead Codex. This is why the "restrict tools + adjust approvals" controls in Section 04 are valuable—setting a server's tools to prompt (ask every time) or blocking dangerous tools in disabled_tools protects you from the source.
Rules of thumb for connecting servers:
| Scenario | Connect? |
|---|---|
| Servers recommended in official docs (OpenAI Docs, Context7, Figma, Playwright) | ✅ Relatively safe |
| Official servers from major vendors (GitHub, Sentry official) | ✅ Relatively safe |
| Third-party servers on GitHub with few stars | ⚠️ Check source code and think twice before connecting |
Setting a server to default_tools_approval_mode = "approve" | ⚠️ Only for servers you trust completely |
| Granting write permissions to production data | ❌ Keep it read-only, do not grant write access |
The last rule is key: limit permissions and prefer read-only settings to minimize risk. Combined with Codex sandboxing and approvals (Articles 15 and 16), MCP servers run inside safety boundaries—but those boundaries cannot save you if you manually set a malicious server to auto-approve. You must make the call.
💡 Summary in one sentence: MCP servers are third-party code, and OpenAI does not audit them; verify trust before connecting, prefer official/vendor servers, watch out for prompt injections on servers fetching external content, set unknown tools to
prompt, block dangerous ones, and default to read-only access.
06 Hands-on: Connect Context7 Docs Server and Verify
Practice makes perfect. Below, we connect Context7—a free server recommended in the official docs for querying developer documentation, requiring no payment and minimal configuration. It is perfect for practicing. It does not depend on any complex local projects.
⚠️ Prerequisite: Context7 is launched using
npx, so you must have Node.js installed (runnode -vto check). It fetches docs online; use appropriate network access if connections fail. Package names and arguments follow current official guidelines.
Step 1: Add the server (in your terminal, not inside a codex session)
codex mcp add context7 -- npx -y @upstash/context7-mcpExpected: Prints confirmation indicating that the context7 MCP server has been added. This command is equivalent to writing a [mcp_servers.context7] table in ~/.codex/config.toml (covered in Section 03); open the file to verify if you wish.
Step 2: Enter a session and check if it is active
codexIn the session, check active MCP servers:
/mcpExpected: Verify context7 appears in the list—showing the configuration took effect and the server connected. If it does not appear or throws errors, verify Node is installed and network connectivity works.
Step 3: Tell Codex to query docs using this server
Send a prompt, explicitly asking it to query the latest documentation (forcing it to use Context7 instead of relying on potentially outdated model training data):
Use Context7 to query the routing setup of React Router latest version, and show me the example from the official documentation.Expected: Codex calls the Context7 tool to fetch the latest docs. Depending on your approvals configuration, it will pause and ask you to approve the tool call on first use (as covered in Sections 04 and 05); click approve. It then returns the configuration from the live doc server rather than legacy memory. You can see Context7 being called during execution, confirming the answer comes from the external server.
Step 4: Cleanup (Optional)
To remove the server, choose one of two methods:
codex mcp --helpUse this command to check the exact spelling of the removal command for your local version, and run it; or simply open ~/.codex/config.toml and delete the [mcp_servers.context7] table, or add enabled = false to disable it—manually modifying the file is just as clean.
Running these steps walks you through the flow of "adding a server → checking connection → calling and approving → removing." Connecting other servers follows this exact process—differing only in name, startup command or URL, and any authentication/permissions added in config.toml.
💡 Summary in one sentence: Connecting Context7 is the most reliable practice—add with
codex mcp add, verify with/mcp, query docs and approve the first call in a session, and clean up inconfig.toml; running this flow is better than memorizing commands.
07 Summary
We have connected Codex to the external world—using MCP as an adapter to hook up a bundle of tools at once.
Let's review the key points:
| Objective | Tool / Method | Key Takeaway |
|---|---|---|
| What is MCP? | An open connection protocol | Codex cannot touch external tools by default; MCP connects them, reading server instructions |
| Local Tools | STDIO server | Provide startup command (npx ...), requiring local environment |
| Cloud Services | Streamable HTTP server | Provide URL, authenticate via Bearer token or by running codex mcp login for OAuth |
| Server Scope | File location (no --scope) | Global ~/.codex/config.toml / project .codex/config.toml (trusted only) |
| Add Server | codex mcp add / edit config.toml | Startup command follows --; configuration shared by CLI and IDE |
| Restrict Server | config.toml fields | enabled / whitelists and blocklists / default_tools_approval_mode / timeouts |
| Third-party Servers | Verify trust | OpenAI does not audit; beware of prompt injections, default tools to prompt, use read-only |
You should now be able to: identify what gap MCP fills; configure STDIO and HTTP servers; understand how Codex uses file locations instead of --scope to define scopes; add servers using codex mcp add or manual edits and check status with /mcp; restrict servers using enabled_tools and default_tools_approval_mode; and verify trust before connecting third-party servers. This ability is your key to elevating Codex from a local assistant to driving your entire toolchain.
Remember the pitfall: Codex has no --scope parameter, configurations go into config.toml, and the startup command follows --. This saves you from the twenty minutes of detours I faced.
The next article [21 Subagents]—MCP lets a single Codex do more, but as tasks grow, a single Codex can become overwhelmed, and its context window crowded. The next article looks at a different approach: instead of one Codex handling everything, we deploy a team of subagents with independent contexts—the main agent assigns tasks, and subagents work separately without polluting each other's context. Think about it: if we split "querying docs," "writing tests," and "running builds" among subagents working in parallel, wouldn't that be cleaner than one Codex switching back and forth?