Plugin manifest cannot declare user-supplied config, leaving credentials with no input path

Open
#36,854 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
35/100
Issue type
Feature
Clarity
Mostly clear
Activity status
Quiet
Tech stack
rust
Domain
cli

Research direction

Start by tracing RawPluginManifest, PluginMcpServerConfig, and create_env_for_mcp_server to understand the current manifest, user-config, and environment-variable boundaries. Review the existing authentication ON_INSTALL and ON_USE policies, then define how declared inputs, sensitive-value storage, prompting, and substitution should work. Done requires an agreed end-to-end credential path rather than relying only on the host environment.

Written by the indexing model from the issue text.

Description

auth CLI config enhancement mcp skills

A plugin whose MCP server needs a credential — an API key, a token, a client secret — has no way to ask the user for it, and the user has no way to supply it through Codex.

Where it breaks

Two independent gaps close off every path:

The manifest cannot declare a config input. RawPluginManifest accepts name, version, description, keywords, skills, mcp_servers, apps, hooks, and interface. There is no field for user-supplied values, so a plugin cannot state that it needs a secret, let alone have Codex prompt for one at install time.

User config cannot fill the gap either. PluginMcpServerConfig carries only enabled, default_tools_approval_mode, enabled_tools, and the tool deny-list. Its doc comment is explicit about why:

This intentionally excludes transport settings: plugin manifests own how the MCP server is launched, while user config owns enablement and tool policy.

So [plugins."name@marketplace".mcp_servers.server] in config.toml cannot add env or env_vars.

That leaves exactly one channel: env_vars forwarding from the host process environment, resolved in create_env_for_mcp_server via env::var_os. The plugin names the variables; the user must arrange for them to exist in the environment Codex itself was started in.

Why that channel is not sufficient

  • It is invisible. Nothing in codex plugin add or /plugins tells the user which variables to set. They have to read the plugin's README, or the manifest.
  • It fails silently by default. Install the plugin, restart, and the server dies on startup with whatever error it emits for missing config. Nothing connects that back to "you needed to export three variables."
  • Shell config does not cover GUI launches. ~/.zshrc only applies to interactive shells; ~/.zshenv covers non-interactive ones too, but neither is read when Codex is launched from Spotlight or the Dock, because no shell is involved. Getting a variable to a GUI-launched Codex means launchctl setenv or a LaunchAgent — which puts the secret in the environment of every GUI application on the machine.
  • It pushes secrets into plaintext. The natural place to put an export is a dotfile, which people back up and commit. Reading from the system keychain is possible but every plugin author has to document that dance themselves.

What Claude Code does

Its plugin manifest has a userConfig block: each entry declares type, title, description, and optionally sensitive and required. The client prompts at enable time, stores sensitive values in the OS keychain rather than settings, and substitutes them into the MCP server config as ${user_config.KEY}.

A plugin shipping the same MCP server to both clients ends up with two manifests that diverge on exactly this point — Claude Code prompts and stores in the keychain, Codex needs the user to edit a shell file and restart.

Suggestion

Let the manifest declare inputs, and let their values reach the MCP server config:

{
  "userConfig": {
    "api_token": {
      "type": "string",
      "title": "API token",
      "description": "Found under Settings → Developer",
      "sensitive": true,
      "required": true
    }
  },
  "mcpServers": {
    "example": {
      "command": "npx",
      "args": ["-y", "example-mcp"],
      "env": { "EXAMPLE_TOKEN": "${user_config.api_token}" }
    }
  }
}

Prompting could reuse the existing authentication: ON_INSTALL / ON_USE policy already present on marketplace entries. Storage for sensitive: true values ideally goes to the OS keychain; even config.toml would be an improvement over "figure out your own shell and launchd setup."

A narrower fix that would also help: allow env and env_vars in PluginMcpServerConfig, so a user can at least supply credentials in config.toml without touching their shell. That contradicts the current doc comment, but the boundary it draws — manifests own launching, user config owns policy — leaves credentials with no owner at all.

Context

Hit this shipping a WeCom MCP server as a plugin to both clients. The Claude Code side is a dialog with three fields. The Codex side is a README section explaining ~/.zshenv, security find-generic-password, and why the variables have to exist before Codex starts.

Versions: codex-cli 0.146.0, source read at main.

Dominant language
Rust
Stars
125k
Forks
19.5k
Avg merge
1m
Merged PRs (30d)
1k

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from openai/codex

All issues in openai/codex

Similar issues

More Rust issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.