Skip to content

Course · Codex · Extending Codex

Connect the exchange-rate API as an MCP server

Nothing inside budgetcli (the course’s running example, a small self-hosted personal-finance API in Python and FastAPI) can fetch a rate. The repo has no fx module and never did - the foreign-currency feature is this course’s constructed next ticket, labeled once in the chapter opening and once more here. Codex can read the ticket, understand exactly what it needs, and reason about currency conversion all day. It still can’t dial a server that isn’t wired to it. That is not a knowledge gap a rule can close. It is a reach gap - and every door that closes it can charge rent.

The Model Context Protocol is an open standard for connecting an agent to an external tool or data source; an MCP server is one such connection. Wire the rate API up as a server and Codex gets a new tool - convert one currency to another - that it reaches for on its own, the way it already reaches for shell or file edits. The API stops being something you look up and paste in, and becomes something the agent touches directly.

Codex configures MCP servers in config.toml, under a [mcp_servers.<name>] table - yours at ~/.codex/config.toml, or the repo’s .codex/config.toml for trusted projects. The common shape is a stdio server: a process Codex spawns on your machine and talks to over stdin/stdout. You give it a command and its args:

# ~/.codex/config.toml (or .codex/config.toml in the repo)
[mcp_servers.fx]
command = "npx"
args = ["-y", "your-exchange-rate-mcp-server", "--api-url", "https://<your-rate-api-endpoint>"]

Use the real package and endpoint your rate provider publishes - the values above are placeholders, not a server that exists. The table name, fx here, is how the server is named in config, in codex mcp output, and in the tool names further down.

Servers that live out on the network are reached as remote servers instead, by giving a url in place of command/args. Which key is present picks the transport; the full syntax for both shapes, plus OAuth and environment-variable auth, is on the Codex MCP docs.

You don’t have to hand-edit the file. The codex mcp subcommand manages servers from the CLI:

codex mcp add fx -- npx -y your-exchange-rate-mcp-server --api-url https://<your-rate-api-endpoint>
codex mcp list # what's registered
codex mcp get fx # inspect one server
codex mcp remove fx

The bare -- in the add form separates the server name from the command Codex will spawn: everything before it is the name, everything after is the process. Inside a session, /mcp shows the same connection status without leaving the agent.

One test before you read any further. Run codex mcp list on your own setup right now. If it comes back empty, none of the arithmetic below has cost you anything yet - it starts the moment you register your first server, and this lesson is about why that moment is worth noticing. If it already lists two or three servers, you’re already on the meter.

Every MCP tool ships a schema - name, description, parameters - and a name the model addresses it by. The model-visible name is mcp__fx__convert: an mcp__ prefix, then the server name, then the tool name, joined with double underscores. The TUI renders the same call as fx.convert - server, dot, tool - which reads easier and is what you’ll see on screen. Two renderings, one tool. Roughly what the schema looks like:

{
"name": "mcp__fx__convert",
"description": "Convert an amount from one currency to another at the day's exchange rate.",
"inputSchema": {
"type": "object",
"properties": {
"from": { "type": "string", "description": "ISO 4217 source currency, e.g. EUR" },
"to": { "type": "string", "description": "ISO 4217 target currency, e.g. USD" },
"amount": { "type": "integer", "description": "Amount in cents of the source currency" }
},
"required": ["from", "to", "amount"]
}
}

Count it: 512 characters. At four characters per token - this course’s declared prose estimator - that’s 128 tokens. Against a 200,000-token window, 128 tokens is nothing. That is exactly the reading that gets people into trouble, because it is measuring the wrong thing.

A schema is not a one-time read, the way opening a file is. A tool definition that is loaded rides the context window turn after turn - the turn where you ask about a EUR transaction, and the turns after it where you don’t. Call this the standing toll: what a connected server charges, every turn, whether you use it or not.

Current Codex gives that toll a wrinkle worth budgeting around. On model and provider combinations that support tool search, Codex defers MCP schemas by default: at the start the model sees the server’s name and description - a small stub, not the 128-token schema - and the full schema loads only when the model searches for and then uses the tool. Once loaded, it stays in context for the rest of the session.

Where deferral isn’t available - older setups, unsupported combinations - the schema rides from the moment you register the server. The tool search docs describe the mechanism.

So the honest version of the toll: it is real in every case that matters. From registration where schemas inject up front, and from first use everywhere else - and from first use it keeps charging whether you call the tool again or not. Reach isn’t a purchase. It’s rent. The lease just may not start until the first call.

Reach is its own surface, not the sandbox wall

Section titled “Reach is its own surface, not the sandbox wall”

