remem-ai 0.5.11

Persistent memory for Claude Code and Codex — single binary, automatic context
Documentation
use anyhow::Result;
use rmcp::model::{ServerCapabilities, ServerInfo};
use rmcp::{tool_handler, ServerHandler, ServiceExt};

use super::MemoryServer;
use crate::db;

const SERVER_INSTRUCTIONS: &str = r#"Persistent memory for Claude Code and Codex sessions.

Retrieval:
- Use `search(query, project?)` for compact memory IDs.
- Use `get_observations(ids, source)` only for selected full details.
- Use `search_raw(query)` for literal chat recall when curated search is sparse.
- Use `timeline(anchor/query)` for chronological context around a change.

Persistence:
- Use `save_memory` only for durable decisions, bugfix root causes, important discoveries, architecture notes, or user preferences.
- For user-requested documents, write the local/project file first; memory is only a backup.
- Search before saving and use a stable kebab-case `topic_key` for repeat topics.

Workstreams:
- `workstreams(project)` lists active tasks.
- `update_workstream(id, status?, next_action?, blockers?)` updates status, next action, or blockers."#;

#[tool_handler]
impl ServerHandler for MemoryServer {
    fn get_info(&self) -> ServerInfo {
        ServerInfo {
            instructions: Some(SERVER_INSTRUCTIONS.into()),
            capabilities: ServerCapabilities::builder().enable_tools().build(),
            ..Default::default()
        }
    }
}

pub async fn run_mcp_server() -> Result<()> {
    let db_path = crate::db::db_path();
    let db_exists = db_path.exists();
    crate::log::info(
        "mcp",
        &format!(
            "server starting db={} exists={}",
            db_path.display(),
            db_exists
        ),
    );
    let server = MemoryServer::new()?;
    if let Ok(conn) = db::open_db() {
        let mem_count: i64 = conn
            .query_row("SELECT count(*) FROM memories", [], |row| row.get(0))
            .unwrap_or(-1);
        let obs_count: i64 = conn
            .query_row("SELECT count(*) FROM observations", [], |row| row.get(0))
            .unwrap_or(-1);
        crate::log::info(
            "mcp",
            &format!(
                "server ready memories={} observations={}",
                mem_count, obs_count
            ),
        );
    }
    let service = server.serve(rmcp::transport::stdio()).await?;
    service.waiting().await?;
    crate::log::info("mcp", "server stopped");
    Ok(())
}