Mirror your Claude Code Linear MCP into Codex in one command

Quick follow-up to running Claude Code and Codex side by side.

In that post, the whole setup hinges on one trick: symlink CLAUDE.md to AGENTS.md and let both agents read the same project instructions. Cheap, simple, works everywhere.

Almost everywhere.

Per-project Linear MCPs.

Here’s the situation. I have my own Linear workspace for each personal project I work on. When I first tried to just keep one linear mcp going and use it from different projects, I ran into an obvious issue… every project was just using the workspace from the first project I had authed. NOT a good idea.

So on the Claude side, I started creating an aliased linear mcp under each project’s scope - linear-trishot, linear-freelancers-copilot, etc.

This was already enough friction to where I almost didn’t adhere to it. Remembering which of the 4 claude mcp command syntaxes in my bash history was the one that actually worked put me just over the edge where I dreaded “breaking my flow” more than I looked forward to “workflow enhancement that will pay dividends for all time”.

But on top of that, I had to figure out the same thing for Codex? No way.

I mean let’s be real, none of it is hard. It’s just fiddly. Five minutes of copy-pasting between files, changing the right variables, dropping a note in AGENTS.md, remembering the command to authenticate.

…Five minutes per project.

One project, fine. But let’s say you’re migrating everything. Or, mid flow on a project already when Claude rate limits you and you not only have to switch to codex, but you realize you have no Linear access unless you break your entire flow and figure it out again… safe to say I got tired of doing it by hand.

The skill

So I wrote a Claude Code skill that does the whole thing. In any project where Claude already has a Linear MCP configured, run:

/mirror-linear-to-codex

The skill reads the name from Claude’s config, writes the matching entry to .codex/config.toml inside the repo, and drops a one-liner in AGENTS.md so Codex picks the right Linear server when you’re in that repo.

Then it gives you the layup: the exact command to run in bash mode (! in Claude Code) once to auth the new server, and you’re set.

Barely 30 seconds per project once the skill is in place. You won’t break a sweat.

The skill itself

Save this as ~/.claude/skills/mirror-linear-to-codex/SKILL.md:

---
name: mirror-linear-to-codex
description: Mirror a project's Claude Code Linear MCP into Codex by writing a matching [mcp_servers.<name>] entry to the project-local `.codex/config.toml` (Codex's per-project MCP scoping mechanism). Use when the user wants Codex to have the same per-project Linear MCP that Claude Code already has (e.g. "set up the Linear MCP for Codex on this project", "mirror the Linear MCP to Codex").
allowed-tools: Bash, Read, Edit, Write, Grep, Glob
---

# Mirror Linear MCP to Codex (per-project)

Codex supports per-project MCP scoping via `.codex/config.toml` in the repo (as of codex-cli 0.121+). This skill mirrors a Claude-side per-project Linear MCP into that file, so Codex only loads it when run from this repo.

Codex requires the project to be **trusted** in `~/.codex/config.toml` — untrusted projects' `.codex/config.toml` is silently ignored. The skill ensures trust is set.

## Preconditions

