use clap::Parser;
use turbovault_core::VaultConfig;
use turbovault::ObsidianMcpServer;
use turbovault_tools::OutputFormat;
use std::path::PathBuf;
use turbomcp_server::observability::ObservabilityConfig;
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
#[arg(short, long, env = "OBSIDIAN_VAULT_PATH")]
vault: Option<PathBuf>,
#[arg(short, long, default_value = "development")]
profile: String,
#[arg(short, long, default_value = "stdio")]
transport: String,
#[arg(long, default_value = "3000")]
port: u16,
#[arg(long, default_value = "json")]
output_format: String,
#[arg(long, action = clap::ArgAction::SetTrue)]
init: bool,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let args = Args::parse();
let output_format = if args.transport == "stdio" {
OutputFormat::Json
} else {
args.output_format.parse::<OutputFormat>()?
};
let _observability_guard = if args.transport == "stdio" {
let obs_config = ObservabilityConfig::default()
.with_service_name("turbovault")
.with_service_version(env!("CARGO_PKG_VERSION"))
.with_log_level(if args.profile == "production" {
"info,turbo_vault=debug".to_string()
} else {
"debug".to_string()
})
.enable_security_auditing()
.enable_performance_monitoring();
Some(obs_config.init()?)
} else {
use simple_logger::SimpleLogger;
match output_format {
OutputFormat::Json => {
let obs_config = ObservabilityConfig::default()
.with_service_name("turbovault")
.with_service_version(env!("CARGO_PKG_VERSION"))
.with_log_level(if args.profile == "production" {
"info,turbo_vault=debug".to_string()
} else {
"debug".to_string()
})
.enable_security_auditing()
.enable_performance_monitoring();
Some(obs_config.init()?)
}
OutputFormat::Human | OutputFormat::Text => {
SimpleLogger::new()
.with_level(if args.profile == "production" {
log::LevelFilter::Info
} else {
log::LevelFilter::Debug
})
.with_utc_timestamps()
.init()
.map_err(|e| format!("Failed to initialize logger: {}", e))?;
None
}
}
};
log::info!("Turbo Vault MCP Server v{}", env!("CARGO_PKG_VERSION"));
log::info!("Transport: {} | Log format: {:?}", args.transport, output_format);
let server =
ObsidianMcpServer::new().map_err(|e| format!("Failed to create MCP server: {}", e))?;
log::info!("MCP Server created (vault-agnostic mode)");
if let Some(vault_path) = args.vault {
log::info!("Adding vault from CLI argument: {:?}", vault_path);
let vault_config = VaultConfig::builder("default", &vault_path)
.build()
.map_err(|e| format!("Failed to create vault config: {}", e))?;
server
.multi_vault()
.add_vault(vault_config)
.await
.map_err(|e| format!("Failed to add vault: {}", e))?;
log::info!("Vault registered: default -> {:?}", vault_path);
if args.init {
log::info!("Scanning vault and building link graph...");
log::info!("Vault ready for operations");
}
} else {
log::info!("No vault path provided. Use add_vault MCP tool to register a vault.");
log::info!("Available tools: add_vault, list_vaults, set_active_vault");
}
log::info!("Starting TurboVault Server");
match args.transport.as_str() {
"stdio" => {
log::info!("Running in STDIO mode for MCP protocol");
server.run_stdio().await?;
}
#[cfg(feature = "http")]
"http" => {
let addr = format!("127.0.0.1:{}", args.port);
log::info!("Running HTTP server on {}", addr);
log::info!("Output format: {:?}", output_format);
server.run_http(&addr).await?;
}
#[cfg(feature = "websocket")]
"websocket" => {
let addr = format!("127.0.0.1:{}", args.port);
log::info!("Running WebSocket server on {}", addr);
log::info!("Output format: {:?}", output_format);
server.run_websocket(&addr).await?;
}
#[cfg(feature = "tcp")]
"tcp" => {
let addr = format!("127.0.0.1:{}", args.port);
log::info!("Running TCP server on {}", addr);
log::info!("Output format: {:?}", output_format);
server.run_tcp(&addr).await?;
}
#[cfg(feature = "unix")]
"unix" => {
let socket_path = "/tmp/turbovault.sock".to_string();
log::info!("Running Unix socket server on {}", socket_path);
log::info!("Output format: {:?}", output_format);
server.run_unix(&socket_path).await?;
}
transport => {
#[cfg(not(feature = "http"))]
if transport == "http" {
return Err("HTTP transport not enabled. Rebuild with --features http".into());
}
#[cfg(not(feature = "websocket"))]
if transport == "websocket" {
return Err("WebSocket transport not enabled. Rebuild with --features websocket".into());
}
#[cfg(not(feature = "tcp"))]
if transport == "tcp" {
return Err("TCP transport not enabled. Rebuild with --features tcp".into());
}
#[cfg(not(feature = "unix"))]
if transport == "unix" {
return Err("Unix socket transport not enabled. Rebuild with --features unix".into());
}
return Err(format!(
"Unknown transport '{}'. Valid options: stdio{}{}{}{}",
transport,
if cfg!(feature = "http") { ", http" } else { "" },
if cfg!(feature = "websocket") { ", websocket" } else { "" },
if cfg!(feature = "tcp") { ", tcp" } else { "" },
if cfg!(feature = "unix") { ", unix" } else { "" },
)
.into());
}
}
Ok(())
}