{"record":{"id":"0f0c17381eb2f8af","repo":"openai/codex","slug":"command-is-required","errorCode":null,"errorMessage":"command is required","messagePattern":"command is required","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"codex-rs/cli/src/mcp_cmd.rs","lineNumber":360,"sourceCode":"        name,\n        transport_args,\n    } = add_args;\n\n    validate_server_name(&name)?;\n\n    let codex_home = find_codex_home().context(\"failed to resolve CODEX_HOME\")?;\n    let mut servers = load_global_mcp_servers(&codex_home)\n        .await\n        .with_context(|| format!(\"failed to load MCP servers from {}\", codex_home.display()))?;\n\n    let (transport, oauth_client_id, client_registration, oauth_resource) = match transport_args {\n        AddMcpTransportArgs {\n            stdio: Some(stdio), ..\n        } => {\n            let mut command_parts = stdio.command.into_iter();\n            let command_bin = command_parts\n                .next()\n                .ok_or_else(|| anyhow!(\"command is required\"))?;\n            let command_args: Vec<String> = command_parts.collect();\n\n            let env_map = if stdio.env.is_empty() {\n                None\n            } else {\n                Some(stdio.env.into_iter().collect::<HashMap<_, _>>())\n            };\n            (\n                McpServerTransportConfig::Stdio {\n                    command: command_bin,\n                    args: command_args,\n                    env: env_map,\n                    env_vars: Vec::new(),\n                    cwd: None,\n                },\n                None,\n                McpOAuthClientRegistration::Auto,\n                None,","sourceCodeStart":342,"sourceCodeEnd":378,"githubUrl":"https://github.com/openai/codex/blob/339751715c64496cb86246bfb3935f40e309dd3d/codex-rs/cli/src/mcp_cmd.rs#L342-L378","documentation":"For `codex mcp add <name>` with the stdio transport, run_add takes stdio.command (a Vec<String> built from --command) and requires a first element to use as the program. An empty command list bails with `command is required` before any config is written.","triggerScenarios":"`codex mcp add my-server --command` with no values following the flag, or a script expanding an unset variable into the command slot so the parsed list is empty (`--command $BIN` with BIN unset and word splitting dropping it).","commonSituations":"Wrapper scripts building the command from variables that came back empty; CI jobs injecting the program name from a missing env var; copy-paste that kept the flag but dropped the program.","solutions":["Pass a program plus its args: `codex mcp add fs --command npx -y @modelcontextprotocol/server-filesystem /tmp`.","Fail fast on unset variables: `set -u` plus `: \"${BIN:?BIN must be set}\"` before invoking codex.","Verify the program resolves: `command -v \"$BIN\"`."],"exampleFix":"# before\ncodex mcp add fs --command            # flag with no program\ncodex mcp add fs --command $BIN       # $BIN unset -> empty command list\n# after\ncodex mcp add fs --command npx -y @modelcontextprotocol/server-filesystem /tmp","handlingStrategy":"validation","validationCode":"add_mcp_stdio() {\n  local name=\"$1\"; shift\n  if [ $# -eq 0 ] || [ -z \"$1\" ]; then\n    echo 'command is required: program name first, then args' >&2; return 2\n  fi\n  command -v \"$1\" >/dev/null 2>&1 || echo \"warn: '$1' not found on PATH\" >&2\n  codex mcp add \"$name\" --command \"$@\"\n}","typeGuard":null,"tryCatchPattern":"if ! codex mcp add fs --command \"$@\" 2>err.log; then\n  grep -q 'command is required' err.log && { echo 'usage: --command <program> [args...]' >&2; exit 2; }\n  exit 1\nfi","preventionTips":["Quote every expansion feeding --command so empty vars surface as errors, not silent drops","Validate argv is non-empty before calling codex from scripts","Prefer explicit literals over variable indirection for the program name"],"tags":["cli","codex","mcp","stdio","argument-validation"],"backgroundTag":"missing-required-argument","analyzedSha":"339751715c64496cb86246bfb3935f40e309dd3d","analyzedAt":"2026-08-25T05:35:09.876Z","schemaVersion":2},"datasetVersion":"2026-08-25T06:17:31.827Z"}