DEV Community

Lukas Wolfsteiner
Lukas Wolfsteiner

Posted on

One MCP Configuration for Codex, Claude, Cursor, and Copilot with chezmoi

If you use multiple coding agents across multiple machines, MCP configuration drift is unavoidable unless you make one file the source of truth.

This guide shows a practical setup for:

  • Codex
  • Claude Code
  • Cursor
  • GitHub Copilot (including VS Code and Copilot coding agent scenarios)

The core idea is simple:

  1. Keep one canonical MCP manifest in your chezmoi source state.
  2. Generate each tool's native config format from that manifest.
  3. Let chezmoi manage symlinks/templates and machine-specific values.

Why this works

All four tools model MCP servers with the same conceptual fields:

  • Server name
  • Transport type (stdio vs remote HTTP/SSE-like)
  • Command + args + env for local servers
  • URL + headers/auth for remote servers

What differs is file location and schema shape.

So instead of manually editing four formats, you maintain one normalized model and project it into each target file.

What each tool expects today

Codex

Codex stores MCP inside config.toml, typically at ~/.codex/config.toml, with optional project overrides in .codex/config.toml for trusted projects.

MCP entries are under [mcp_servers.<name>] and support both local command servers and remote URL servers.

Claude Code

Claude settings are split across ~/.claude/settings.json, .claude/settings.json, and .claude/settings.local.json, but MCP server configuration is associated with ~/.claude.json for user/local scope and .mcp.json for project scope.

In practice, you can treat .mcp.json as the repository-shareable MCP surface and keep secrets/user-only material outside repo.

Cursor

Cursor uses JSON with mcpServers and supports command- and URL-based MCP installations.

The official docs page confirms MCP as a first-class feature and transport diversity; path specifics (~/.cursor/mcp.json, .cursor/mcp.json) are consistent with the validated storage map you linked.

GitHub Copilot / VS Code

There are two adjacent configuration worlds:

  • VS Code MCP config: mcp.json (workspace commonly at .vscode/mcp.json, plus user profile config)
  • Copilot coding agent MCP config: JSON with mcpServers and explicit type (local, stdio, http, sse), and documented reuse from VS Code MCP configuration patterns

For a chezmoi setup, it is practical to generate:

  • .vscode/mcp.json for local editor agent workflows
  • .copilot/mcp-config.json (or equivalent copilot-target file in your model) for coding-agent workflows where needed

Common ground: a normalized MCP model

Use one canonical data file, for example in chezmoi source state:

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"
Enter fullscreen mode Exit fullscreen mode

Then render adapters per tool.

chezmoi layout that scales

A practical structure:

~/.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
  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
Enter fullscreen mode Exit fullscreen mode

Use .chezmoitemplates for reusable snippets and avoid duplicating mapping logic.

Templating pattern

chezmoi treats files as templates when they have .tmpl suffix (or live under .chezmoitemplates), and exposes machine facts like .chezmoi.os and .chezmoi.hostname.

That lets you do things like:

  • Different filesystem roots on macOS vs Linux
  • Company-only servers on work laptops
  • Personal-only servers on home machines

Example gate in template:

{{- if eq .chezmoi.hostname "work-laptop" -}}
# render internal MCP server
{{- end -}}
Enter fullscreen mode Exit fullscreen mode

Symlinks and private data

chezmoi source-state attributes are important for this problem:

  • symlink_ to create symlink targets
  • private_ for sensitive files/permissions
  • encrypted_ + age/gpg encryption for secret-bearing material

This is ideal for MCP because tokens and headers frequently differ by machine/account.

Recommended split:

  • Keep server topology in a committed template/data file
  • Keep secrets in encrypted/private files or external secret providers
  • Render env var references into final tool configs

Mapping rules (the critical part)

Define clear transformation rules once:

  1. transport: stdio

    • Codex: TOML command/args/env under [mcp_servers.<name>]
    • Claude/Cursor/VSCode/Copilot: JSON object with command args env and tool-specific type field if required
  2. transport: http (or sse)

    • Codex: url (+ auth/header fields)
    • JSON tools: url, headers, and possibly type (http/sse)
  3. Optional per-tool fields

    • Keep them in an overrides map in canonical YAML if absolutely necessary
    • Avoid polluting the base model with vendor-only keys unless needed

Suggested generation flow

  1. Edit canonical servers.yaml
  2. Run chezmoi apply
  3. Let templates produce:
    • ~/.codex/config.toml MCP block
    • ~/.claude.json or project .mcp.json projection
    • ~/.cursor/mcp.json
    • .vscode/mcp.json
    • ~/.copilot/mcp-config.json (if used in your setup)

If you want strict reproducibility, generate all from templates only and never edit generated targets directly.

Real-world caveats

  • Copilot and Cursor MCP features are evolving quickly; treat adapters as projection layers, not permanent schemas.
  • Claude has multiple config surfaces (settings.json, ~/.claude.json, .mcp.json), so be explicit about which one your team standardizes on.
  • Project-level files (.vscode/mcp.json, .mcp.json, .codex/config.toml) are great for shared defaults; user-level files should hold personal secrets and machine specifics.

Bottom line

The durable strategy is not "pick one tool format."

It is:

  • One canonical MCP model
  • Many generated vendor configs
  • chezmoi templates + machine facts + private/encrypted files to keep it safe and portable

That gives you consistency across Codex, Claude, Cursor, and Copilot without locking yourself to one vendor schema.

Sources

Top comments (0)