One MCP Configuration for Codex, Claude, Cursor, and Copilot with chezmoi
Source: Dev.to
When you use multiple coding agents on several machines, MCP configuration drift is inevitable—unless you make one file the source of truth.
The following guide shows a practical, reproducible setup for:
- Codex
- Claude Code
- Cursor
- GitHub Copilot (including VS Code and Copilot‑coding‑agent scenarios)
Core Idea
- Keep one canonical MCP manifest in your
chezmoisource state. - Generate each tool’s native config format from that manifest.
- Let
chezmoimanage symlinks / templates and machine‑specific values.
All four tools model MCP servers with the same conceptual fields:
| Field | Meaning |
|---|---|
| Server name | Identifier used by the tool |
| Transport type | stdio (local) vs. remote http/sse |
| Command + args + env | For local servers |
| URL + headers / auth | For remote servers |
What differs is file location and schema shape.
Instead of editing four formats manually, you maintain one normalized model and project it into each target file.
Tool‑Specific Storage Details
| Tool | Where MCP lives | Format | Notes |
|---|---|---|---|
| Codex | ~/.codex/config.toml (optional project overrides in .codex/config.toml) | TOML | Entries under [mcp_servers.] |
| Claude | ~/.claude/settings.json, .claude/settings.json, .claude/settings.local.json (MCP config in ~/.claude.json for user/local scope and .mcp.json for project scope) | JSON | Treat .mcp.json as the repo‑shareable MCP surface; keep secrets outside the repo |
| Cursor | ~/.cursor/mcp.json (project: .cursor/mcp.json) | JSON | Uses mcpServers array; supports command‑ and URL‑based MCP |
| VS Code | Workspace: .vscode/mcp.json; User profile: mcp.json | JSON | First‑class MCP feature |
| Copilot coding agent | ~/.copilot/mcp-config.json (or equivalent) | JSON | Same schema as VS Code MCP, with explicit type (local, stdio, http, sse) |
Canonical MCP Manifest
Create a single YAML file that describes all servers. Example:
# dot_config/mcp/servers.yaml
servers:
github:
transport: http
url: "https://api.githubcopilot.com/mcp/"
headers:
Authorization: "Bearer ${GITHUB_TOKEN}"
filesystem:
transport: stdio
command: "npx"
args: ["-y", "@modelcontextprotocol/server-filesystem", "/Users/lukas"]
env:
NODE_NO_WARNINGS: "1"
Tip: Store secrets (
${GITHUB_TOKEN}) in encrypted/ private files (see Security below).
Directory Layout (chezmoi source state)
~/.local/share/chezmoi/
├─ .chezmoitemplates/
│ └─ mcp/
│ ├─ codex-config.toml.tmpl
│ ├─ claude-mcp.json.tmpl
│ ├─ cursor-mcp.json.tmpl
│ ├─ vscode-mcp.json.tmpl
│ └─ copilot-mcp-config.json.tmpl
├─ dot_config/
│ └─ mcp/
│ └─ servers.yaml ← canonical model (committed)
├─ dot_codex/
│ └─ config.toml.tmpl
├─ dot_claude/
│ └─ mcp_servers.json.tmpl
├─ dot_cursor/
│ └─ mcp.json.tmpl
├─ dot_vscode/
│ └─ mcp.json.tmpl
└─ dot_copilot/
└─ mcp-config.json.tmpl
- Files under
.chezmoitemplatesare reusable snippets. - Templates are recognized by the
.tmplsuffix (or by living inside.chezmoitemplates). - Machine facts such as
.chezmoi.osand.chezmoi.hostnameare available inside templates.
Example Template Logic
{{- /* Render internal server only on work laptop */ -}}
{{- if eq .chezmoi.hostname "work-laptop" -}}
{
"name": "internal",
"type": "http",
"url": "https://internal.example.com/mcp/",
"headers": {
"Authorization": "Bearer ${INTERNAL_TOKEN}"
}
}
{{- end -}}
You can also vary filesystem roots, company‑only servers, etc., based on .chezmoi.os, .chezmoi.hostname, or any custom fact.
Source‑State Attributes (chezmoi)
| Prefix | Purpose |
|---|---|
symlink_ | Create a symlink target |
private_ | Mark file as private (restrict permissions) |
encrypted_ | Encrypt with age/gpg (ideal for tokens, headers) |
Recommended split
- Committed –
servers.yaml(topology, non‑secret data) - Encrypted / private – per‑machine secrets (tokens, passwords)
Render env‑var references (${GITHUB_TOKEN}) into the final tool configs.
Transformation Rules (once, in templates)
| Canonical field | Codex (TOML) | Claude / Cursor / VS Code / Copilot (JSON) |
|---|---|---|
transport: stdio | command, args, env under [mcp_servers.] | command, args, env, type: "stdio" |
transport: http (or sse) | url, headers under [mcp_servers.] | url, headers, type: "http" (or "sse") |
| Optional per‑tool keys | Avoid unless absolutely required | Keep in an overrides map inside servers.yaml if needed |
Applying the Configuration
# From your chezmoi repo root
chezmoi apply
chezmoi will:
- Render each template using the canonical
servers.yaml(and any encrypted/private files). - Place the resulting files in the appropriate locations:
~/.codex/config.toml ← MCP block
~/.claude.json or .mcp.json ← projection
~/.cursor/mcp.json
.vscode/mcp.json
~/.copilot/mcp-config.json
Never edit the generated targets directly – always modify the source model or templates and re‑run
chezmoi apply.
Security & Reproducibility
- Strict reproducibility – generate all config files from templates; source‑only edits.
- Secret handling – keep tokens in
encrypted_files or external secret managers; reference them via environment variables in the templates. - Version control – only the canonical model (
servers.yaml) and template files are committed.
Quick Reference Links
- chezmoi – templating guide, machine facts, source‑state attributes
- OpenAI Codex MCP – advanced config docs
- Anthropic Claude Code MCP – settings overview
- Cursor MCP – official docs page confirming first‑class MCP support
- VS Code MCP – workspace (
.vscode/mcp.json) and user config - GitHub Copilot MCP – coding‑agent configuration
TL;DR
- One canonical YAML model (
servers.yaml). - Templates for each tool’s native format.
- chezmoi manages rendering, symlinks, and machine‑specific overrides (private/encrypted).
Result: Consistent, drift‑free MCP configuration across Codex, Claude, Cursor, and Copilot without locking yourself into any single vendor schema.
# Copilot coding agent MCP
## skills-sync agent storage map