use anyhow::{bail, Result};
use clap::Parser;
use mcp_git::server;
use rmcp::{transport::stdio, ServiceExt};
use tracing_subscriber::EnvFilter;
#[derive(Parser)]
#[command(name = "mcp-git", version, about)]
struct Cli {
#[arg(long = "repo")]
repos: Vec<String>,
#[arg(long, default_value = "500")]
max_diff_lines: u32,
#[arg(long, default_value = "50")]
max_log_entries: u32,
}
#[tokio::main]
async fn main() -> Result<()> {
let cli = Cli::parse();
tracing_subscriber::fmt()
.with_env_filter(EnvFilter::from_default_env())
.with_writer(std::io::stderr)
.init();
let repo_paths = if cli.repos.is_empty() {
vec![".".to_string()]
} else {
cli.repos
};
let mut entries = Vec::new();
for path in &repo_paths {
let canonical = std::fs::canonicalize(path)
.map_err(|e| anyhow::anyhow!("Cannot resolve path '{}': {}", path, e))?;
let repo = gix::discover(&canonical)
.map_err(|e| anyhow::anyhow!("Not a git repository '{}': {}", path, e))?;
let name = canonical
.file_name()
.map(|n| n.to_string_lossy().to_string())
.unwrap_or_else(|| path.clone());
let work_dir = repo
.work_dir()
.map(|p| p.to_path_buf())
.unwrap_or_else(|| canonical.clone());
entries.push(server::RepoEntry {
name,
path: work_dir,
});
tracing::info!(path = %canonical.display(), "Discovered git repository");
}
if entries.is_empty() {
bail!("No valid git repositories found.");
}
tracing::info!(
repos = entries.len(),
max_diff_lines = cli.max_diff_lines,
max_log_entries = cli.max_log_entries,
"Starting mcp-git server"
);
let service = server::McpGitServer::new(entries, cli.max_diff_lines, cli.max_log_entries);
let running = service.serve(stdio()).await?;
running.waiting().await?;
Ok(())
}