mirror of
https://github.com/openai/codex.git
synced 2026-11-14 06:48:26 +00:00
Honor explicit plugin mentions during MCP startup (#42406)
## Why Selected plugin MCP servers may be skipped after the optional startup grace period. When a user explicitly mentions a plugin or MCP server, the turn should continue waiting so the requested tools are available to the model. ## What changed - Track explicitly mentioned plugin IDs and MCP servers across later samples, steered input, and same-turn restarts. - Require matching selected-plugin MCP servers to finish startup before capturing the tool catalog, while leaving unmentioned servers optional. - Match `plugin://` identities independently of display names and ignore targeting query parameters such as `app` and `browserFamily`. ## Testing Added coverage for linked and structured plugin mentions, direct and batched capability discovery, delayed environment attachment, steering, and same-turn restarts. GitOrigin-RevId: c509ef8df45df1a7edb0da6afdb2682dc53a4de8
This commit is contained in:
1 parent
b7f710273e
commit
460b63e5f4
14 files changed
+617
-106
No files matched your search
@@ -6,6 +6,7 @@
|
||||
//! [`crate::connection_manager`].
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
@@ -335,20 +336,29 @@ impl McpRuntime {
|
||||
|
||||
/// Captures the latest published configuration and live client handles.
|
||||
pub async fn current_binding(&self) -> Option<Arc<McpBinding>> {
|
||||
self.current_binding_with_required_servers(&[]).await
|
||||
self.current_binding_with_requirements(&[], &HashSet::new())
|
||||
.await
|
||||
}
|
||||
|
||||
/// Captures the latest runtime, waiting for servers explicitly required by this turn.
|
||||
pub async fn current_binding_with_required_servers(
|
||||
/// Captures one runtime, waiting for explicitly required servers and selected plugins.
|
||||
/// Plugin IDs are resolved by the captured connection set, even if a refresh publishes later.
|
||||
pub async fn current_binding_with_requirements(
|
||||
&self,
|
||||
required_servers: &[String],
|
||||
required_plugins: &HashSet<String>,
|
||||
) -> Option<Arc<McpBinding>> {
|
||||
Self::binding_from_published_runtime(self.current.load_full(), required_servers).await
|
||||
Self::binding_from_published_runtime(
|
||||
self.current.load_full(),
|
||||
required_servers,
|
||||
required_plugins,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn binding_from_published_runtime(
|
||||
current: Arc<PublishedMcpRuntime>,
|
||||
required_servers: &[String],
|
||||
required_plugins: &HashSet<String>,
|
||||
) -> Option<Arc<McpBinding>> {
|
||||
let config = Arc::clone(current.config.as_ref()?);
|
||||
let stable_catalog_revision = current.connections.stable_catalog_revision().await;
|
||||
@@ -367,7 +377,12 @@ impl McpRuntime {
|
||||
let binding = Arc::new(
|
||||
current
|
||||
.connections
|
||||
.capture_binding_with_metadata(config, current.plugins_available, required_servers)
|
||||
.capture_binding_with_metadata(
|
||||
config,
|
||||
current.plugins_available,
|
||||
required_servers,
|
||||
required_plugins,
|
||||
)
|
||||
.await,
|
||||
);
|
||||
if let Some(catalog_revision) = stable_catalog_revision
|
||||
@@ -445,7 +460,12 @@ impl McpRuntime {
|
||||
if !current.connections.wait_for_server_startup(server).await {
|
||||
return None;
|
||||
}
|
||||
Self::binding_from_published_runtime(current, /*required_servers*/ &[]).await
|
||||
Self::binding_from_published_runtime(
|
||||
current,
|
||||
/*required_servers*/ &[],
|
||||
/*required_plugins*/ &HashSet::new(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Returns the latest published configuration without waiting for clients.
|
||||
@@ -877,12 +897,14 @@ mod tests {
|
||||
let first = McpRuntime::binding_from_published_runtime(
|
||||
Arc::clone(&published),
|
||||
/*required_servers*/ &[],
|
||||
/*required_plugins*/ &HashSet::new(),
|
||||
)
|
||||
.await
|
||||
.expect("first binding");
|
||||
let repeated = McpRuntime::binding_from_published_runtime(
|
||||
Arc::clone(&published),
|
||||
/*required_servers*/ &[],
|
||||
/*required_plugins*/ &HashSet::new(),
|
||||
)
|
||||
.await
|
||||
.expect("repeated binding");
|
||||
@@ -893,10 +915,13 @@ mod tests {
|
||||
cached_binding: Mutex::new(None),
|
||||
..previous
|
||||
});
|
||||
let refreshed =
|
||||
McpRuntime::binding_from_published_runtime(republished, /*required_servers*/ &[])
|
||||
.await
|
||||
.expect("republished binding");
|
||||
let refreshed = McpRuntime::binding_from_published_runtime(
|
||||
republished,
|
||||
/*required_servers*/ &[],
|
||||
/*required_plugins*/ &HashSet::new(),
|
||||
)
|
||||
.await
|
||||
.expect("republished binding");
|
||||
assert!(!Arc::ptr_eq(&first, &refreshed));
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user