use crate::commands::Cli;
use crate::config::Config;
use crate::error::Result;
use crate::mcp_server::FnoxMcpServer;
use crate::{env, error::FnoxError};
use clap::Args;
use rmcp::service::RunningService;
use rmcp::{RoleServer, ServiceExt};
#[derive(Debug, Args)]
pub struct McpCommand {}
impl McpCommand {
pub async fn run(&self, cli: &Cli, config: Config) -> Result<()> {
env::set_non_interactive(true);
let profile = Config::get_profile(cli.profile.as_deref());
let mcp_config = config.mcp.clone().unwrap_or_default();
let all_secrets = config.get_secrets(&profile)?;
if let Some(ref allowlist) = mcp_config.secrets {
if allowlist.is_empty() {
tracing::warn!(
"mcp.secrets is set to an empty list — no secrets will be available to the MCP server"
);
}
let allowed_set: std::collections::HashSet<&str> =
allowlist.iter().map(|s| s.as_str()).collect();
let providers = config.get_providers(&profile);
for name in allowlist {
if !all_secrets.contains_key(name) {
tracing::warn!(
"mcp.secrets allowlist contains '{name}' which is not a configured secret"
);
continue;
}
if let Some(sc) = all_secrets.get(name)
&& let Some(provider_name) = sc.provider()
&& let Some(pc) = providers.get(provider_name)
{
for dep in pc.env_dependencies() {
if all_secrets.contains_key(*dep) && !allowed_set.contains(*dep) {
tracing::warn!(
"mcp.secrets: '{name}' uses provider '{provider_name}' which \
depends on '{dep}' — add '{dep}' to mcp.secrets or its provider \
may fail to authenticate"
);
}
}
}
}
}
let profile_secrets = mcp_config.filter_secrets(all_secrets);
if mcp_config.exec_timeout_secs == Some(0) {
return Err(FnoxError::Config(
"mcp.exec_timeout_secs must be >= 1; use a large value to effectively disable the timeout".into(),
));
}
let server = FnoxMcpServer::new(config, profile, mcp_config, profile_secrets);
let service: RunningService<RoleServer, FnoxMcpServer> = server
.serve(rmcp::transport::io::stdio())
.await
.map_err(|e| FnoxError::Config(format!("Failed to start MCP server: {e}")))?;
service
.waiting()
.await
.map_err(|e| FnoxError::Config(format!("MCP server error: {e}")))?;
Ok(())
}
}