obsidian-mcp 2.2.1

MCP server for Obsidian vaults — direct filesystem access for AI agents
Documentation
use tracing_subscriber::EnvFilter;

use obsidian_mcp::config::DEFAULT_MODEL_NAME;
use obsidian_mcp::daemon::home::{self, semantic_home_paths};
use obsidian_mcp::daemon::server::{self, DaemonServerConfig, IpcEndpoint};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    if let Some(code) = handle_cli_flags() {
        std::process::exit(code);
    }

    let log_level = std::env::var("OBSIDIAN_LOG_LEVEL").unwrap_or_else(|_| "info".to_string());
    tracing_subscriber::fmt()
        .with_env_filter(EnvFilter::new(log_level))
        .with_writer(std::io::stderr)
        .init();

    let semantic_home = home::resolve_semantic_home()?;
    let paths = semantic_home_paths(&semantic_home);
    home::ensure_home_layout(&paths)?;

    let endpoint =
        resolve_endpoint_from_env().unwrap_or_else(|| home::default_ipc_endpoint(&paths));
    let model_name =
        std::env::var("OBSIDIAN_SEMANTIC_MODEL").unwrap_or_else(|_| DEFAULT_MODEL_NAME.to_string());

    tracing::info!(
        endpoint = %endpoint.endpoint_string(),
        semantic_home = %semantic_home.display(),
        "starting obsidian-semanticd"
    );

    let config = DaemonServerConfig {
        endpoint,
        model_name,
        semantic_home,
    };
    server::run(config).await?;
    Ok(())
}

fn handle_cli_flags() -> Option<i32> {
    let arg = std::env::args().nth(1)?;
    match arg.as_str() {
        "--version" | "-v" => {
            println!("obsidian-semanticd {}", env!("CARGO_PKG_VERSION"));
            Some(0)
        }
        "--help" | "-h" | "help" => {
            println!(
                "obsidian-semanticd {version} — semantic search daemon for obsidian-mcp\n\
                 \n\
                 USAGE:\n    \
                     obsidian-semanticd\n\
                 \n\
                 OPTIONS:\n    \
                     -h, --help       Print this help message\n    \
                     -v, --version    Print version\n\
                 \n\
                 ENVIRONMENT VARIABLES:\n    \
                     OBSIDIAN_LOG_LEVEL          Tracing log level           [default: info]\n    \
                     OBSIDIAN_SEMANTIC_HOME      Override semantic home dir\n    \
                     OBSIDIAN_SEMANTIC_ENDPOINT  Override IPC endpoint\n    \
                     OBSIDIAN_SEMANTIC_MODEL     Embedding model name        [default: {model}]",
                version = env!("CARGO_PKG_VERSION"),
                model = DEFAULT_MODEL_NAME,
            );
            Some(0)
        }
        _ => None,
    }
}

fn resolve_endpoint_from_env() -> Option<IpcEndpoint> {
    let raw = std::env::var("OBSIDIAN_SEMANTIC_ENDPOINT").ok()?;
    if raw.trim().is_empty() {
        return None;
    }
    #[cfg(unix)]
    {
        Some(IpcEndpoint::UnixSocket(std::path::PathBuf::from(raw)))
    }
    #[cfg(windows)]
    {
        Some(IpcEndpoint::NamedPipe(raw))
    }
}