use crate::capabilities::{BindingRequest, McpBinding, McpBindingRequest, McpTransportKind};
use crate::launchers::base::LaunchContext;
use crate::utils::ui::Ui;
use anyhow::Context;
use std::collections::HashSet;
use std::path::Path;
pub(crate) fn mcp_binding_request() -> BindingRequest {
BindingRequest::Mcp(McpBindingRequest {
supported_transports: HashSet::from([McpTransportKind::Stdio, McpTransportKind::Http]),
})
}
pub(crate) fn register_mcp_server(
binary: &Path,
name: &str,
binding: &McpBinding,
scope_args: &[&str],
ctx: &LaunchContext,
ui: &dyn Ui,
) -> anyhow::Result<()> {
let json = binding.to_canonical_json().to_string();
let mut args = vec![
"mcp".to_string(),
"add-json".to_string(),
name.to_string(),
json,
];
args.extend(scope_args.iter().map(|s| s.to_string()));
run_mcp_cli(binary, &args, "register", ctx, ui)
}
pub(crate) fn remove_mcp_server(
binary: &Path,
name: &str,
scope_args: &[&str],
ctx: &LaunchContext,
ui: &dyn Ui,
) {
let mut args = vec!["mcp".to_string(), "remove".to_string(), name.to_string()];
args.extend(scope_args.iter().map(|s| s.to_string()));
if let Err(e) = run_mcp_cli(binary, &args, "remove", ctx, ui) {
ui.warn(&format!("Failed to remove MCP server '{name}': {e}"));
}
}
fn run_mcp_cli(
binary: &Path,
args: &[String],
verb: &str,
ctx: &LaunchContext,
ui: &dyn Ui,
) -> anyhow::Result<()> {
if ctx.dry_run {
ui.info(&format!(
"Would run: {} {}",
binary.display(),
args.join(" ")
));
return Ok(());
}
let status = std::process::Command::new(binary)
.args(args)
.status()
.with_context(|| {
format!(
"failed to {verb} MCP server via `{} {}`",
binary.display(),
args.join(" ")
)
})?;
anyhow::ensure!(
status.success(),
"`{} {}` exited with status {}",
binary.display(),
args.join(" "),
status
);
Ok(())
}