use std::path::PathBuf;
use std::process::ExitCode;
use embedmind_core::Store;
use embedmind_mcp::{McpServer, OpLog, detect_project};
fn main() -> ExitCode {
let args = match parse_args() {
Ok(args) => args,
Err(message) => {
eprintln!("embedmind-mcp: {message}");
eprintln!("usage: embedmind-mcp [--file <path>] [--op-log <path>]");
return ExitCode::FAILURE;
}
};
let file = match args.file.map_or_else(default_memory_file, Ok) {
Ok(file) => file,
Err(message) => {
eprintln!("embedmind-mcp: {message}");
return ExitCode::FAILURE;
}
};
if let Some(parent) = file.parent()
&& !parent.as_os_str().is_empty()
&& let Err(e) = std::fs::create_dir_all(parent)
{
eprintln!("embedmind-mcp: cannot create {}: {e}", parent.display());
return ExitCode::FAILURE;
}
let store = match Store::open_or_create(&file) {
Ok(store) => store,
Err(e) => {
eprintln!("embedmind-mcp: cannot open {}: {e}", file.display());
return ExitCode::FAILURE;
}
};
let project = std::env::current_dir()
.ok()
.and_then(|cwd| detect_project(&cwd));
match &project {
Some(name) => eprintln!(
"embedmind-mcp: serving memories from {} (project: {name})",
file.display()
),
None => eprintln!(
"embedmind-mcp: serving memories from {} (no project context)",
file.display()
),
}
let mut server = McpServer::new(store, project);
if let Some(path) = args.op_log {
match OpLog::create(&path) {
Ok(op_log) => {
eprintln!("embedmind-mcp: op-log appending to {}", path.display());
server = server.with_op_log(op_log);
}
Err(e) => {
eprintln!("embedmind-mcp: cannot open op-log {}: {e}", path.display());
return ExitCode::FAILURE;
}
}
}
let stdin = std::io::stdin();
let stdout = std::io::stdout();
match server.serve(stdin.lock(), stdout.lock()) {
Ok(()) => ExitCode::SUCCESS,
Err(e) => {
eprintln!("embedmind-mcp: transport error: {e}");
ExitCode::FAILURE
}
}
}
struct Args {
file: Option<PathBuf>,
op_log: Option<PathBuf>,
}
fn parse_args() -> Result<Args, String> {
let mut args = std::env::args_os().skip(1);
let mut file = None;
let mut op_log = None;
while let Some(arg) = args.next() {
if arg == "--file" {
let value = args.next().ok_or("--file requires a path")?;
file = Some(PathBuf::from(value));
} else if arg == "--op-log" {
let value = args.next().ok_or("--op-log requires a path")?;
op_log = Some(PathBuf::from(value));
} else {
return Err(format!("unknown argument: {}", arg.to_string_lossy()));
}
}
Ok(Args { file, op_log })
}
fn default_memory_file() -> Result<PathBuf, String> {
let home = std::env::var_os("HOME")
.or_else(|| std::env::var_os("USERPROFILE"))
.ok_or("cannot determine home directory (HOME/USERPROFILE unset); pass --file")?;
Ok(PathBuf::from(home).join(".embedmind").join("memory.mind"))
}