feat(mcp): hide background startup status by default

This commit is contained in:
Felipe Coury
2026-06-03 15:43:59 -03:00
parent 2d5c264ebc
commit 000c857ecc
15 changed files with 309 additions and 64 deletions
+2
View File
@@ -632,6 +632,7 @@ fn config_toml_deserializes_model_availability_nux() {
notification_settings: TuiNotificationSettings::default(),
animations: true,
show_tooltips: true,
show_mcp_startup_status: false,
vim_mode_default: false,
raw_output_mode: false,
alternate_screen: AltScreenMode::default(),
@@ -3380,6 +3381,7 @@ fn tui_config_missing_notifications_field_defaults_to_enabled() {
notification_settings: TuiNotificationSettings::default(),
animations: true,
show_tooltips: true,
show_mcp_startup_status: false,
vim_mode_default: false,
raw_output_mode: false,
alternate_screen: AltScreenMode::Auto,
+8
View File
@@ -705,6 +705,9 @@ pub struct Config {
/// Show startup tooltips in the TUI welcome screen.
pub show_tooltips: bool,
/// Show background MCP server startup status and optional failure diagnostics in the TUI.
pub tui_show_mcp_startup_status: bool,
/// Persisted startup availability NUX state for model tooltips.
pub model_availability_nux: ModelAvailabilityNuxConfig,
@@ -3575,6 +3578,11 @@ impl Config {
.unwrap_or_default(),
animations: cfg.tui.as_ref().map(|t| t.animations).unwrap_or(true),
show_tooltips: cfg.tui.as_ref().map(|t| t.show_tooltips).unwrap_or(true),
tui_show_mcp_startup_status: cfg
.tui
.as_ref()
.map(|t| t.show_mcp_startup_status)
.unwrap_or(false),
model_availability_nux: cfg
.tui
.as_ref()
+3 -1
View File
@@ -102,7 +102,9 @@ pub(crate) async fn list_accessible_and_enabled_connectors_from_manager(
config: &Config,
) -> Vec<AppInfo> {
with_app_enabled_state(
accessible_connectors_from_mcp_tools(&mcp_connection_manager.list_all_tools().await),
accessible_connectors_from_mcp_tools(
&mcp_connection_manager.list_ready_or_cached_tools().await,
),
config,
)
.into_iter()
+40 -5
View File
@@ -74,6 +74,7 @@ use codex_extension_api::TurnInputEnvironment;
use codex_features::Feature;
use codex_git_utils::get_git_repo_root;
use codex_git_utils::get_git_repo_root_with_fs;
use codex_mcp::CODEX_APPS_MCP_SERVER_NAME;
use codex_protocol::config_types::AutoCompactTokenLimitScope;
use codex_protocol::config_types::ModeKind;
use codex_protocol::config_types::ServiceTier;
@@ -450,7 +451,7 @@ async fn run_hooks_and_record_inputs(
#[expect(
clippy::await_holding_invalid_type,
reason = "MCP tool listing borrows the read guard across cancellation-aware await"
reason = "ready-or-cached tool inspection never awaits unresolved MCP startup"
)]
async fn build_skills_and_plugins(
sess: &Arc<Session>,
@@ -481,6 +482,40 @@ async fn build_skills_and_plugins(
// enabled plugins, then converted into turn-scoped guidance below.
let mentioned_plugins =
collect_explicit_plugin_mentions(&user_input, loaded_plugins.capability_summaries());
let explicitly_mentioned_apps = collect_explicit_app_ids(&user_input);
let mut explicitly_requested_mcp_servers = mentioned_plugins
.iter()
.flat_map(|plugin| plugin.mcp_server_names.iter().cloned())
.collect::<HashSet<_>>();
if turn_context.apps_enabled() && !explicitly_mentioned_apps.is_empty() {
explicitly_requested_mcp_servers.insert(CODEX_APPS_MCP_SERVER_NAME.to_string());
}
if !explicitly_requested_mcp_servers.is_empty() {
let mut explicitly_requested_mcp_servers = explicitly_requested_mcp_servers
.into_iter()
.collect::<Vec<_>>();
explicitly_requested_mcp_servers.sort();
let readiness = {
let mcp_connection_manager = sess.services.mcp_connection_manager.read().await;
mcp_connection_manager.wait_for_servers_ready(&explicitly_requested_mcp_servers)
};
let failures = match readiness.or_cancel(cancellation_token).await {
Ok(failures) => failures,
Err(_) => return None,
};
for failure in failures {
sess.send_event(
turn_context,
EventMsg::Warning(WarningEvent {
message: format!(
"MCP dependency `{}` requested for this turn is unavailable: {}",
failure.server, failure.error
),
}),
)
.await;
}
}
let mcp_tools = if turn_context.apps_enabled() || !mentioned_plugins.is_empty() {
// Plugin mentions need raw MCP/app inventory even when app tools
// are normally hidden so we can describe the plugin's currently
@@ -490,7 +525,7 @@ async fn build_skills_and_plugins(
.mcp_connection_manager
.read()
.await
.list_all_tools()
.list_ready_or_cached_tools()
.or_cancel(cancellation_token)
.await
{
@@ -563,7 +598,7 @@ async fn build_skills_and_plugins(
);
let plugin_items =
build_plugin_injections(&mentioned_plugins, &mcp_tools, &available_connectors);
let mut explicitly_enabled_connectors = collect_explicit_app_ids(&user_input);
let mut explicitly_enabled_connectors = explicitly_mentioned_apps;
explicitly_enabled_connectors.extend(skill_connector_ids);
let connector_names_by_id = available_connectors
.iter()
@@ -1075,7 +1110,7 @@ async fn run_sampling_request(
#[expect(
clippy::await_holding_invalid_type,
reason = "tool router construction reads through the session-owned manager guard"
reason = "ready-or-cached tool inspection never awaits unresolved MCP startup"
)]
#[instrument(level = "trace",
skip_all,
@@ -1098,7 +1133,7 @@ pub(crate) async fn built_tools(
.await;
let has_mcp_servers = mcp_connection_manager.has_servers();
let all_mcp_tools = mcp_connection_manager
.list_all_tools()
.list_ready_or_cached_tools()
.or_cancel(cancellation_token)
.await?;
drop(mcp_connection_manager);