2026-07-19

Codex MCP Server Setup: Connect Skills to Live Tools

Connect Codex skills to an MCP server with scoped tools, safe approvals, authentication, dependency metadata, testing, and production troubleshooting.

Codex MCP Server Setup: Connect Skills to Live Tools cover illustration

The most misleading MCP status is a healthy-looking list. A server name appears, its URL looks right, and the row says enabled. None of that proves Codex can discover a useful tool, authenticate the call, or return data the workflow can trust.

That distinction showed up on the current host with codex-cli 0.144.6. codex mcp list reported the OpenAI documentation server as enabled while its authentication column read Unsupported. An actual documentation search through that same server succeeded. The list was describing configuration and an authentication capability, not end-to-end health. A setup test that stops at the list can therefore reject a working no-auth server—or approve a broken authenticated one.

The first decision is how much failure you want

Before choosing STDIO or HTTP, decide whether the job should continue when the server is absent. Codex exposes that decision as required. With required = true, an enabled server that cannot initialize prevents startup or makes codex exec exit. That is appropriate when the task would be misleading without the external source: a compliance check that must inspect a policy system, for example.

Most convenience integrations should remain optional. If a documentation helper is down, unrelated code editing can still proceed. The cost is subtler: a workflow may degrade into answers from local context without making the missing source obvious. Optional is resilient; required is honest. Neither is universally safer.

Server roleReasonable failure modeOperator consequence
Helpful documentation searchrequired = falseCodex remains usable, but the workflow must disclose that live documentation was unavailable
Authoritative policy or inventory lookuprequired = trueThe dependent run stops instead of substituting stale or guessed facts
Write path into an external systemUsually required for that workflow, with explicit tool approvalNo draft or mutation is claimed unless the server initialized and the tool returned an identifier

This is the operating choice people often bury under transport details. A ten-second startup timeout can be tuned later. Silent degradation is a product decision.

A server can be listed and still be useless

The local check used two commands and one real call:

$ codex --version
codex-cli 0.144.6

$ codex mcp list
Name                 Url                              Status   Auth
openaiDeveloperDocs  https://developers.openai.com/mcp  enabled  Unsupported

After that list, the MCP search tool was asked for the Codex approval-mode documentation. It returned the relevant configuration reference. That final call established transport, initialization, discovery, invocation, and result delivery. It also exposed why the status column should not be promoted into a monitoring oracle: this server does not need an interactive OAuth flow, so Unsupported was not an error.

Use codex mcp list to inspect configuration. Use a known-answer tool call to test the integration.

A useful smoke test is deliberately boring. Ask a read-only tool for a fact whose answer and source are known, then compare both. Avoid a broad research prompt; it can succeed from model knowledge or repository files even when MCP contributed nothing. Record the server name, tool name, one source identifier, and the returned fact. That small artifact is enough to distinguish “the model answered” from “the integration worked.”

Workflow instructions passing through a narrow gateway to separately controlled external tool modules
Configuration establishes the connection; a narrow workflow decides what evidence a successful call must return.

Choose transport from the ownership boundary

STDIO is a process Codex starts. Streamable HTTP is a service somebody operates. The shorter TOML block is not the deciding factor.

A local repository index, a package-distributed helper, or a developer tool that needs the current working tree usually belongs on STDIO. Codex can set its command, arguments, environment, forwarded environment variables, and working directory. The machine now owns the runtime and package version. Pinning that version matters because a floating package can change tool schemas without a repository diff.

A shared catalog, SaaS integration, or centrally governed internal service usually belongs behind Streamable HTTP. That moves availability, TLS, authentication, rate limits, and versioning to the service owner. Codex can supply a bearer token from an environment variable, static headers, environment-backed headers, or stored OAuth credentials. If no credential source resolves, it may still connect without authentication; whether that is valid depends on the endpoint, not on Codex.

Scope matters: user-wide MCP settings normally live in ~/.codex/config.toml. A project may define .codex/config.toml only when the project is trusted. The desktop app, CLI, and IDE extension share the configuration on the same Codex host.

Small STDIO configuration, explicit assumptions

[mcp_servers.engineering_docs]
command = "npx"
args = ["-y", "@example/engineering-docs-mcp@1.4.2"]
cwd = "/srv/engineering-docs"
startup_timeout_sec = 20
tool_timeout_sec = 45
enabled = true
required = false

[mcp_servers.engineering_docs.env]
DOCS_ROOT = "/srv/engineering-docs"

