use std::process::ExitCode;
use promptforge_mcp_server::{ServerArgs, run};
const USAGE: &str = "usage: promptforge-mcp-server serve [--stdio] <prompts.toml>";
fn main() -> ExitCode {
let Some(args) = ServerArgs::parse(std::env::args_os().skip(1)) else {
eprintln!("{USAGE}");
return ExitCode::FAILURE;
};
if args.stdio() {
tracing_subscriber::fmt()
.with_writer(std::io::stderr)
.init();
} else {
tracing_subscriber::fmt()
.with_writer(std::io::stdout)
.init();
}
match run(&args) {
Ok(()) => ExitCode::SUCCESS,
Err(error) => {
eprintln!("{}", report(&error));
ExitCode::FAILURE
}
}
}
fn report(error: &(dyn std::error::Error + 'static)) -> String {
let mut out = format!("error: {error}");
let mut cause = error.source();
while let Some(source) = cause {
out.push_str("\n caused by: ");
out.push_str(&source.to_string());
cause = source.source();
}
out
}
#[cfg(test)]
mod tests {
use promptforge_mcp_server::Config;
use tempfile::TempDir;
use super::report;
#[test]
fn a_report_carries_every_cause_under_the_outermost_message() {
let dir = TempDir::new().expect("create a temporary directory");
let missing = dir.path().join("no-such-prompts-file.toml");
let error = Config::load(&missing).expect_err("a missing configuration is refused");
let text = report(&error);
let mut lines = text.lines();
let first = lines.next().expect("the outermost message is printed");
assert!(first.starts_with("error: read config "), "{text}");
assert!(
first.contains("no-such-prompts-file.toml"),
"the failing path is named: {text}"
);
let cause = lines.next().expect("the I/O reason is printed under it");
assert!(cause.starts_with(" caused by: "), "{text}");
assert!(cause.len() > " caused by: ".len(), "{text}");
}
}