#![cfg_attr(coverage_nightly, coverage(off))]
use crate::services::agent_context::{AgentContextIndex, QueryOptions};
use async_trait::async_trait;
use serde_json::{json, Value};
use std::path::PathBuf;
use std::sync::Arc;
use std::time::Instant;
use tokio::sync::RwLock;
#[async_trait]
pub trait McpTool: Send + Sync {
fn name(&self) -> &str;
fn schema(&self) -> Value;
async fn execute(&self, params: Value) -> Result<Value, String>;
}
pub struct IndexManager {
index: RwLock<Option<AgentContextIndex>>,
project_path: PathBuf,
}
pub struct QueryCodeTool {
manager: Arc<IndexManager>,
}
pub struct GetFunctionTool {
manager: Arc<IndexManager>,
}
pub struct FindSimilarTool {
manager: Arc<IndexManager>,
}
pub struct IndexStatsTool {
manager: Arc<IndexManager>,
}
fn parse_function_id(function_id: &str) -> Result<(String, String), String> {
if let Some(pos) = function_id.rfind("::") {
let file_path = function_id.get(..pos).unwrap_or_default();
let function_name = function_id.get(pos + 2..).unwrap_or_default();
if file_path.is_empty() || function_name.is_empty() {
return Err(format!(
"Invalid function_id format. Expected 'file_path::function_name', got: {}",
function_id
));
}
Ok((file_path.to_string(), function_name.to_string()))
} else {
Err(format!(
"Invalid function_id format. Expected 'file_path::function_name', got: {}",
function_id
))
}
}
include!("agent_context_tools_index_manager.rs");
include!("agent_context_tools_query_tool.rs");
include!("agent_context_tools_lookup_tools.rs");
include!("agent_context_tools_tests.rs");