use crate::Config;
use crate::embedding::EmbeddingEngine;
use crate::errors::Error;
use crate::mcp::tools::ToolHandler;
use crate::memory::MemoryStore;
use std::sync::mpsc;
use std::sync::{Arc, Mutex};
use std::time::Duration;
pub fn run_mcp(config: Config, project_id: &str) -> Result<(), Error> {
let mut store = MemoryStore::new(
&config.database_path,
&config.embedding_model,
config.clone(),
)?;
let model_id = config.embedding_model.clone();
let model_id_for_thread = model_id.clone();
let (tx, rx) = mpsc::channel();
let init_thread = std::thread::spawn(move || {
let _ = tx.send(EmbeddingEngine::new(&model_id_for_thread));
});
let engine = match rx.recv_timeout(Duration::from_secs(120)) {
Ok(Ok(engine)) => engine,
Ok(Err(e)) => {
let _ = init_thread.join();
return Err(Error::EmbedderUnavailable {
reason: format!("Failed to load embedding model '{}': {}", model_id, e),
});
}
Err(mpsc::RecvTimeoutError::Timeout) => {
drop(init_thread); return Err(Error::EmbedderUnavailable {
reason: format!(
"Embedding model '{}' download timed out after 120s. Check network connectivity to HuggingFace Hub.",
model_id
),
});
}
Err(mpsc::RecvTimeoutError::Disconnected) => {
let _ = init_thread.join();
return Err(Error::EmbedderUnavailable {
reason: format!(
"Embedding model '{}' initialization thread panicked. Check disk space and permissions for model cache.",
model_id
),
});
}
};
store.set_preinitialized_embedder(engine);
let store = Arc::new(Mutex::new(store));
let handler = ToolHandler::new(store, project_id.to_string(), config);
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.map_err(|e| Error::Config(format!("Failed to create tokio runtime: {}", e)))?;
runtime.block_on(async {
let (stdin, stdout) = rmcp::transport::stdio();
let service = rmcp::serve_server(handler, (stdin, stdout))
.await
.map_err(|e| Error::Config(format!("MCP server error: {}", e)))?;
service
.waiting()
.await
.map_err(|e| Error::Config(format!("MCP server task error: {}", e)))?;
Ok(())
})
}