Codeman logocodeman GitHub →

Share MCP servers between Claude Code, Codex, Gemini CLI and OpenCode

Updated 2026-10-10

On this pageWhere each CLI keeps user-level MCP serversThe same two servers in all four formatsAdding them from the command lineSecrets, environment variables and headersProject-level files and precedenceMoving the config somewhere elseTraps when translatingHow Codeman handles it

There is no shared MCP file. Each CLI reads its own user-level config in its own format: Claude Code uses ~/.claude.json, Codex uses ~/.codex/config.toml, Gemini CLI uses ~/.gemini/settings.json and OpenCode uses ~/.config/opencode/opencode.json. To use the same servers everywhere, translate each one into all four formats, using each CLI's own variable syntax to keep secrets out of the files where it allows. The tables and examples below reflect the docs as of October 2026.

Where each CLI keeps user-level MCP servers

CLI User-level file Format Top-level key Add command Relocation env var
Claude Code ~/.claude.json JSON mcpServers claude mcp add --scope user CLAUDE_CONFIG_DIR
Codex ~/.codex/config.toml TOML [mcp_servers.<name>] codex mcp add CODEX_HOME
Gemini CLI ~/.gemini/settings.json JSON mcpServers gemini mcp add -s user GEMINI_CLI_HOME
OpenCode ~/.config/opencode/opencode.json JSON or JSONC mcp opencode mcp add (guided) XDG_CONFIG_HOME

Sources: Claude Code's MCP docs, Codex's MCP page and command reference, Gemini CLI's MCP server docs and OpenCode's MCP servers, config and CLI pages.

Watch the defaults. ~/.claude.json also holds your sign-in session and per-project state, and Claude Code writes it itself; plain claude mcp add uses local scope, which stores the server under the current project's entry and loads it only there. gemini mcp add defaults to project scope (.gemini/settings.json). codex mcp add always writes ~/.codex/config.toml, and opencode mcp add walks you through a local or remote server.

The same two servers in all four formats

One stdio server (npx -y example-mcp-server, which needs EXAMPLE_API_KEY) and one remote server at https://mcp.example.com/mcp that wants an Authorization: Bearer header. The names use hyphens, not underscores (see traps).

Claude Code (~/.claude.json, top level):

{
  "mcpServers": {
    "example": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "example-mcp-server"],
      "env": { "EXAMPLE_API_KEY": "${EXAMPLE_API_KEY}" }
    },
    "example-remote": {
      "type": "http",
      "url": "https://mcp.example.com/mcp",
      "headers": { "Authorization": "Bearer ${EXAMPLE_TOKEN}" }
    }
  }
}

Codex (~/.codex/config.toml):

[mcp_servers.example]
command = "npx"
args = ["-y", "example-mcp-server"]
env_vars = ["EXAMPLE_API_KEY"]          # forward it from the environment Codex runs in

[mcp_servers.example-remote]
url = "https://mcp.example.com/mcp"
bearer_token_env_var = "EXAMPLE_TOKEN"  # sent as Authorization: Bearer <value>

Gemini CLI (~/.gemini/settings.json):

{
  "mcpServers": {
    "example": {
      "command": "npx",
      "args": ["-y", "example-mcp-server"],
      "env": { "EXAMPLE_API_KEY": "<your key>" }
    },
    "example-remote": {
      "type": "http",
      "url": "https://mcp.example.com/mcp",
      "headers": { "Authorization": "Bearer <your token>" }
    }
  }
}

OpenCode (~/.config/opencode/opencode.json):

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "example": {
      "type": "local",
      "command": ["npx", "-y", "example-mcp-server"],
      "environment": { "EXAMPLE_API_KEY": "{env:EXAMPLE_API_KEY}" },
      "enabled": true
    },
    "example-remote": {
      "type": "remote",
      "url": "https://mcp.example.com/mcp",
      "headers": { "Authorization": "Bearer {env:EXAMPLE_TOKEN}" },
      "oauth": false,
      "enabled": true
    }
  }
}

OpenCode tries OAuth automatically on remote servers, and its docs say to set "oauth": false for a server that uses an API key instead.

Adding them from the command line

# Claude Code: keep another option between --env and the name
claude mcp add --env EXAMPLE_API_KEY=sk-123 --scope user --transport stdio example -- npx -y example-mcp-server
claude mcp add --scope user --transport http example-remote https://mcp.example.com/mcp --header "Authorization: Bearer sk-456"

# Codex
codex mcp add example --env EXAMPLE_API_KEY=sk-123 -- npx -y example-mcp-server
codex mcp add example-remote --url https://mcp.example.com/mcp --bearer-token-env-var EXAMPLE_TOKEN

# Gemini CLI: arguments that start with a dash go after --
gemini mcp add -e EXAMPLE_API_KEY=sk-123 -s user example npx -- -y example-mcp-server
gemini mcp add -H "Authorization: Bearer sk-456" -s user -t http example-remote https://mcp.example.com/mcp

# OpenCode
opencode mcp add

Claude Code reads a name placed directly after --env as another KEY=value pair and rejects it. Check the result with each CLI's mcp list.

These commands store the literal values you type. To keep a variable reference in Claude Code, pass single-quoted JSON so the shell leaves ${...} alone: claude mcp add-json --scope user example '{"type":"stdio","command":"npx","args":["-y","example-mcp-server"],"env":{"EXAMPLE_API_KEY":"${EXAMPLE_API_KEY}"}}'. That is also safer than editing ~/.claude.json by hand while Claude Code is rewriting it.

Secrets, environment variables and headers

CLI Literal values Reference to a variable
Claude Code env, headers ${VAR} or ${VAR:-default} in command, args, env, url, headers
Codex env, http_headers env_vars (forward), bearer_token_env_var, env_http_headers (header name to variable name)
Gemini CLI env, headers $VAR or ${VAR} in env, with the caveat below
OpenCode environment, headers {env:VAR} in config values, {file:path} for a file's contents

Sources: Claude Code's variable expansion, Codex's config reference, Gemini CLI's environment variable expansion and OpenCode's variable substitution.

Unset variables behave differently. Claude Code keeps the unexpanded ${VAR} text and warns in claude mcp list. Gemini CLI and OpenCode substitute an empty string. Claude Code also reads its own and your cloud provider's credentials (such as ANTHROPIC_API_KEY) as empty inside a remote server's url and headers, so copy such a value into a variable with a name of your own.

The Gemini caveat: it redacts inherited variables whose names match *TOKEN*, *KEY*, *SECRET*, *PASSWORD* and similar, and in v0.63.0 $VAR references are expanded from that redacted environment: a repository test asserts that $MY_AWS_TOKEN does not expand to the secret. For such a name, write the value into env and protect the file. More generally, do not count on a stdio server inheriting secrets from your shell in Codex (list them in env_vars) or Gemini CLI.

Project-level files and precedence

Moving the config somewhere else

Traps when translating

How Codeman handles it

Codeman has an opt-in MCP server sync, in the MCP servers group of Settings → Agents & CLIs (since 1.34.0). It is off by default, synced across devices and admin only in multi-user mode. Turn on Enable MCP server sync and save, then Preview shows what would change and Sync now applies it. Details are in Settings Reference.

Over the API it is GET /api/mcp-sync (dry run) and POST /api/mcp-sync (apply), both 403 while the setting is off; results carry server names only, never env values or headers (HTTP API). For running these CLIs side by side on one project, see Run Claude Code, Codex, Gemini CLI and other agents side by side and Agent CLIs.