openai/codex · error · ExecutorPluginMcpProviderError
failed to parse MCP config for selected plugin `{plugin_id}`
Error message
failed to parse MCP config for selected plugin `{plugin_id}` at `{path}`: {source} What it means
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.
Source
Thrown at codex-rs/ext/mcp/src/executor_plugin/provider.rs:41
pub(super) enum ExecutorPluginMcpProviderError {
#[error("failed to read MCP config for selected plugin `{plugin_id}` at `{path}`: {source}")]
ReadConfig {
plugin_id: String,
path: PathUri,
#[source]
source: io::Error,
},
#[error(
"failed to resolve MCP config path `{relative_path}` below selected plugin `{plugin_id}` at `{root}`: {source}"
)]
InvalidConfigPath {
plugin_id: String,
root: PathUri,
relative_path: &'static str,
#[source]
source: PathUriParseError,
},
#[error("failed to parse MCP config for selected plugin `{plugin_id}` at `{path}`: {source}")]
ParseConfig {
plugin_id: String,
path: PathUri,
#[source]
source: serde_json::Error,
},
}
impl ExecutorPluginMcpProvider {
/// Returns MCP servers declared by `plugin`, bound to its environment.
#[tracing::instrument(name = "mcp.executor_plugin.servers.load", skip_all)]
pub(super) async fn load(
&self,
plugin: &ResolvedExecutorPlugin,
) -> Result<Vec<(String, McpServerConfig)>, ExecutorPluginMcpProviderError> {
let ResolvedPluginLocation::Environment { root, .. } = plugin.plugin().location();
load_from_file_system(plugin.plugin(), root, plugin.file_system()).awaitView on GitHub (pinned to 339751715c)
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.
Defensive patterns
Strategy: validation
Validate before calling
// In plugin CI: fail the build on a malformed MCP config
let raw = std::fs::read_to_string(plugin_root.join(".mcp.json"))?;
serde_json::from_str::<serde_json::Value>(&raw)?; Prevention
- 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.
When it happens
Trigger: .mcp.json containing invalid JSON, or a top-level structure whose entries do not deserialize into McpServerConfig (wrong field types for command/args/env).
Common situations: 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.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- failed to parse app config for selected plugin `{plugin_id}`
- failed to read MCP config for selected plugin `{plugin_id}`
- failed to resolve MCP config path `{relative_path}` below se
- queued submission payload is invalid: {0}
- failed to read app config for selected plugin `{plugin_id}`
AI-assisted analysis of openai/codex@339751715c (2026-08-25).
Data as JSON: /api/errors/6b16baed90f712ec.
Report an issue: GitHub.