use clap::{Arg, ArgMatches, Command};
use tracing::Level;
use crate::Result;
use crate::config::Config;
pub fn build() -> Command {
Command::new("start")
.about("Start the MCP server")
.long_about("Start stdio server to expose CLI commands to AI assistants")
.arg(
Arg::new("log-level")
.long("log-level")
.value_name("LEVEL")
.help("Log level (trace, debug, info, warn, error)"),
)
}
pub async fn run(matches: &ArgMatches, cli: Command, cfg: Option<Config>) -> Result<()> {
let log_level = parse_log_level(matches);
crate::server::stdio::serve_stdio(cli, cfg, log_level).await
}
pub fn parse_log_level_for_test(matches: &ArgMatches) -> Option<Level> {
parse_log_level(matches)
}
pub fn build_for_test() -> Command {
build()
}
fn parse_log_level(matches: &ArgMatches) -> Option<Level> {
super::common::parse_log_level(matches)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn start_subcommand_has_log_level_flag() {
let cmd = build();
let arg = cmd
.get_arguments()
.find(|a| a.get_id().as_str() == "log-level")
.expect("--log-level flag must be present");
assert_eq!(arg.get_long(), Some("log-level"));
}
#[test]
fn parse_log_level_recognises_common_values() {
for (raw, expected) in [
("trace", Level::TRACE),
("debug", Level::DEBUG),
("info", Level::INFO),
("warn", Level::WARN),
("warning", Level::WARN),
("error", Level::ERROR),
("INFO", Level::INFO),
] {
let matches = Command::new("start")
.arg(Arg::new("log-level").long("log-level"))
.try_get_matches_from(["start", "--log-level", raw])
.expect("parses");
assert_eq!(parse_log_level(&matches), Some(expected), "raw={raw}");
}
}
#[test]
fn parse_log_level_unknown_returns_none() {
let matches = Command::new("start")
.arg(Arg::new("log-level").long("log-level"))
.try_get_matches_from(["start", "--log-level", "verbose"])
.expect("parses");
assert!(parse_log_level(&matches).is_none());
}
#[test]
fn parse_log_level_absent_returns_none() {
let matches = Command::new("start")
.arg(Arg::new("log-level").long("log-level"))
.try_get_matches_from(["start"])
.expect("parses");
assert!(parse_log_level(&matches).is_none());
}
}