Skip to content

Commit 24b8104

Browse files
Fix/mcp disable (#257)
1 parent 9a60489 commit 24b8104

File tree

3 files changed

+70
-5
lines changed

3 files changed

+70
-5
lines changed

crates/chat-cli/src/cli/chat/tool_manager.rs

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,22 @@ impl ToolManagerBuilder {
287287
let regex = regex::Regex::new(VALID_TOOL_NAME)?;
288288
let mut hasher = DefaultHasher::new();
289289
let is_interactive = self.is_interactive;
290-
let pre_initialized = mcp_servers
290+
291+
// Separate enabled and disabled servers
292+
let (enabled_servers, disabled_servers): (Vec<_>, Vec<_>) = mcp_servers
293+
.into_iter()
294+
.partition(|(_, server_config)| !server_config.disabled);
295+
296+
// Prepare disabled servers for display
297+
let disabled_servers_display: Vec<String> = disabled_servers
298+
.iter()
299+
.map(|(server_name, _)| {
300+
let snaked_cased_name = server_name.to_case(convert_case::Case::Snake);
301+
sanitize_name(snaked_cased_name, &regex, &mut hasher)
302+
})
303+
.collect();
304+
305+
let pre_initialized = enabled_servers
291306
.into_iter()
292307
.map(|(server_name, server_config)| {
293308
let snaked_cased_name = server_name.to_case(convert_case::Case::Snake);
@@ -296,6 +311,7 @@ impl ToolManagerBuilder {
296311
(sanitized_server_name, custom_tool_client)
297312
})
298313
.collect::<Vec<(String, _)>>();
314+
299315
let mut loading_servers = HashMap::<String, Instant>::new();
300316
for (server_name, _) in &pre_initialized {
301317
let init_time = std::time::Instant::now();
@@ -306,14 +322,26 @@ impl ToolManagerBuilder {
306322
// Spawn a task for displaying the mcp loading statuses.
307323
// This is only necessary when we are in interactive mode AND there are servers to load.
308324
// Otherwise we do not need to be spawning this.
309-
let (_loading_display_task, loading_status_sender) = if is_interactive && total > 0 {
325+
let (_loading_display_task, loading_status_sender) = if is_interactive
326+
&& (total > 0 || !disabled_servers_display.is_empty())
327+
{
310328
let (tx, mut rx) = tokio::sync::mpsc::channel::<LoadingMsg>(50);
329+
let disabled_servers_display_clone = disabled_servers_display.clone();
311330
(
312331
Some(tokio::task::spawn(async move {
313332
let mut spinner_logo_idx: usize = 0;
314333
let mut complete: usize = 0;
315334
let mut failed: usize = 0;
316-
queue_init_message(spinner_logo_idx, complete, failed, total, &mut output)?;
335+
336+
// Show disabled servers immediately
337+
for server_name in &disabled_servers_display_clone {
338+
queue_disabled_message(server_name, &mut output)?;
339+
}
340+
341+
if total > 0 {
342+
queue_init_message(spinner_logo_idx, complete, failed, total, &mut output)?;
343+
}
344+
317345
loop {
318346
match tokio::time::timeout(Duration::from_millis(50), rx.recv()).await {
319347
Ok(Some(recv_result)) => match recv_result {
@@ -352,7 +380,7 @@ impl ToolManagerBuilder {
352380
queue_init_message(spinner_logo_idx, complete, failed, total, &mut output)?;
353381
},
354382
LoadingMsg::Terminate { still_loading } => {
355-
if !still_loading.is_empty() {
383+
if !still_loading.is_empty() && total > 0 {
356384
execute!(
357385
output,
358386
cursor::MoveToColumn(0),
@@ -365,6 +393,14 @@ impl ToolManagerBuilder {
365393
});
366394
let msg = eyre::eyre!(msg);
367395
queue_incomplete_load_message(complete, total, &msg, &mut output)?;
396+
} else if total > 0 {
397+
// Clear the loading line if we have enabled servers
398+
execute!(
399+
output,
400+
cursor::MoveToColumn(0),
401+
cursor::MoveUp(1),
402+
terminal::Clear(terminal::ClearType::CurrentLine),
403+
)?;
368404
}
369405
execute!(output, style::Print("\n"),)?;
370406
break;
@@ -687,6 +723,7 @@ impl ToolManagerBuilder {
687723
has_new_stuff,
688724
is_interactive,
689725
mcp_load_record: load_record,
726+
disabled_servers: disabled_servers_display,
690727
..Default::default()
691728
})
692729
}
@@ -776,6 +813,9 @@ pub struct ToolManager {
776813
/// invalid characters).
777814
/// The value is the load message (i.e. load time, warnings, and errors)
778815
pub mcp_load_record: Arc<Mutex<HashMap<String, Vec<LoadingRecord>>>>,
816+
817+
/// List of disabled MCP server names for display purposes
818+
disabled_servers: Vec<String>,
779819
}
780820

781821
impl Clone for ToolManager {
@@ -790,6 +830,7 @@ impl Clone for ToolManager {
790830
schema: self.schema.clone(),
791831
is_interactive: self.is_interactive,
792832
mcp_load_record: self.mcp_load_record.clone(),
833+
disabled_servers: self.disabled_servers.clone(),
793834
..Default::default()
794835
}
795836
}
@@ -1473,6 +1514,19 @@ fn queue_warn_message(name: &str, msg: &eyre::Report, time: &str, output: &mut i
14731514
)?)
14741515
}
14751516

1517+
fn queue_disabled_message(name: &str, output: &mut impl Write) -> eyre::Result<()> {
1518+
Ok(queue!(
1519+
output,
1520+
style::SetForegroundColor(style::Color::DarkGrey),
1521+
style::Print("○ "),
1522+
style::SetForegroundColor(style::Color::Blue),
1523+
style::Print(name),
1524+
style::ResetColor,
1525+
style::Print(" is disabled\n"),
1526+
style::ResetColor,
1527+
)?)
1528+
}
1529+
14761530
fn queue_incomplete_load_message(
14771531
complete: usize,
14781532
total: usize,

crates/chat-cli/src/cli/chat/tools/custom_tool.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ pub struct CustomToolConfig {
4242
pub env: Option<HashMap<String, String>>,
4343
#[serde(default = "default_timeout")]
4444
pub timeout: u64,
45+
#[serde(default)]
46+
pub disabled: bool,
4547
}
4648

4749
pub fn default_timeout() -> u64 {
@@ -65,6 +67,7 @@ impl CustomToolClient {
6567
args,
6668
env,
6769
timeout,
70+
disabled: _,
6871
} = config;
6972
let mcp_client_config = McpClientConfig {
7073
server_name: server_name.clone(),

crates/chat-cli/src/cli/mcp.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ pub struct AddArgs {
9494
/// Server launch timeout, in milliseconds
9595
#[arg(long)]
9696
pub timeout: Option<u64>,
97+
/// Whether the server should be disabled (not loaded)
98+
#[arg(long, default_value_t = false)]
99+
pub disabled: bool,
97100
/// Overwrite an existing server with the same name
98101
#[arg(long, default_value_t = false)]
99102
pub force: bool,
@@ -120,6 +123,7 @@ impl AddArgs {
120123
"command": self.command,
121124
"env": merged_env,
122125
"timeout": self.timeout.unwrap_or(default_timeout()),
126+
"disabled": self.disabled,
123127
}))?;
124128

125129
writeln!(
@@ -203,7 +207,8 @@ impl ListArgs {
203207
match cfg_opt {
204208
Some(cfg) if !cfg.mcp_servers.is_empty() => {
205209
for (name, tool_cfg) in &cfg.mcp_servers {
206-
writeln!(output, " • {name:<12} {}", tool_cfg.command)?;
210+
let status = if tool_cfg.disabled { " (disabled)" } else { "" };
211+
writeln!(output, " • {name:<12} {}{}", tool_cfg.command, status)?;
207212
}
208213
},
209214
_ => {
@@ -287,6 +292,7 @@ impl StatusArgs {
287292
style::Print(format!("File : {}\n", path.display())),
288293
style::Print(format!("Command : {}\n", cfg.command)),
289294
style::Print(format!("Timeout : {} ms\n", cfg.timeout)),
295+
style::Print(format!("Disabled: {}\n", cfg.disabled)),
290296
style::Print(format!(
291297
"Env Vars: {}\n",
292298
cfg.env
@@ -451,6 +457,7 @@ mod tests {
451457
env: vec![],
452458
timeout: None,
453459
scope: None,
460+
disabled: false,
454461
force: false,
455462
}
456463
.execute(&ctx, &mut out)
@@ -501,6 +508,7 @@ mod tests {
501508
.collect()
502509
],
503510
timeout: None,
511+
disabled: false,
504512
force: false,
505513
}))
506514
);

0 commit comments

Comments
 (0)