openai/codex · error · ExecutorPluginMcpProviderError

failed to read MCP config for selected plugin `{plugin_id}`

Error message

failed to read MCP config for selected plugin `{plugin_id}` at `{path}`: {source}

What it means

ExecutorPluginMcpProvider::load reads the plugin's MCP config — the manifest's paths.mcp_servers file, or the default <plugin_root>/.mcp.json. ReadConfig wraps the io error. Note the asymmetry: NotFound on the DEFAULT .mcp.json returns Ok(vec![]) (no servers), so ReadConfig means either the manifest-declared path failed, or a non-NotFound error (permissions, transport) hit the default path.

Source

Thrown at codex-rs/ext/mcp/src/executor_plugin/provider.rs:24

use codex_plugin::PluginResourceLocator;
use codex_plugin::ResolvedPlugin;
use codex_plugin::ResolvedPluginLocation;
use codex_plugin::manifest::PluginManifestMcpServers;
use codex_utils_path_uri::PathUri;
use codex_utils_path_uri::PathUriParseError;
use std::io;
use thiserror::Error;

const DEFAULT_MCP_CONFIG_FILE: &str = ".mcp.json";

/// Loads MCP declarations from resolved plugins through their owning executor.
#[derive(Clone, Copy, Debug, Default)]
pub(super) struct ExecutorPluginMcpProvider;

/// Failure to load an executor plugin's MCP declarations.
#[derive(Debug, Error)]
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 {

View on GitHub (pinned to 339751715c)

Solutions

  1. Confirm the file at the printed path exists and is readable in the plugin environment.
  2. If the plugin has no MCP servers, remove the paths.mcp_servers manifest entry — an absent default .mcp.json loads as empty.
  3. Fix the manifest path or repackage the plugin.
  4. Check executor environment connectivity when the io source is a transport error.
Defensive patterns

Strategy: try-catch

Try / catch

match mcp_provider.load(&plugin).await {
    Ok(servers) => servers,
    Err(ExecutorPluginMcpProviderError::ReadConfig { plugin_id, path, source }) => {
        tracing::warn!(%plugin_id, %path, %source, "plugin MCP config unreadable; skipping");
        Vec::new()
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Manifest declares paths.mcp_servers pointing at a missing or unreadable file; or the default .mcp.json exists but reading it fails with permission or executor transport errors.

Common situations: Plugin manifest references an MCP config that is not shipped; wrong file mode bits inside the plugin environment; remote executor environment unreachable.

Related errors


AI-assisted analysis of openai/codex@339751715c (2026-08-25). Data as JSON: /api/errors/98a0e9e7459d6130. Report an issue: GitHub.