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
78 lines
2.9 KiB
Rust
78 lines
2.9 KiB
Rust
//! Read selected-server metadata from one published thread runtime.
|
|
|
|
use std::sync::Arc;
|
|
|
|
use super::McpRuntime;
|
|
use super::McpRuntimeContext;
|
|
use crate::McpConfig;
|
|
use crate::McpServerStatusSnapshot;
|
|
use crate::McpSnapshotDetail;
|
|
use crate::ResolvedMcpServer;
|
|
use crate::mcp::collect_mcp_server_status_snapshot_from_manager;
|
|
use crate::mcp::compute_auth_statuses;
|
|
use crate::mcp::effective_mcp_servers;
|
|
|
|
impl McpRuntime {
|
|
/// Reuses the selected connection and catalog without starting unrelated servers.
|
|
/// Configuration and metadata belong to the same captured runtime publication.
|
|
/// An expected registration excludes mismatched connections before discovery.
|
|
pub async fn server_status_snapshot(
|
|
&self,
|
|
server: &str,
|
|
detail: McpSnapshotDetail,
|
|
expected_registration: Option<&ResolvedMcpServer>,
|
|
runtime_context: &McpRuntimeContext,
|
|
) -> anyhow::Result<(Arc<McpConfig>, McpServerStatusSnapshot)> {
|
|
let current = self.current.load_full();
|
|
let runtime_context = runtime_context.clone().with_selected_environments(
|
|
Arc::clone(¤t.environment_selections),
|
|
current.ready_environments.clone(),
|
|
);
|
|
let config = Arc::clone(
|
|
current
|
|
.config
|
|
.as_ref()
|
|
.ok_or_else(|| anyhow::anyhow!("MCP runtime is not configured"))?,
|
|
);
|
|
let mut servers = effective_mcp_servers(&config, current.auth.as_ref());
|
|
servers.retain(|name, _| {
|
|
Some(name) == config.mcp_server_catalog.resolve_server_name(server)
|
|
&& expected_registration
|
|
.is_none_or(|expected| config.mcp_server_catalog.server(name) == Some(expected))
|
|
});
|
|
let servers = servers
|
|
.into_values()
|
|
.map(|value| (server.to_owned(), value))
|
|
.collect::<std::collections::HashMap<_, _>>();
|
|
if config.xaa_enabled
|
|
&& servers
|
|
.values()
|
|
.any(|server| matches!(server.config().auth, codex_config::McpServerAuth::EmaAuth))
|
|
{
|
|
// Finish selected startup and any rejected-grant cleanup before reading auth.
|
|
current
|
|
.connections
|
|
.list_available_server_infos(|name| name == server)
|
|
.await;
|
|
}
|
|
let auth_statuses = compute_auth_statuses(
|
|
servers.iter(),
|
|
config.mcp_oauth_credentials_store_mode,
|
|
config.auth_keyring_backend_kind,
|
|
current.auth.as_ref(),
|
|
current.auth_manager.as_ref(),
|
|
&config.ema_state,
|
|
&runtime_context,
|
|
)
|
|
.await;
|
|
let snapshot = collect_mcp_server_status_snapshot_from_manager(
|
|
¤t.connections,
|
|
auth_statuses,
|
|
servers.into_keys().collect(),
|
|
detail,
|
|
)
|
|
.await;
|
|
Ok((config, snapshot))
|
|
}
|
|
}
|