From b32ef8a9def2e1e56c228766706096863e22cf76 Mon Sep 17 00:00:00 2001 From: viyatb-oai Date: Thu, 25 Jun 2026 09:59:04 -0700 Subject: [PATCH] docs(mcp): document replacement invariants Co-authored-by: Codex noreply@openai.com --- codex-rs/codex-mcp/src/connection_manager.rs | 3 ++- codex-rs/core/src/session/mcp.rs | 3 +++ codex-rs/protocol/src/protocol.rs | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/codex-rs/codex-mcp/src/connection_manager.rs b/codex-rs/codex-mcp/src/connection_manager.rs index 770cfe2478..3541fa4c01 100644 --- a/codex-rs/codex-mcp/src/connection_manager.rs +++ b/codex-rs/codex-mcp/src/connection_manager.rs @@ -107,7 +107,7 @@ pub fn tool_is_model_visible(tool: &ToolInfo) -> bool { .any(|target| target.as_str() == Some(MCP_UI_MODEL_VISIBILITY)) } -/// A thin wrapper around a set of running [`RmcpClient`] instances. +/// Immutable inputs needed to construct one MCP client during a live replacement. #[derive(Clone)] struct McpClientRuntime { store_mode: OAuthCredentialsStoreMode, @@ -155,6 +155,7 @@ impl McpClientRuntime { } } +/// A thin wrapper around a set of running [`RmcpClient`] instances. pub struct McpConnectionManager { clients: HashMap, server_metadata: HashMap, diff --git a/codex-rs/core/src/session/mcp.rs b/codex-rs/core/src/session/mcp.rs index b6e135572e..2d251fec3b 100644 --- a/codex-rs/core/src/session/mcp.rs +++ b/codex-rs/core/src/session/mcp.rs @@ -473,6 +473,9 @@ impl Session { .services .mcp_connection_manager .swap(Arc::clone(&replacement_manager)); + // Publish first, then transfer cancellation ownership while both manager + // snapshots are still held here. Dropping an uncommitted replacement + // cancels only the client it prepared. replacement_manager.take_cancellation_ownership_from(&superseded_manager); drop(current_manager); diff --git a/codex-rs/protocol/src/protocol.rs b/codex-rs/protocol/src/protocol.rs index dbd2a74886..c684477a46 100644 --- a/codex-rs/protocol/src/protocol.rs +++ b/codex-rs/protocol/src/protocol.rs @@ -190,6 +190,7 @@ pub struct McpServerRefreshConfig { impl fmt::Debug for McpServerRefreshConfig { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + // Server configuration can contain headers and environment credentials. formatter .debug_struct("McpServerRefreshConfig") .field("mcp_servers", &"") @@ -202,12 +203,15 @@ impl fmt::Debug for McpServerRefreshConfig { /// Config payload for replacing one MCP server in a running session. #[derive(Clone, PartialEq)] pub struct McpServerUpdateConfig { + /// Name of the server to replace. pub server_name: String, + /// Serialized `McpServerConfig` for the replacement. pub server: Value, } impl fmt::Debug for McpServerUpdateConfig { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + // Keep the server name diagnosable without exposing its credential-bearing config. formatter .debug_struct("McpServerUpdateConfig") .field("server_name", &self.server_name)