iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
🤖

Configuring Project-Specific MCP in openai/codex

に公開

I'm looking into codex to try out gpt-5-codex.

Note: I've found two methods, but they are hacky approaches that feel like a temporary workaround during a transitional phase.

Motivation

While Claude Code allowed for independent MCP settings per project, currently codex only provides a way to configure MCP globally.

For example, I don't want code analysis tools like lsmcp or serena to be running constantly; I want them to be project-specific MCP processes.

https://github.com/mizchi/lsmcp

Since this isn't in the documentation, I searched for a configuration method by reading the codex source code directly.

https://github.com/openai/codex

(Admittedly, since both lsmcp and serena analyze code based on the current directory, they do function simply by being left running.)

Method 1: CODEX_HOME=$PWD/.codex

You can change the loading directory by specifying the CODEX_HOME= environment variable.

By specifying it directly, you can load project-specific MCP settings.

Configure .codex/config.toml as follows:

model = "gpt-5-codex"

[mcp_servers.playwright]
command = "npx"
args = ["-y", "@playwright/mcp"]

Start it in this state:

CODEX_HOME=$PWD/.codex codex

A drawback is that .codex/ also stores authentication information and other data, so it cannot be committed to the repository.

$ ls ~/.codex/
auth.json    history.jsonl          log       version.json
config.toml  internal_storage.json  sessions

Even if you add !/.codex/config.toml to .gitignore, OpenAI might change what gets written there at any time, so it's likely to cause issues eventually.

Therefore, this should only be treated as an internal debugging method; for daily use, the following method seems safer.

Method 2: --config='...'

Based on the implementation, codex has a feature to load TOML directly using --config='key=val'.

I thought I could use this to overwrite just the mcp_servers= setting.

# Verify with codex mcp list
$ codex -c 'mcp_servers={"playwright"={"command"="npx",args=["-y", "@playwright/mcp@latest"]}}' mcp list
Name        Command  Args                       Env
playwright  npx      -y @playwright/mcp@latest  -

# Start with this configuration
$ codex -c 'mcp_servers={"playwright"={"command"="npx",args=["-y", "@playwright/mcp@latest"]}}'

 Open https://example.com with playwright-mcp

tool running...
playwright.browser_navigate({"url":"https://example.com"})

If you want to load it dynamically by placing .mcp.json in your current directory:

$ codex -c "mcp_servers=$(jq .mcpServers .mcp.json -cM | sed 's/\":/\"=/g')" mcp list

You can set this as a bash/zsh alias:

# ~/.bashrc
alias codex-mcp='codex -c "mcp_servers=$(jq .mcpServers .mcp.json -cM | sed 's/\":/\"=/g')"'

Note that this relies on a strong assumption that .mcp.json exists, and it uses sed to forcibly convert JSON to TOML.

Reference (pretty much the source):

https://github.com/openai/codex/issues/2554

Addendum: For serena

The JSON => TOML conversion was too crude and failed to work with serena, so I'll provide a fix for just this part (since I feel like many people might use it).

https:// was being converted to https=//.

# without sed
codex -c 'mcp_servers.serena={command="uvx",args=["--from", "git+https://github.com/oraios/serena", "serena", "start-mcp-server", "--context", "codex", "--enable-web-dashboard=false"]}'

# .zshrc
alias codex-serena='codex -c "mcp_servers.serena={command=\"uvx\",args=[\"--from\", \"git+https://github.com/oraios/serena\", \"serena\", \"start-mcp-server\", \"--context\", \"codex\", \"--enable-web-dashboard=false\"]}"'

Wrap-up

In any case, these are tips that will likely be rendered obsolete by a better method in the future.

Discussion