use std::collections::HashMap;
use std::path::PathBuf;
use std::sync::Arc;
use tokio::sync::{Mutex, RwLock};
use tracing::info;
use ck_core::{SearchOptions, get_default_exclude_patterns};
use super::McpResult;
use super::cache::StatsCache;
use super::session::SessionManager;
#[derive(Clone)]
pub struct McpContext {
pub cwd: PathBuf,
pub stats_cache: StatsCache,
pub session_manager: SessionManager,
#[allow(dead_code)]
pub index_locks: Arc<RwLock<HashMap<PathBuf, Arc<Mutex<()>>>>>,
#[allow(dead_code)]
pub operation_tokens: Arc<RwLock<HashMap<String, tokio_util::sync::CancellationToken>>>,
#[allow(dead_code)]
pub default_search_options: SearchOptions,
}
impl McpContext {
pub fn new(cwd: PathBuf) -> McpResult<Self> {
info!("Initializing MCP context for directory: {}", cwd.display());
let default_search_options = SearchOptions {
mode: ck_core::SearchMode::Semantic,
query: String::new(),
path: cwd.clone(),
top_k: Some(10),
threshold: Some(0.6),
case_insensitive: false,
whole_word: false,
fixed_string: false,
line_numbers: false,
context_lines: 0,
before_context_lines: 0,
after_context_lines: 0,
recursive: true,
json_output: false,
jsonl_output: true, no_snippet: false,
reindex: false,
show_scores: true,
show_filenames: true,
files_with_matches: false,
files_without_matches: false,
exclude_patterns: get_default_exclude_patterns(),
include_patterns: Vec::new(),
respect_gitignore: true,
use_ckignore: true,
full_section: false,
rerank: false,
rerank_model: None,
embedding_model: None,
};
Ok(Self {
cwd,
stats_cache: StatsCache::default(), session_manager: SessionManager::default(), #[allow(dead_code)]
index_locks: Arc::new(RwLock::new(HashMap::new())),
#[allow(dead_code)]
operation_tokens: Arc::new(RwLock::new(HashMap::new())),
#[allow(dead_code)]
default_search_options,
})
}
#[allow(dead_code)]
pub async fn get_index_lock(&self, path: &PathBuf) -> Arc<Mutex<()>> {
let locks = self.index_locks.read().await;
if let Some(lock) = locks.get(path) {
return lock.clone();
}
drop(locks);
let new_lock = Arc::new(Mutex::new(()));
let mut locks = self.index_locks.write().await;
locks.insert(path.clone(), new_lock.clone());
new_lock
}
#[allow(dead_code)]
pub async fn register_operation(
&self,
operation_id: String,
) -> tokio_util::sync::CancellationToken {
let token = tokio_util::sync::CancellationToken::new();
let mut tokens = self.operation_tokens.write().await;
tokens.insert(operation_id, token.clone());
token
}
#[allow(dead_code)]
pub async fn cancel_operation(&self, operation_id: &str) -> bool {
let mut tokens = self.operation_tokens.write().await;
if let Some(token) = tokens.remove(operation_id) {
token.cancel();
true
} else {
false
}
}
}