🌟

Codex CLI 完全ガイド:codex exec での MCP 起動エラーと対処法

に公開

はじめに

Codex のヘッドレスモードである codex exec から Model Context Protocol (MCP) サーバーを立ち上げたところ、ログに次のようなメッセージが連続して表示されるケースがあります。

ERROR codex_core::mcp_connection_manager: new_stdio_client use_rmcp_client: false program: "uvx" ...
ERROR codex_core::mcp_connection_manager: new_stdio_client use_rmcp_client: false program: "npx" ...

実際にコードをたどると、これは codex-rs/core/src/mcp_connection_manager.rs:112info! ログが標準エラーに出力されているだけで、MCP 起動自体は成功していることが確認できました。

// codex-rs/core/src/mcp_connection_manager.rs
info!(
    "new_stdio_client use_rmcp_client: {use_rmcp_client} program: {program:?} args: {args:?} env: {env:?} params: {params:?} startup_timeout: {startup_timeout:?}"
);

しかし codex exec 環境では別の要因によって本当に失敗することがあるため、原因・再現シナリオ・解決法を以下に詳しくまとめます。

codex exec を使うシーン

codex exec は TUI を持たないバッチ実行向けのコマンドです。CI/CD、外部スケジューラ、ChatOps など 人の承認待ちを挟まずに Codex に作業を任せたい場面で活用されます。このため、デフォルトでは承認ポリシーが AskForApproval::Never に固定され、ユーザーに確認を求めずにコマンドやファイル操作を進めます。

実装は codex-rs/exec/src/lib.rs:82 付近で確認できます(抜粋)。

// codex-rs/exec/src/lib.rs
let overrides = ConfigOverrides {
    model,
    review_model: None,
    config_profile,
    // この CLI はヘッドレスなので承認を挟めない
    approval_policy: Some(AskForApproval::Never),
    sandbox_mode,
    cwd: cwd.map(|p| p.canonicalize().unwrap_or(p)),
    model_provider,
    codex_linux_sandbox_exe,
    base_instructions: None,
    include_plan_tool: Some(include_plan_tool),
    include_apply_patch_tool: None,
    include_view_image_tool: None,
    show_raw_agent_reasoning: oss.then_some(true),
    tools_web_search_request: None,
};

発生する真のエラー

codex exec + MCP の組み合わせで本当に失敗する代表的な要因は次の 2 点です。

  1. codex exec がネットワークを遮断した状態で uvxnpx を起動し、必要なリポジトリからの取得に失敗する。
  2. キャッシュディレクトリやワークスペース外への書き込みが禁止されたまま uvx がセットアップを試みてタイムアウトする。

codex-rs/mcp-client/src/mcp_client.rs:224 にある request timed out のエラーがこの状況を示します。

// codex-rs/mcp-client/src/mcp_client.rs
Err(_) => {
    let mut guard = self.pending.lock().await;
    guard.remove(&id);
    return Err(anyhow!("request timed out"));
}

原因詳説

  • codex exec はヘッドレスであるため、承認ダイアログを出せないAskForApproval::Never 固定(前掲のソース参照)。
  • --sandbox workspace-write を指定しても、ネットワークはデフォルトでブロックcodex-rs/protocol/src/protocol.rs:302 を見ると、Workspace Write モードは network_access: false で作られることがわかります。
// codex-rs/protocol/src/protocol.rs
pub fn new_workspace_write_policy() -> Self {
    SandboxPolicy::WorkspaceWrite {
        writable_roots: vec![],
        network_access: false,
        exclude_tmpdir_env_var: false,
        exclude_slash_tmp: false,
    }
}
  • Workspace Write サンドボックスは cwd と一部の TMP しか書き込みできないため、uvx が利用するキャッシュディレクトリ(~/.cache, ~/.uv など)へのアクセスが拒否される。
  • uvx / npx は最初の起動時にリソース取得+キャッシュ作成を行う。この処理が進めないと MCP の initialize リクエストがタイムアウトし、上記のエラーになる。

解決策

  1. ネットワークと書き込み先を明示的に許可 する。
  2. MCP サーバーの初期化タイムアウトを延長 する。
  3. ログのノイズをフィルタリング する。(成功時でも ERROR 表示が残るため)

以下のコマンドでは、それぞれを -c オプションと RUST_LOG で上書きしています。パスは自分の環境に合わせて読み替えてください。

RUST_LOG=warn,codex_core::mcp_connection_manager=off \
  codex exec \
    --experimental-json \
    --sandbox workspace-write \
    -c 'sandbox_workspace_write={network_access=true,writable_roots=["/path/to/.cache","/path/to/.uv"]}' \
    -c mcp_servers.serena.startup_timeout_sec=30 \
    --cd "/path/to/workspace" \
    resume <SESSION_ID> "こんにちは"

コマンドのポイント

  • RUST_LOG=warn,codex_core::mcp_connection_manager=off … MCP 管理モジュールからの冗長なエラーログを抑止し、他の WARN 以上だけを表示。
  • --experimental-json--json のエイリアスであり、どちらを指定しても同じ JSONL 出力モードになります。CLI 定義は codex-rs/exec/src/cli.rs:67 にあります。
// codex-rs/exec/src/cli.rs
#[arg(long = "json", alias = "experimental-json", default_value_t = false)]
pub json: bool,
  • --sandbox workspace-write … ワークスペースと一部 TMP に限定した書き込み権を付与。
  • -c 'sandbox_workspace_write=...' … Workspace Write モードに対してネットワーク許可と追加の書き込みルートを設定。writable_roots に MCP が使用するキャッシュディレクトリを登録するのがポイントです。
  • -c mcp_servers.serena.startup_timeout_sec=30 … serena MCP サーバーの初期化タイムアウトを 30 秒へ延長。
  • --cd "..." … Codex の作業ルートを明示。
  • resume <SESSION_ID> "こんにちは" … 指定したセッションを再開し、追加プロンプトを送信。

なぜこれで解決するのか

ネットワークとキャッシュ領域が解放されることで、uvx / npx が外部リポジトリから依存関係を取得できるようになり、初回 initialize リクエストが成功します。タイムアウト延長により、ネットワーク遅延や初回セットアップで時間を要しても失敗しにくくなります。またログフィルターを掛けることで、成功にもかかわらず ERROR 表示が残りユーザーを不安にさせる状況を避けられます。

まとめ

  • codex exec は無人実行に便利な反面、デフォルトではネットワークや書き込み権限が厳しく制限される。
  • MCP サーバーがリモートから依存物を取得するタイプ(serena、context7 など)では、必要な権限とタイムアウトを適切に緩める必要がある。
  • --experimental-json / --json は同じ機能で、警告テキストが古いだけ。
  • 一時的には CLI の -c フラグで上書きし、動作を確認したうえで config.toml に反映すると安全。

Codex CLI をヘッドレス自動化で使う際は、サンドボックスや MCP 起動条件を意識して設定を調整しましょう。

Discussion