Here is the correction this chapter promised, because the instinct is strong. Back in approvals & sandbox, the constructed rate ticket hit a wall: workspace-write keeps network off by default for scripts and subprocesses that shell commands spawn, and [sandbox_workspace_write] network_access = true was the deliberate, scoped fix. It’s natural to assume the MCP server faces the same wall. It doesn’t - and assuming so mis-aims both controls.

The docs draw the line explicitly. The command network proxy “applies to scripts, programs, and subprocesses spawned by commands” and “does not filter … MCP server connections.” Those connections run through their own surface: the mcp_servers config that defines the server, managed allowlists where an organization sets them, and per-server and per-tool approval settings - destructive tool calls always require approval when the tool advertises a destructive annotation.

Practically: registering a server is the reach decision. Nothing else has to be switched on for fx to go get rates. So treat registration the way the approvals chapter taught you to treat widening a fence - named server, known tools, a reason you can say out loud - and check /mcp to see exactly what you’ve granted. Flipping network_access for a shell-spawned script and registering an MCP server are two different doors, opened by two different decisions, on purpose.

With the server wired, the copy-paste loop the ticket was built to avoid finally closes:

> recompute the EUR and GBP transactions at the current rate
• fx.convert { from: "EUR", to: "USD", amount: 4200 }
→ 4557
• fx.convert { from: "GBP", to: "USD", amount: 1899 }
→ 2402
Converted both at the live rate and stored integer cents, per the
AGENTS.md money rule. The March total drops by $38 once the stale
guessed rates are replaced.

An illustrative reconstruction, not a captured run - your server supplies the numbers, and the reply wording is yours. The fx.convert lines are the TUI rendering; the model addressed mcp__fx__convert. You asked one question in plain language; Codex called the rate tool twice on its own, applied the cents-not-floats rule from AGENTS.md without being reminded, and reasoned across the result.

One server at 128 tokens a turn is easy to shrug off. Real setups rarely stop at one. The meter below models five servers people commonly reach for - GitHub, a browser via Playwright, Notion, Figma, Postgres - stacked on top of Codex’s own built-in tools, modeled at roughly 12,000 tokens before you add anything:

82k of 200k (41%) spent before your first message
Built-in tools (12k, fixed)MCP tool schemas (70k)

Tool counts and schema sizes are illustrative (~600 - 800 tokens per tool definition). The shape is the point: every enabled server's schemas are paid for in window space - up front on clients that load eagerly, at first use on clients that defer.

Turn all five add-ons on together and tool schemas alone cost 82,000 of the 200,000-token window - 41 percent - before your first message goes out. Turn them off one at a time and watch the bar shrink. The meter is an order-of-magnitude model of the upfront arithmetic, the worst case: its tool counts and schema sizes are illustrative, and mcp__fx__convert at 128 tokens is one tool with three parameters - a 35-tool server carries thirty-five of those.

Tick the box marked defer schemas until first use and every enabled server drops to a small stub until one of its tools is called. That lever is not hypothetical in current Codex: on supported model and provider combinations, deferral is the default behavior described above. What the checkbox models - and what you should still check on your own setup - is availability: deferral depends on the model, provider, and configuration, so verify which regime you’re actually in before budgeting around it.

The discipline this buys you is simple: connect for a concrete gap, not on spec. fx earns its place because nothing in budgetcli can reach that API. A server you added “in case it’s useful later” charges the same standing toll as one you use ten times a day - the meter doesn’t know the difference, and neither does your context window.

MCP runs both ways. Everything above pointed Codex outward - it became a client of the rate API. Codex can also stand on the other side, exposing “do a coding task in this repo” as a tool some other program drives. The old wiring for that was codex mcp-server, a stdio entry point.

Treat that command as history. It was deprecated in the 2026-08-24 changelog and removed from the CLI in 0.154.0 (2026-09-09; re-verified firsthand against the installed 0.155.1, where mcp-server is no longer a recognized subcommand); new integrations use the Codex app server instead. If you meet codex mcp-server in older automation examples, that’s what it was.

The pattern it served still matters. When another system owns the loop - a larger agent, a script, CI - and wants repo-scoped coding as one callable capability, Codex serves rather than hosts, and the caller then owns the approval and sandbox decisions for the work Codex does. A serving invocation with wide-open approvals on your real repo is exactly as dangerous as it sounds, with no human at the TUI to catch it. Scope it like any unattended run - which is squarely where the automation chapter heads.

fx is wired conceptually, and the constructed label deserves restating: no rate code exists anywhere in budgetcli - what this lesson added is the door, not the feature. The door has a price you can now compute for any server before you add it. And what a server sends back is outside content the agent reads and acts on, exactly like a bank CSV or a web page - a tool reply is a place instructions can arrive from, and the same rule applies as to any untrusted input.

None of that stops Codex from using the reach to make the one write that must never happen by accident. Rent buys you a tool, not a guarantee. The guarantee is a different kind of thing entirely, and it is the next lesson.