mirror of
https://github.com/openai/codex.git
synced 2026-11-12 21:20:34 +00:00
## Why MCP servers discovered on different executors can share a name. Resolving them by name alone exposes only one server and prevents tools and resources from being addressed independently. ## What changed - Add the disabled-by-default `multi_environment_mcp` feature to expose environment-scoped servers, including multiple installations of the same plugin. - Carry exact `McpServerKey` identities through catalogs, connections, tool calls, resources, and approval tracking. Give environment-scoped tools stable namespaces derived from their environment. - Include `environment_id` in scoped resource listings and accept it in resource requests. Require it for environment-owned servers when multiple environments are selected. - Preserve server ownership through hooks and use the owning environment's permissions for scoped elicitation review. ## Testing Add coverage for same-named servers across environments, independent calls and approvals, resource selection, plugin discovery, and rejection of hook changes to the tool environment. GitOrigin-RevId: 5593372b06a15c16aa3220faa3b19f5d3b20e67e
69 lines
2.4 KiB
Rust
69 lines
2.4 KiB
Rust
use std::collections::BTreeSet;
|
|
|
|
use codex_connectors::metadata::connector_display_label;
|
|
use codex_features::Features;
|
|
use codex_protocol::models::ResponseItem;
|
|
|
|
use crate::connectors;
|
|
use crate::context::ContextualUserFragment;
|
|
use crate::context::PluginInstructions;
|
|
use crate::plugins::PluginCapabilitySummary;
|
|
use crate::plugins::render_explicit_plugin_instructions;
|
|
use codex_mcp::CODEX_APPS_MCP_SERVER_NAME;
|
|
use codex_mcp::ToolInfo;
|
|
|
|
pub(crate) fn build_plugin_injections(
|
|
mentioned_plugins: &[PluginCapabilitySummary],
|
|
mcp_tools: &[ToolInfo],
|
|
available_connectors: &[connectors::AppInfo],
|
|
features: &Features,
|
|
model_messages: codex_prompts::ResolvedModelMessages<'_>,
|
|
) -> Vec<ResponseItem> {
|
|
if mentioned_plugins.is_empty() {
|
|
return Vec::new();
|
|
}
|
|
|
|
let messages = model_messages.selected_plugin();
|
|
// Turn each explicit plugin mention with available capabilities into a developer hint.
|
|
mentioned_plugins
|
|
.iter()
|
|
.filter_map(|plugin| {
|
|
let available_mcp_servers = mcp_tools
|
|
.iter()
|
|
.filter(|tool| {
|
|
tool.server_name() != CODEX_APPS_MCP_SERVER_NAME
|
|
&& tool
|
|
.plugin_display_names
|
|
.iter()
|
|
.any(|plugin_name| plugin_name == &plugin.display_name)
|
|
})
|
|
.map(|tool| tool.server_name().to_owned())
|
|
.collect::<BTreeSet<String>>()
|
|
.into_iter()
|
|
.collect::<Vec<_>>();
|
|
let available_apps = available_connectors
|
|
.iter()
|
|
.filter(|connector| {
|
|
connector.is_enabled
|
|
&& connector
|
|
.plugin_display_names
|
|
.iter()
|
|
.any(|plugin_name| plugin_name == &plugin.display_name)
|
|
})
|
|
.map(connector_display_label)
|
|
.collect::<BTreeSet<String>>()
|
|
.into_iter()
|
|
.collect::<Vec<_>>();
|
|
render_explicit_plugin_instructions(
|
|
plugin,
|
|
&available_mcp_servers,
|
|
&available_apps,
|
|
features,
|
|
&messages,
|
|
)
|
|
.map(PluginInstructions::new)
|
|
.map(ContextualUserFragment::into)
|
|
})
|
|
.collect()
|
|
}
|