mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
Add selected-plugin precedence and attribution to the MCP catalog (#27884)
## Why **In short:** this PR resolves already-discovered MCP registrations. It does not read selected plugins or discover their MCP servers. The resolved MCP catalog currently builds config and auto-discovered plugin registrations before runtime contributors are applied. A thread-selected plugin needs a distinct precedence tier in that same initial resolution pass: otherwise a disabled lower-precedence winner can leave stale name-level state behind, and the winning MCP tools cannot be attributed to the selected package reliably. This PR adds that catalog boundary before executor discovery is connected. ## What changed - Added an explicit selected-plugin registration tier between auto-discovered plugins and explicit config. - Collected selected-plugin contributions before the initial catalog build, while leaving compatibility and generic extension overlays in their existing runtime phase. - Retained the winning plugin ID and display name directly on plugin-owned catalog registrations. - Derived MCP tool provenance from the winning catalog entry instead of joining against local-only plugin summaries. - Retained the winning selected server's tool approval policy in the running connection manager, so a selected registration cannot inherit approval behavior from a losing local plugin. - Kept remembered approval session-scoped for selected plugins until there is an authority-aware persistence contract; Codex will not write approval back to an unrelated local plugin. - Preserved existing name-level disabled vetoes for discovered plugins and config, while keeping a selected package's own disabled registration scoped to that registration. - Preserved deterministic selection order and existing config, compatibility, and extension precedence. The resulting order is: ```text auto-discovered plugin < selected plugin < explicit config < compatibility registration < extension overlay ``` ## Behavior and scope This is a catalog and provenance change only. No production host contributes selected-plugin MCP registrations yet, so existing local MCP behavior remains unchanged. The stacked follow-up, #27870, installs the executor plugin provider that produces these registrations. App-server activation remains a separate final step. ## Verification Focused tests cover precedence, deterministic selected-plugin conflicts, disabled-veto behavior across catalog phases, managed requirements before selected-plugin resolution, winning-server approval policy, and attribution when local and selected packages share an ID or server name. CI owns execution of the test suite.
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use codex_config::AppToolApproval;
|
||||
use codex_config::McpServerConfig;
|
||||
use codex_config::McpServerTransportConfig;
|
||||
|
||||
@@ -75,6 +78,18 @@ pub(crate) struct McpServerMetadata {
|
||||
pub pollutes_memory: bool,
|
||||
pub origin: Option<McpServerOrigin>,
|
||||
pub supports_parallel_tool_calls: bool,
|
||||
pub default_tools_approval_mode: Option<AppToolApproval>,
|
||||
pub tool_approval_modes: HashMap<String, AppToolApproval>,
|
||||
}
|
||||
|
||||
impl McpServerMetadata {
|
||||
pub fn tool_approval_mode(&self, tool_name: &str) -> AppToolApproval {
|
||||
self.tool_approval_modes
|
||||
.get(tool_name)
|
||||
.copied()
|
||||
.or(self.default_tools_approval_mode)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&EffectiveMcpServer> for McpServerMetadata {
|
||||
@@ -84,6 +99,16 @@ impl From<&EffectiveMcpServer> for McpServerMetadata {
|
||||
pollutes_memory: true,
|
||||
origin: McpServerOrigin::from_transport(&config.transport),
|
||||
supports_parallel_tool_calls: config.supports_parallel_tool_calls,
|
||||
default_tools_approval_mode: config.default_tools_approval_mode,
|
||||
tool_approval_modes: config
|
||||
.tools
|
||||
.iter()
|
||||
.filter_map(|(name, config)| {
|
||||
config
|
||||
.approval_mode
|
||||
.map(|approval_mode| (name.clone(), approval_mode))
|
||||
})
|
||||
.collect(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user