- Run from the project's working directory.
- The project already has a Claude Code Linear MCP configured (this skill mirrors it; it doesn't invent a name).
- The project is a git repo (Codex's default project-root marker is `.git`).

## Steps

### 1. Find the Claude Linear MCP name for this project

Claude Code can store MCP server configs in several places. Check all of these for an entry whose URL contains `mcp.linear.app`:

1. **`~/.claude.json`** (user-scoped-per-project - where `claude mcp add` without `--scope` lands). Look under `projects["<abs-project-path>"].mcpServers`. Use `python3 -c "import json; ..."` since the file is large (~250KB); don't dump it.
2. `./.mcp.json` (project-committed)
3. `./.claude/settings.json` and `./.claude/settings.local.json` (`mcpServers` key)

The server name is the key whose value has `url: "https://mcp.linear.app/..."` (e.g. `linear-freelancers-copilot`).

As a secondary signal, `./.claude/settings.local.json` may list `mcp__<name>__*` entries under `permissions.allow` - that confirms the name.

If none is found, stop and tell the user - this skill mirrors an existing Claude setup; it doesn't create one from scratch.

If multiple Linear entries exist, ask the user which to mirror.

### 2. Determine the project root

Run `git rev-parse --show-toplevel` to get the project root. If the command fails (not a git repo), stop and tell the user - Codex's project-root detection relies on `.git` by default.

All subsequent file paths are relative to this root.

### 3. Ensure the project is trusted in `~/.codex/config.toml`

Codex ignores `.codex/config.toml` in untrusted projects. Trust is declared in `~/.codex/config.toml` like:

```toml
[projects."/abs/path/to/project"]
trust_level = "trusted"
```

Check whether an entry already exists for the project root path (exact match, or any ancestor with `trust_level = "trusted"` - note: inheritance isn't documented, so prefer an exact match).

- **Entry exists, `trust_level = "trusted"`** → nothing to do.
- **Entry missing** → append one at the end of `~/.codex/config.toml`. Warn the user that this marks the project as trusted for Codex, which means Codex will load project-local config from it.

### 4. Write the MCP entry to `<project-root>/.codex/config.toml`

Create `<project-root>/.codex/` if missing. Then create or append to `<project-root>/.codex/config.toml`:

```toml
[mcp_servers.<name>]
url = "https://mcp.linear.app/mcp"
```

If `.codex/config.toml` already exists:
- If `[mcp_servers.<name>]` is already present with the same URL → nothing to do.
- If `[mcp_servers.<name>]` is present with a different URL/config → stop and show the user; don't overwrite.
- Otherwise → append (blank line before the new section).

### 5. Gitignore `.codex/` by default

Per-project Linear MCPs usually encode a workspace name you don't want in git history (e.g. client names). Default to adding `.codex/` to `.gitignore` so the config stays per-user.

- If `.gitignore` already contains `.codex/` or `.codex/config.toml` → nothing to do.
- Otherwise → append `.codex/` to `.gitignore`.

Mention this to the user so they can reverse it if they *want* to commit (e.g. for solo projects or team-wide workspace names).

### 6. Update AGENTS.md

If `~/.codex/config.toml` also has a generic `[mcp_servers.linear]` entry (global fallback), Codex may see both `linear` and `<name>` in this project. Add a short note in `AGENTS.md` (check `ls -la` in case it's a symlink to `CLAUDE.md`) under a **Linear MCP** heading:

```markdown
## Linear MCP

For this project, use the `<name>` Linear MCP server (not the generic `linear` one). This project has its own `.codex/config.toml` registering `<name>`; use that workspace.
```

Place it near other tool/integration notes. Don't duplicate the heading if it already exists - update in place.

If the user has no generic `linear` in global Codex config, this step is optional - the per-project scoping alone is usually enough.

### 7. Clean up any stale global entry (optional, user-driven)

If `~/.codex/config.toml` contains `[mcp_servers.<name>]` for this same name - e.g. because an earlier version of this skill put it there - tell the user they can now remove it since the project-local entry supersedes. **Don't auto-delete** from global config; show the line and let them decide.

### 8. Tell the user to auth the new server

Tell the user to run this from the project directory:

```
codex mcp login <name>
```

This prints a URL - they open it, auth the correct Linear workspace, and Codex caches the token. Auth is per-server-name, so other Linear servers' tokens stay separate.

## Notes

- The name must match Claude's exactly - that's the whole point. Names align across tools so the user's mental model stays consistent.
- `codex mcp add` has no `--scope` flag; it always writes to `~/.codex/config.toml`. Per-project scoping requires writing `.codex/config.toml` manually, which is what this skill does.
- Closest-to-cwd wins on conflicts: if both global and project-local declare the same `[mcp_servers.<name>]`, the project-local one takes precedence.
- Don't modify Claude's `.mcp.json` - this skill is one-way (Claude → Codex).

Same principle as the earlier post: don’t let your workflow care which vendor is running it. Symlinks where they work. Skills where they don’t.

If you’re running both Claude Code and Codex and hitting this exact problem, grab the skill and email me if it saved you an afternoon.