Codex defaults to ten seconds for startup and sixty seconds for a tool call. Increase those values only after measuring the slow path. A generous timeout can hide a package install on every launch; a tiny one can make a sound server look intermittent.

Shared HTTP service with a constrained surface

[mcp_servers.issue_hub]
url = "https://mcp.example.com/mcp"
bearer_token_env_var = "ISSUE_HUB_MCP_TOKEN"
enabled_tools = ["search_docs", "get_issue", "create_issue_draft"]
disabled_tools = ["delete_issue", "publish_issue"]
default_tools_approval_mode = "writes"
startup_timeout_sec = 20
tool_timeout_sec = 45
enabled = true
required = true

[mcp_servers.issue_hub.tools.search_docs]
approval_mode = "approve"

[mcp_servers.issue_hub.tools.create_issue_draft]
approval_mode = "prompt"

The deny list is applied after the allow list. That makes it useful as an emergency subtraction, but it should not excuse an overbroad allow list. Start with the few tools the workflow actually calls. The supported approval modes are auto, prompt, writes, and approve; per-tool rules can override the server default.

Client policy is a guardrail, not authorization. The server still has to authenticate the caller, enforce tenant and scope, validate arguments, and reject prohibited mutations. A hidden delete tool is good ergonomics. A delete endpoint that trusts every authenticated caller remains a security defect.

Tool discovery is an API diff

MCP tools are an interface, even when nobody generated a client library. A server update can rename an input, split one tool into two, drop a read-only annotation, or add a tempting administrative action. “The server initialized” says nothing about that drift.

Capture the discovered tool names and the input shape of each approved tool in a review artifact. Compare that artifact after package upgrades or service releases. The most important changes are not always additions: if a previously read-only tool loses that annotation, writes approval behavior can change. If a new alias bypasses a deny entry, the visible surface has expanded.

Server-wide instructions deserve the same review. Codex reads that field during initialization as guidance alongside the tools. OpenAI recommends keeping its first 512 characters self-contained, because that leading portion must carry the constraints and workflow information Codex needs while deciding whether to use the server. Treat a change there as code, not marketing copy.

An MCP connection passing separate initialization, discovery, read, approval, and readback checkpoints
A reliable check isolates the layer that failed instead of treating one final prompt as proof of the whole stack.

Validation that makes false confidence difficult

Run the read path before the write path. A known-answer lookup proves that the named server and tool contributed evidence. Then test absence: disable the server or remove its credential and confirm the workflow reports the missing dependency instead of inventing a result. For an optional server, the rest of Codex should remain usable; for a required server, startup should stop.

Only then exercise a write tool against a disposable destination. Confirm that the expected approval appears, capture the returned record identifier, and read the object back through a separate call. A success string is weaker than external state. If the write times out after dispatch, search for the record before retrying; the lost event may be the response rather than the mutation.

A compact acceptance run covers six distinct claims:

  • The configured server initializes within the measured startup budget.
  • Only reviewed tool names and schemas are discoverable.
  • A read-only known-answer call returns the expected fact and source.
  • A consequential tool follows its configured approval rule.
  • The external system confirms a write by identifier or readback.
  • Missing credentials, an unavailable server, and a denied tool each fail in the intended way.

This is more work than glancing at a green row, but it is also the smallest test that covers what operators care about. It separates configuration, transport, authentication, discovery, invocation, approval, and external state. When a later update fails, the broken boundary is visible.

Where a skill belongs—and where it does not

A Codex skill can name the job, the evidence to collect, the order of calls, and the conditions that must stop the run. It should not contain bearer tokens, duplicate transport configuration, or pretend to enforce server permissions. Keep the MCP connection in Codex configuration and the authorization boundary on the service.

The acceptance contract should survive a transport swap

For a repository-support workflow, the skill might require a documentation search, an existing-issue check, a human-confirmed destination, a draft-only create call, and a final readback. If the integration is unavailable, the destination is ambiguous, or a duplicate exists, the skill stops. This remains reviewable even if the team later replaces STDIO with HTTP while preserving the tool contract.

That separation is the durable design: transport can change without rewriting the business procedure, and the procedure can become stricter without modifying the server. GolemWorkers can keep a Codex host, scoped secrets, logs, and schedules available continuously. It cannot turn an overprivileged MCP server into a narrow one; that boundary still belongs to the service owner.

Primary documents used for this check