Per-directory MCP servers in Codex and Claude Code

By Rareș GosmanWork in progress

Atomic's MCP server works on one database per connection, so I wrote a script that picks one per folder in Codex and Claude Code, keeps the token out of the config, and warns you when Codex is ignoring your .codex/config.toml.

MCPCLIAI Agents

I keep my notes in Atomic, a self-hostable AI note-app. I have four databases. Admin is full of flight confirmations and AI Chat Sessions is full of product theses. Atomic's MCP server works on one database per connection, the one in the URL. An agent can see the others with list_databases, but no tool can switch to them, so a session connected to Admin can't get at my product theses.

So the database gets picked when you configure the MCP server, not when you call it. That should be a quick edit, but Codex and Claude Code each need their own, and they keep per-folder config in different places. Codex also ignores its per-folder file until you trust the project, and it doesn't tell you. So I wrote a script.

atomic-mcp-select

atomic-mcp-select lists your databases, lets you pick one, and adds the MCP server to both Codex and Claude Code:

atomic-mcp-select --list            # what databases exist
atomic-mcp-select admin             # this directory, both tools
atomic-mcp-select --global admin    # user-level config, both tools

Each entry is named after its database, like atomic_admin or atomic_ai_chat_sessions, so the agent can see which notes it's about to write to. Picking a database replaces the previous atomic_* entry in that scope. Restart Codex and Claude Code afterward so they pick up the change (in Claude Code, /mcp also works).

The config stores the name of the token's env var, never the token. Codex has a bearer_token_env_var field for this. In Claude Code, you put ${ATOMIC_MCP_TOKEN} in a --header and it fills in the value at runtime, so ~/.claude.json only ever has the placeholder and claude mcp list still says Connected. If you're doing this by hand, use single quotes so your shell doesn't fill in the real token first:

claude mcp add --transport http atomic_admin "$URL" \
  --header 'Authorization: Bearer ${ATOMIC_MCP_TOKEN}'

Where the config actually lives

Scopes work the way both tools already handle skills: set a default globally, add another in a folder, and inside that folder you get both. Picking a database in one scope leaves the other alone. off clears this folder, and --global off clears the global entry.

But Codex and Claude Code store the per-folder entry in opposite places. Codex keeps it in the directory, in ./.codex/config.toml. Claude Code keeps it centrally, in ~/.claude.json, keyed by the exact path, so run the selector in the directory you start sessions from. And codex mcp add has no project flag at all; it only writes the global file. For Codex, the script edits the TOML itself, with tomlkit, so your comments and your other servers survive.

Codex ignores the file until you trust the project

Until you trust the project, Codex ignores ./.codex/config.toml without telling you. Your server just doesn't show up in codex mcp list. Trust lives in ~/.codex/config.toml:

[projects."/Users/rares/atomic"]
trust_level = "trusted"

The easy way to get that entry is to run codex in the directory once and accept the prompt. The script warns you when it's missing.

I used to think the trust entry had to be for the project's top folder and nothing else: the root of the git repo or, outside a repo, the directory itself. That's true outside a repo, and a trusted folder above the project never counts. But inside a repo, trust carries down from whichever folder you trust. Trust the root and Codex loads every .codex/config.toml from the root down to your working directory. Trust only a subfolder and Codex loads that subfolder's config but not the root's.

I had an agent test all of this in October 2026 on throwaway configs, using Claude Code 2.1.302 and codex-cli 0.162.1 and 0.142.5.

Get the script

Grab the gist (MIT). With uv installed, save it as atomic-mcp-select on your PATH and chmod +x it. Set ATOMIC_BASE_URL to your Atomic server and ATOMIC_MCP_TOKEN to a token. It writes to three config files, so read it before you run it.

If you don't want to touch config at all, atomic-mcp-select url prints a database's MCP URL, which you can pass to mcpfile. Every mcpfile call takes its own URL, so you can reach any database without restarting your session:

URL=$(atomic-mcp-select url admin)
mcpfile call read_atom --arg atom_id="$ID" --select content \
  --out note.md --url "$URL" --bearer-env ATOMIC_MCP_TOKEN