use std::{env, path::PathBuf, process::ExitCode, time::Duration};
use mcport::FlushPolicy;
use weavatrix_git::mcp::{open_server, runtime_config};
fn main() -> ExitCode {
match run(&env::args().skip(1).collect::<Vec<_>>()) {
Ok(()) => ExitCode::SUCCESS,
Err(error) => {
eprintln!("weavatrix-git-mcp: {error}");
ExitCode::FAILURE
}
}
}
fn run(arguments: &[String]) -> Result<(), Box<dyn std::error::Error>> {
if arguments
.iter()
.any(|value| value == "--help" || value == "-h")
{
print_help();
return Ok(());
}
if arguments
.iter()
.any(|value| value == "--version" || value == "-V")
{
println!("weavatrix-git-mcp {}", env!("CARGO_PKG_VERSION"));
return Ok(());
}
if arguments.iter().any(|value| value == "--build-info") {
print_build_info();
return Ok(());
}
let mut repository = PathBuf::from(".");
let mut runtime = runtime_config();
let mut index = 0;
while index < arguments.len() {
let option = &arguments[index];
let value = arguments
.get(index + 1)
.ok_or_else(|| format!("{option} requires a value"))?;
match option.as_str() {
"--repository" | "-C" => repository = PathBuf::from(value),
"--max-request-bytes" => runtime.transport.max_request_bytes = parse(value, option)?,
"--max-response-bytes" => runtime.transport.max_response_bytes = parse(value, option)?,
"--max-in-flight" => runtime.max_in_flight = parse(value, option)?,
"--queue-depth" => runtime.queue_depth = parse(value, option)?,
"--output-queue-depth" => runtime.output_queue_depth = parse(value, option)?,
"--handler-deadline-ms" => {
let milliseconds: u64 = parse(value, option)?;
runtime.handler_deadline =
(milliseconds > 0).then(|| Duration::from_millis(milliseconds));
}
"--batch-size" => {
let max_messages = parse(value, option)?;
runtime.output_flush_policy = if max_messages <= 1 {
FlushPolicy::PerMessage
} else {
FlushPolicy::Batch { max_messages }
};
}
_ => return Err(format!("unknown option {option:?}; use --help").into()),
}
index += 2;
}
open_server(repository)?.serve(runtime)?;
Ok(())
}
fn parse<T>(value: &str, option: &str) -> Result<T, Box<dyn std::error::Error>>
where
T: std::str::FromStr,
T::Err: std::fmt::Display,
{
value
.parse()
.map_err(|error| format!("invalid value for {option}: {error}").into())
}
fn print_build_info() {
println!(
concat!(
"{{\"name\":\"weavatrix-git-mcp\",\"version\":\"{}\",",
"\"git_sha\":\"{}\",\"platform\":\"{}\",\"arch\":\"{}\"}}"
),
env!("CARGO_PKG_VERSION"),
option_env!("WEAVATRIX_GIT_BUILD_SHA").unwrap_or("unknown"),
env::consts::OS,
env::consts::ARCH
);
}
fn print_help() {
println!(
"\
weavatrix-git-mcp {}
USAGE:
weavatrix-git-mcp [OPTIONS]
OPTIONS:
-C, --repository <PATH> Repository to expose (default: current directory)
--max-request-bytes <N> Input frame budget
--max-response-bytes <N> Output frame budget
--max-in-flight <N> Concurrent handler ceiling
--queue-depth <N> Waiting request ceiling
--output-queue-depth <N> Complete response queue ceiling
--handler-deadline-ms <N> Handler deadline; 0 disables it
--batch-size <N> Flush after N responses; 1 is interactive
--build-info Print native binary provenance
-V, --version Print version
-h, --help Print help",
env!("CARGO_PKG_VERSION")
);
}