use anyhow::Result;
use clap::Args;
use octocode::config::Config;
use octocode::indexer;
use octocode::mcp::{McpServer, MultiServer};
#[derive(Args, Clone)]
pub struct McpArgs {
#[arg(long)]
pub debug: bool,
#[arg(long, default_value = ".")]
pub path: String,
#[arg(long)]
pub no_git: bool,
#[arg(long, value_name = "COMMAND")]
pub with_lsp: Option<String>,
#[arg(long, value_name = "HOST:PORT")]
pub bind: Option<String>,
#[arg(long)]
pub multi: bool,
}
pub async fn run(args: McpArgs) -> Result<()> {
let config = Config::load()?;
let working_directory = std::path::Path::new(&args.path)
.canonicalize()
.map_err(|e| anyhow::anyhow!("Invalid path '{}': {}", args.path, e))?;
if !working_directory.is_dir() {
return Err(anyhow::anyhow!(
"Path '{}' is not a directory",
working_directory.display()
));
}
if args.multi {
let server = MultiServer::new(config, working_directory, args.no_git, args.debug).await?;
return match args.bind {
Some(bind_addr) => server.run_http(&bind_addr).await,
None => server.run_stdio().await,
};
}
if config.index.require_git
&& !args.no_git
&& !indexer::git::is_git_repo_root(&working_directory)
{
return Err(anyhow::anyhow!(
"'{}' is not a git repository. Run `octocode mcp` from a git repo root, \
pass --no-git to serve a non-git directory, or use --multi to serve \
repositories found under this path.",
working_directory.display()
));
}
let (server, bg) = McpServer::new(
config,
args.debug,
working_directory,
args.no_git,
args.with_lsp,
)
.await?;
if let Some(bind_addr) = args.bind {
server.run_http(&bind_addr, bg).await
} else {
server.run_stdio(bg).await
}
}