use clap::Parser;
use rmcp::service::ServiceExt;
use tracing::{error, info};
use ssh_mcp::config::{Args, Config};
use ssh_mcp::error::Result;
use ssh_mcp::logging::init_logging;
use ssh_mcp::server::SshMcpServer;
#[tokio::main]
async fn main() -> Result<()> {
let args = Args::parse();
let _guard = init_logging(&args)?;
let config = Config::from_args(args)?;
info!("SSH MCP Server v{} starting...", env!("CARGO_PKG_VERSION"));
info!(
"Connecting to {}@{}:{}",
config.user, config.host, config.port
);
info!(
"Timeout: {}ms, Max chars: {}",
config.timeout_ms,
config
.max_chars
.map_or("unlimited".to_string(), |n| n.to_string())
);
info!(
"Keepalive: interval={}s, max_failures={}",
config.keepalive_interval, config.keepalive_max
);
info!(
"Host key checking: {:?}, known_hosts={}",
config.strict_host_key_checking,
config
.known_hosts
.as_ref()
.map(|p| p.display().to_string())
.unwrap_or_else(|| "default".to_string())
);
if config.disable_sudo {
info!("sudo-exec tool is disabled");
}
let server = SshMcpServer::new(config).await?;
info!("SSH MCP Server running on stdio");
let server_for_shutdown = server.clone();
let shutdown_handle = tokio::spawn(async move {
tokio::select! {
_ = tokio::signal::ctrl_c() => {
info!("Received SIGINT (Ctrl+C), shutting down...");
}
_ = async {
#[cfg(unix)]
{
match tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate())
{
Ok(mut sigterm) => {
sigterm.recv().await;
}
Err(e) => {
error!(error = ?e, "Failed to register SIGTERM handler");
std::future::pending::<()>().await;
}
}
}
#[cfg(not(unix))]
{
std::future::pending::<()>().await;
}
} => {
info!("Received SIGTERM, shutting down...");
}
}
server_for_shutdown.shutdown().await;
});
match server.serve(rmcp::transport::io::stdio()).await {
Ok(running_server) => {
info!("MCP server is serving...");
if let Err(e) = running_server.waiting().await {
error!(error = ?e, "Server error");
}
}
Err(e) => {
error!(error = ?e, "Failed to start MCP server");
return Err(ssh_mcp::SshMcpError::connection(e.to_string()));
}
}
shutdown_handle.abort();
info!("SSH MCP Server stopped");
Ok(())
}