{"record":{"id":"6b16baed90f712ec","repo":"openai/codex","slug":"failed-to-parse-mcp-config-for-selected-plugin-p","errorCode":null,"errorMessage":"failed to parse MCP config for selected plugin `{plugin_id}` at `{path}`: {source}","messagePattern":"failed to parse MCP config for selected plugin `(.+?)` at `(.+?)`: (.+?)","errorType":"exception","errorClass":"ExecutorPluginMcpProviderError","httpStatus":null,"severity":"error","filePath":"codex-rs/ext/mcp/src/executor_plugin/provider.rs","lineNumber":41,"sourceCode":"pub(super) enum ExecutorPluginMcpProviderError {\n    #[error(\"failed to read MCP config for selected plugin `{plugin_id}` at `{path}`: {source}\")]\n    ReadConfig {\n        plugin_id: String,\n        path: PathUri,\n        #[source]\n        source: io::Error,\n    },\n    #[error(\n        \"failed to resolve MCP config path `{relative_path}` below selected plugin `{plugin_id}` at `{root}`: {source}\"\n    )]\n    InvalidConfigPath {\n        plugin_id: String,\n        root: PathUri,\n        relative_path: &'static str,\n        #[source]\n        source: PathUriParseError,\n    },\n    #[error(\"failed to parse MCP config for selected plugin `{plugin_id}` at `{path}`: {source}\")]\n    ParseConfig {\n        plugin_id: String,\n        path: PathUri,\n        #[source]\n        source: serde_json::Error,\n    },\n}\n\nimpl ExecutorPluginMcpProvider {\n    /// Returns MCP servers declared by `plugin`, bound to its environment.\n    #[tracing::instrument(name = \"mcp.executor_plugin.servers.load\", skip_all)]\n    pub(super) async fn load(\n        &self,\n        plugin: &ResolvedExecutorPlugin,\n    ) -> Result<Vec<(String, McpServerConfig)>, ExecutorPluginMcpProviderError> {\n        let ResolvedPluginLocation::Environment { root, .. } = plugin.plugin().location();\n\n        load_from_file_system(plugin.plugin(), root, plugin.file_system()).await","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/openai/codex/blob/339751715c64496cb86246bfb3935f40e309dd3d/codex-rs/ext/mcp/src/executor_plugin/provider.rs#L23-L59","documentation":"The MCP config contents (manifest-declared file, serialized inline object config, or default .mcp.json) failed to parse via parse_executor_plugin_mcp_config (serde_json). Distinct from per-server problems: malformed individual server entries are logged as warnings and skipped, so ParseConfig means the top-level document is not valid JSON or does not fit the expected config shape at all.","triggerScenarios":".mcp.json containing invalid JSON, or a top-level structure whose entries do not deserialize into McpServerConfig (wrong field types for command/args/env).","commonSituations":"Copying a .mcp.json written for the Codex CLI's top-level config format into a plugin; comments or trailing commas; schema drift between plugin SDK and host.","solutions":["Validate with jq: jq . .mcp.json inside the plugin root.","Compare against the executor-plugin MCP config shape (entries must map to McpServerConfig fields).","Fix or remove the file — an absent default file is treated as no servers.","Update plugin or host so both speak the same config schema."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// In plugin CI: fail the build on a malformed MCP config\nlet raw = std::fs::read_to_string(plugin_root.join(\".mcp.json\"))?;\nserde_json::from_str::<serde_json::Value>(&raw)?;","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate .mcp.json with jq before shipping the plugin.","Match the executor-plugin MCP schema (entries deserialize into McpServerConfig), not the CLI top-level format.","Per-server problems only warn and skip — a hard parse failure means the document itself is broken."],"tags":["rust","mcp","plugin","json","serde","codex"],"backgroundTag":"config-json-parse-error","analyzedSha":"339751715c64496cb86246bfb3935f40e309dd3d","analyzedAt":"2026-08-25T05:35:09.876Z","schemaVersion":2},"datasetVersion":"2026-08-25T06:17:31.827Z"}