Skip to content

mcp-manager

Safely manage Codex MCP server registrations with collision checks, backups, advanced-key patches, dry-run planning, and rollback.

codex-mcp-manager is a small wrapper around the official codex mcp CLI. It delegates normal add, remove, list, and get operations to Codex so the official writer and validation stay in charge, then adds the safety features that are useful for repeatable setup scripts:

  • detects name collisions before add
  • creates backups before mutating config.toml
  • records backup manifests for rollback
  • supports dry-run plans
  • patches advanced MCP table keys that codex mcp add does not expose
  • supports current auth, remote stdio placement, mixed env_vars, and per-tool approvals
  • rejects static credential headers; use environment-variable references instead
  • rejects unknown CLI flags instead of silently ignoring typos
  • treats only Codex’s explicit not-found response as absence; CLI/config/timeouts fail closed
  • hash-guards mutations and automatically restores verified pre-operation bytes on validation failure

The manager supports stdio servers and streamable HTTP servers.

Terminal window
npm install @codex-modules/mcp-manager

For local development inside this repository:

Terminal window
cd modules/mcp-manager
npm install
npm run build

Add a stdio server:

Terminal window
codex-mcp-manager add \
--name docs \
--command node \
--arg /path/to/server.js

Add a streamable HTTP server:

Terminal window
codex-mcp-manager add \
--name web \
--url https://mcp.example.com/mcp \
--bearer-token-env-var MCP_WEB_TOKEN

Use an environment-backed authorization header and a per-tool approval:

Terminal window
codex-mcp-manager add \
--name web \
--url https://mcp.example.com/mcp \
--auth oauth \
--env-http-header Authorization=MCP_AUTH_HEADER \
--tool-approval search=prompt

Configure remote stdio and mixed local/remote environment references:

Terminal window
codex-mcp-manager add \
--name remote_tools \
--command node \
--arg /path/to/server.js \
--experimental-environment remote \
--env-var LOCAL_TOKEN \
--env-var-source REMOTE_TOKEN=remote

Read a server definition from JSON:

{
"name": "github",
"url": "https://mcp.example.com/github",
"auth": "oauth",
"bearerTokenEnvVar": "GITHUB_MCP_TOKEN",
"httpHeaders": {
"X-Client": "codex"
},
"envHttpHeaders": {
"Authorization": "GITHUB_MCP_AUTH_HEADER"
},
"toolApprovals": {
"search": "prompt"
}
}
Terminal window
codex-mcp-manager plan --from github.json --json
codex-mcp-manager add --from github.json --force

Patch advanced keys under an existing [mcp_servers.<name>] table:

Terminal window
codex-mcp-manager patch github \
--set startup_timeout_sec=20 \
--set 'enabled_tools=["search","open"]' \
--tool-approval search=prompt

--set 'tools={"repo/list":{"approval_mode":"approve"}}' is also supported. Tool names are emitted as quoted TOML path segments, so names that contain / or . remain a single tool identifier.

Inspect or remove servers:

Terminal window
codex-mcp-manager list --json
codex-mcp-manager get github --json
codex-mcp-manager remove github
codex-mcp-manager doctor

Use --codex-home DIR on any command to target an isolated Codex home instead of the current user’s default ~/.codex.

import {
addServer,
doctor,
getServer,
listServers,
patchServer,
patchServerText,
plan,
removeServer,
rollback,
type ServerDef,
} from "@codex-modules/mcp-manager";
const def: ServerDef = {
name: "web",
url: "https://mcp.example.com/mcp",
auth: "oauth",
bearerTokenEnvVar: "MCP_WEB_TOKEN",
envHttpHeaders: { Authorization: "MCP_WEB_AUTH_HEADER" },
toolApprovals: { search: "prompt" },
};
await plan(def, { codexHome: "/tmp/codex-home" });
await addServer(def, { codexHome: "/tmp/codex-home", force: true });
await patchServer("web", { startup_timeout_sec: 20 }, { codexHome: "/tmp/codex-home" });
await rollback({ codexHome: "/tmp/codex-home" });

ServerDef accepts either:

  • stdio: { name, command, args?, env?, envVars?, experimentalEnvironment?, toolApprovals? }
  • HTTP: { name, url, auth?, bearerTokenEnvVar?, httpHeaders?, envHttpHeaders?, toolApprovals? }

envVars accepts strings and { name, source: "local" | "remote" } objects. A remote-source entry requires experimentalEnvironment: "remote". Definition files reject unknown fields and definitions that mix stdio and HTTP transport fields.

Do not pass plaintext bearer tokens or credential-bearing static headers. Values named bearer_token, bearer-token, or bearerToken, static Authorization, Cookie, API-key headers, and header values beginning with an authentication scheme such as Bearer are rejected. Store the secret in an environment variable and use bearerTokenEnvVar or envHttpHeaders.

Current advanced patch keys follow the official Codex config reference. environment_id is rejected with guidance to use experimental_environment; supports_parallel_tool_calls is rejected because it is not part of the current MCP config contract.

patchServerText(content, name, keys) is exported for fixture tests and tools that need to preview a table patch without touching disk.

For add and remove, the module asks the installed codex mcp command to generate or validate the operation inside a temporary isolated CODEX_HOME. It then mutates only the target server in the requested config. This prevents the Codex writer from reserializing or dropping advanced keys on unrelated MCP servers. List and get still delegate directly to the installed codex binary.

Before a mutating operation, the module hashes the expected current config and copies it into an operation-specific directory under:

<CODEX_HOME>/codex-mcp-manager-state/backups/

Each pending, committed, automatically restored, or rolled-back operation is recorded in:

<CODEX_HOME>/codex-mcp-manager-state/manifest.jsonl

patchServer is intentionally narrower than a TOML rewriter. It validates the file, inserts or replaces only the requested keys inside the selected server or tool table, validates again, and asks codex mcp get --json to parse the result. Quoted table identifiers, multi-line existing values, inline tool maps, and nested [mcp_servers.<name>.tools.<tool>] tables are handled without reserializing unrelated parts of config.toml.

Add, patch, and remove verify the expected-current hash immediately before the atomic write and validate the result through Codex afterward. A validation failure restores the verified backup automatically only when no concurrent writer has changed the result. Concurrent changes are left intact and reported instead of being overwritten.

Replacing a server intentionally replaces that server’s own table subtree; comments inside the replaced subtree are not preserved. Unrelated server tables and top-level content remain byte-preserved.

See the official Codex MCP configuration reference for the source contract used by this module.

Removing the npm package does not edit Codex configuration:

Terminal window
npm uninstall @codex-modules/mcp-manager

To undo the last change made by this module:

Terminal window
codex-mcp-manager rollback

For an isolated home:

Terminal window
codex-mcp-manager rollback --codex-home /tmp/codex-home

Rollback entries are one-use. Rollback requires the manifest target to exactly match the selected config.toml, the current hash to match the committed result, and the canonical backup to remain inside the manager’s backup directory. It refuses to overwrite changes made after the operation.

If the CLI is unavailable, restore manually by copying the appropriate verified backup from <CODEX_HOME>/codex-mcp-manager-state/backups/<operation-id>/ over <CODEX_HOME>/config.toml. The manifest at <CODEX_HOME>/codex-mcp-manager-state/manifest.jsonl records which file each backup belongs to.

Schema mapping was informed by jtianling/mcps-manager (MIT). Writer and backup patterns were informed by Brightwing-Systems-LLC/mcp-manager (MIT).