[tui] Support /mcp command (#2430)

## Summary
Adds a `/mcp` command to list active tools. We can extend this command
to allow configuration of MCP tools, but for now a simple list command
will help debug if your config.toml and your tools are working as
expected.
This commit is contained in:
Dylan
2025-08-19 09:00:31 -07:00
committed by GitHub
parent 096bca2fa2
commit e7e5fe91c8
8 changed files with 137 additions and 0 deletions

View File

@@ -634,6 +634,87 @@ pub(crate) fn new_status_output(
PlainHistoryCell { lines }
}
/// Render a summary of configured MCP servers from the current `Config`.
pub(crate) fn empty_mcp_output() -> PlainHistoryCell {
let lines: Vec<Line<'static>> = vec![
Line::from("/mcp".magenta()),
Line::from(""),
Line::from(vec!["🔌 ".into(), "MCP Tools".bold()]),
Line::from(""),
Line::from(" • No MCP servers configured.".italic()),
Line::from(""),
];
PlainHistoryCell { lines }
}
/// Render MCP tools grouped by connection using the fully-qualified tool names.
pub(crate) fn new_mcp_tools_output(
config: &Config,
tools: std::collections::HashMap<String, mcp_types::Tool>,
) -> PlainHistoryCell {
let mut lines: Vec<Line<'static>> = vec![
Line::from("/mcp".magenta()),
Line::from(""),
Line::from(vec!["🔌 ".into(), "MCP Tools".bold()]),
Line::from(""),
];
if tools.is_empty() {
lines.push(Line::from(" • No MCP tools available.".italic()));
lines.push(Line::from(""));
return PlainHistoryCell { lines };
}
for (server, cfg) in config.mcp_servers.iter() {
let prefix = format!("{server}__");
let mut names: Vec<String> = tools
.keys()
.filter(|k| k.starts_with(&prefix))
.map(|k| k[prefix.len()..].to_string())
.collect();
names.sort();
lines.push(Line::from(vec![
" • Server: ".into(),
server.clone().into(),
]));
if !cfg.command.is_empty() {
let cmd_display = format!("{} {}", cfg.command, cfg.args.join(" "));
lines.push(Line::from(vec![
" • Command: ".into(),
cmd_display.into(),
]));
}
if let Some(env) = cfg.env.as_ref() {
if !env.is_empty() {
let mut env_pairs: Vec<String> =
env.iter().map(|(k, v)| format!("{k}={v}")).collect();
env_pairs.sort();
lines.push(Line::from(vec![
" • Env: ".into(),
env_pairs.join(" ").into(),
]));
}
}
if names.is_empty() {
lines.push(Line::from(" • Tools: (none)"));
} else {
lines.push(Line::from(vec![
" • Tools: ".into(),
names.join(", ").into(),
]));
}
lines.push(Line::from(""));
}
PlainHistoryCell { lines }
}
pub(crate) fn new_error_event(message: String) -> PlainHistoryCell {
let lines: Vec<Line<'static>> = vec![vec!["🖐 ".red().bold(), message.into()].into(), "".into()];
PlainHistoryCell { lines }