rag-server-mcp 2.3.2

Sovereign, high-performance RAG MCP server written in Rust for local code and legal search.
use anyhow::Result;
use std::env;
use std::path::PathBuf;

#[derive(Debug, Clone)]
pub struct Config {
    pub db_path: String,
    pub tokenizer_path: String,
    pub embed_url: String,
    pub rerank_url: String,
    pub chunk_size: usize,
    pub chunk_overlap: usize,
    pub embed_batch_size: usize,
    pub rerank_candidates: usize,
    pub timeout_secs: u64,
    pub embed_model: String,
    pub rerank_model: String,
    pub rerank_min_score: f64,
    pub max_concurrent_files: usize,
    pub max_concurrent_requests: Option<usize>,
    pub rerank_min_candidates: Option<usize>,
    // cache_ttl_secs borttagen – används inte
}

impl Config {
    pub fn from_env() -> Result<Self> {
        let base_dir = PathBuf::from("/home/bfrost/.config/rag-server");
        std::fs::create_dir_all(&base_dir)?;

        Ok(Self {
            db_path: base_dir.join("vectors.db").to_string_lossy().into_owned(),
            tokenizer_path: base_dir
                .join("tokenizer.json")
                .to_string_lossy()
                .into_owned(),
            embed_url: env::var("RAG_EMBED_URL")
                .unwrap_or_else(|_| "http://localhost:11435/v1/embeddings".to_string()),
            rerank_url: env::var("RAG_RERANK_URL")
                .unwrap_or_else(|_| "http://localhost:11436/rerank".to_string()),
            chunk_size: env::var("RAG_CHUNK_SIZE")
                .unwrap_or_else(|_| "1024".to_string())
                .parse()
                .unwrap_or(1024),
            chunk_overlap: env::var("RAG_CHUNK_OVERLAP")
                .unwrap_or_else(|_| "150".to_string())
                .parse()
                .unwrap_or(150),
            embed_batch_size: env::var("RAG_BATCH_SIZE")
                .unwrap_or_else(|_| "8".to_string())
                .parse()
                .unwrap_or(8),
            rerank_candidates: env::var("RAG_RERANK_K")
                .unwrap_or_else(|_| "15".to_string())
                .parse()
                .unwrap_or(15),
            timeout_secs: 14400,
            embed_model: env::var("RAG_EMBED_MODEL")
                .unwrap_or_else(|_| "bge-m3".to_string()),
            rerank_model: env::var("RAG_RERANK_MODEL")
                .unwrap_or_else(|_| "bge-reranker-v2-m3".to_string()),
            rerank_min_score: env::var("RAG_RERANK_MIN_SCORE")
                .unwrap_or_else(|_| "0.3".to_string())
                .parse()
                .unwrap_or(0.3),
            max_concurrent_files: env::var("RAG_MAX_CONCURRENT_FILES")
                .unwrap_or_else(|_| "4".to_string())
                .parse()
                .unwrap_or(4),
            max_concurrent_requests: env::var("RAG_MAX_CONCURRENT_REQUESTS")
                .ok()
                .and_then(|s| s.parse().ok()),
            rerank_min_candidates: env::var("RAG_RERANK_MIN_CANDIDATES")
                .ok()
                .and_then(|s| s.parse().ok()),
        })
    }
}