{"record":{"id":"8968bb7258062532","repo":"openai/codex","slug":"codex-apps-mcp-server-is-unavailable","errorCode":null,"errorMessage":"codex_apps MCP server is unavailable","messagePattern":"codex_apps MCP server is unavailable","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"codex-rs/codex-mcp/src/runtime.rs","lineNumber":234,"sourceCode":"            .restore_checkpoint(checkpoint);\n    }\n\n    /// Reads a widget through the current binding of the app tool that produced it.\n    pub async fn read_resource_for_call(\n        &self,\n        thread_id: ThreadId,\n        call_id: &str,\n        uri: &str,\n    ) -> anyhow::Result<ReadResourceResult> {\n        let origin = self\n            .resource_origins\n            .lock()\n            .unwrap_or_else(std::sync::PoisonError::into_inner)\n            .find(call_id)?;\n        let binding = self\n            .current_binding_for_call(crate::CODEX_APPS_MCP_SERVER_NAME)\n            .await\n            .ok_or_else(|| anyhow::anyhow!(\"codex_apps MCP server is unavailable\"))?;\n\n        origin.read(&binding, thread_id, uri).await\n    }\n\n    pub async fn new(input: McpRuntimeInput) -> Self {\n        let runtime = Self::empty(input.config.prefix_mcp_tool_names);\n        runtime.replace(input).await;\n        runtime\n    }\n\n    /// Reconciles configured servers and publishes their immutable runtime snapshot.\n    pub async fn replace(&self, input: McpRuntimeInput) {\n        let current = self.current.load_full();\n        let mut reconnect = McpReconnectGuard {\n            pending: &self.reconnect_pending,\n            claimed: self.reconnect_pending.swap(false, Ordering::AcqRel),\n        };\n        self.publish(","sourceCodeStart":216,"sourceCodeEnd":252,"githubUrl":"https://github.com/openai/codex/blob/339751715c64496cb86246bfb3935f40e309dd3d/codex-rs/codex-mcp/src/runtime.rs#L216-L252","documentation":"read_resource_for_call resolves which app tool produced a widget resource (by call_id in resource_origins), then reads it through the current binding of the reserved codex_apps MCP server. current_binding_for_call returned None: the hosted apps server has no live connection right now (Apps not enabled in this session, the server dropped by a config replace, or its connection failed), so the resource read cannot proceed.","triggerScenarios":"Reading a widget resource for an older tool call (e.g. re-rendering an app widget from thread history) after the MCP runtime replaced connections without a codex_apps server, when the Apps feature is disabled, or while the codex_apps connection is down or restarting.","commonSituations":"Resuming a thread whose widgets came from apps now disabled or reconfigured; enterprise config removing apps mid-session; transient connection drop during a resource read.","solutions":["Ensure the Apps/codex_apps feature and its hosted server are enabled, then restart the session so a live binding exists","Re-run the originating tool call: a fresh call registers a new origin and binding for the read","If the read is a best-effort UI refresh, degrade gracefully (render stale/placeholder content) instead of propagating the error"],"exampleFix":"// before\nlet result = runtime.read_resource_for_call(thread_id, call_id, uri).await?;\n\n// after: degrade when the apps server is unavailable\nlet result = match runtime.read_resource_for_call(thread_id.clone(), call_id, uri).await {\n    Ok(r) => r,\n    Err(err) if err.to_string().contains(\"codex_apps MCP server is unavailable\") => return render_stale(call_id),\n    Err(err) => return Err(err),\n};","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match runtime.read_resource_for_call(thread_id, call_id, uri).await {\n    Ok(result) => { /* render */ }\n    Err(err) if err.to_string().contains(\"codex_apps MCP server is unavailable\") => { /* stale or placeholder render; optionally retry after the next runtime replace */ }\n    Err(err) => return Err(err),\n}","preventionTips":["Treat widget resource reads as refreshable: cache last-good content keyed by call_id","Check that Apps are enabled before issuing reads for app-originated resources","Re-establish the MCP runtime (session restart) after config changes that touch apps"],"tags":["mcp","codex","codex-apps","resource-read","widget","connection-unavailable"],"backgroundTag":"service-unavailable","analyzedSha":"339751715c64496cb86246bfb3935f40e309dd3d","analyzedAt":"2026-08-25T05:35:09.876Z","schemaVersion":2},"datasetVersion":"2026-08-25T06:17:31.827Z"}