fix: restore AppError::Internal for AST parser error, keeping BadRequest for JSON schema validation

This commit is contained in:
Riz Ashraf committed 2026-10-10 13:10:15 +01:00
1 parent 39528411f4
commit de060c4db4
10 files changed
+57 -57

No files matched your search

+7 -7
View File
@@ -41,7 +41,7 @@ impl McpTool for ReadFileSkeletonHandler {
async fn execute(&self, args: Value, _state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, _state: Arc<MemoryState>) -> crate::error::Result<String> {
let tool_args: ReadFileSkeletonTool = let tool_args: ReadFileSkeletonTool =
serde_json::from_value(args).map_err(|e| e.to_string())?; serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let file_path = tool_args.file_path.clone(); let file_path = tool_args.file_path.clone();
validate_safe_path(&file_path)?; validate_safe_path(&file_path)?;
@@ -202,7 +202,7 @@ impl McpTool for ReplaceAstNodeHandler {
async fn execute(&self, args: Value, _state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, _state: Arc<MemoryState>) -> crate::error::Result<String> {
let tool_args: ReplaceAstNodeTool = let tool_args: ReplaceAstNodeTool =
serde_json::from_value(args).map_err(|e| e.to_string())?; serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let file_path = tool_args.file_path.clone(); let file_path = tool_args.file_path.clone();
validate_safe_path(&file_path)?; validate_safe_path(&file_path)?;
@@ -237,7 +237,7 @@ impl McpTool for ReplaceAstNodeHandler {
parser parser
.set_language(&language.into()) .set_language(&language.into())
.map_err(|e| e.to_string())?; .map_err(|e| crate::error::AppError::Internal(e.to_string()))?;
let tree = parser.parse(&code, None).ok_or_else(|| { let tree = parser.parse(&code, None).ok_or_else(|| {
crate::error::AppError::Internal("Failed to parse code".to_string()) crate::error::AppError::Internal("Failed to parse code".to_string())
})?; })?;
@@ -342,7 +342,7 @@ impl McpTool for ReplaceAstNodeHandler {
.unwrap_or_else(|| std::path::Path::new(".")); .unwrap_or_else(|| std::path::Path::new("."));
let temp_file_path = let temp_file_path =
parent_dir.join(format!(".tmp_ast_{}.tmp", uuid::Uuid::new_v4())); parent_dir.join(format!(".tmp_ast_{}.tmp", uuid::Uuid::new_v4()));
std::fs::write(&temp_file_path, new_file_content).map_err(|e| e.to_string())?; std::fs::write(&temp_file_path, new_file_content).map_err(|e| crate::error::AppError::Internal(format!("Failed to write temporary file: {}", e)))?;
if let Err(e) = std::fs::rename(&temp_file_path, &target_path) { if let Err(e) = std::fs::rename(&temp_file_path, &target_path) {
// On Windows, std::fs::rename fails if the target file already exists. // On Windows, std::fs::rename fails if the target file already exists.
// Fall back to copy-and-remove to ensure atomic-like overwrite behavior. // Fall back to copy-and-remove to ensure atomic-like overwrite behavior.
@@ -473,7 +473,7 @@ impl McpTool for FindSymbolReferencesHandler {
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: crate::tools::FindSymbolReferencesTool = let req: crate::tools::FindSymbolReferencesTool =
serde_json::from_value(args).map_err(|e| e.to_string())?; serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let limit = req.limit.unwrap_or(10); let limit = req.limit.unwrap_or(10);
let target_sym = req.symbol.clone(); let target_sym = req.symbol.clone();
@@ -527,7 +527,7 @@ impl McpTool for GetCallersHandler {
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: crate::tools::GetCallersTool = let req: crate::tools::GetCallersTool =
serde_json::from_value(args).map_err(|e| e.to_string())?; serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let limit = req.limit.unwrap_or(10); let limit = req.limit.unwrap_or(10);
let target_fn = req.function_name.clone(); let target_fn = req.function_name.clone();
let call_pattern = format!("{}(", target_fn); let call_pattern = format!("{}(", target_fn);
@@ -583,7 +583,7 @@ impl McpTool for AnalyzeImpactHandler {
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: crate::tools::AnalyzeImpactTool = let req: crate::tools::AnalyzeImpactTool =
serde_json::from_value(args).map_err(|e| e.to_string())?; serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let sym = req.target_symbol.clone(); let sym = req.target_symbol.clone();
let mut callers = Vec::new(); let mut callers = Vec::new();
+1 -1
View File
@@ -21,7 +21,7 @@ impl McpTool for EnvironmentHandler {
} }
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: EnvironmentTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let req: EnvironmentTool = serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let ns = req let ns = req
.namespace .namespace
.unwrap_or_else(crate::models::default_namespace); .unwrap_or_else(crate::models::default_namespace);
+2 -2
View File
@@ -28,7 +28,7 @@ impl McpTool for GetActiveWorktreeContextHandler {
) -> crate::error::Result<String> { ) -> crate::error::Result<String> {
let result = let result =
tokio::task::spawn_blocking(move || -> crate::error::Result<serde_json::Value> { tokio::task::spawn_blocking(move || -> crate::error::Result<serde_json::Value> {
let cwd = env::current_dir().map_err(|e| e.to_string())?; let cwd = env::current_dir().map_err(|e| crate::error::AppError::Internal(format!("Failed to get current directory: {}", e)))?;
let repo = git2::Repository::discover(&cwd).map_err(|e| { let repo = git2::Repository::discover(&cwd).map_err(|e| {
crate::error::AppError::Internal(format!("Not in a git repository: {}", e)) crate::error::AppError::Internal(format!("Not in a git repository: {}", e))
})?; })?;
@@ -108,7 +108,7 @@ impl McpTool for QueryGitDiffsHandler {
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: crate::tools::QueryGitDiffsTool = let req: crate::tools::QueryGitDiffsTool =
serde_json::from_value(args).map_err(|e| e.to_string())?; serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let limit = req.limit.unwrap_or(5); let limit = req.limit.unwrap_or(5);
let q = req.query.to_lowercase(); let q = req.query.to_lowercase();
+17 -17
View File
@@ -121,7 +121,7 @@ impl McpTool for QueryGraphPathHandler {
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: crate::tools::QueryGraphPathTool = let req: crate::tools::QueryGraphPathTool =
serde_json::from_value(args).map_err(|e| e.to_string())?; serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
tokio::task::spawn_blocking(move || { tokio::task::spawn_blocking(move || {
state.read_graph(|graph| { state.read_graph(|graph| {
@@ -160,7 +160,7 @@ impl McpTool for CreateEntitiesHandler {
} }
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: CreateEntitiesTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let req: CreateEntitiesTool = serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let mut inserted = Vec::new(); let mut inserted = Vec::new();
state.modify_graph(|g| { state.modify_graph(|g| {
for entity_input in req.entities { for entity_input in req.entities {
@@ -209,7 +209,7 @@ impl McpTool for UpdateEntitiesHandler {
} }
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: UpdateEntitiesTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let req: UpdateEntitiesTool = serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let mut updated_entities = Vec::new(); let mut updated_entities = Vec::new();
let mut deleted_names = Vec::new(); let mut deleted_names = Vec::new();
@@ -414,7 +414,7 @@ impl McpTool for AddObservationsHandler {
} }
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: AddObservationsTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let req: AddObservationsTool = serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let mut missing_entities = Vec::new(); let mut missing_entities = Vec::new();
state.read_graph(|g| { state.read_graph(|g| {
for o in &req.observations { for o in &req.observations {
@@ -458,7 +458,7 @@ impl McpTool for DeleteEntitiesHandler {
} }
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: DeleteEntitiesTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let req: DeleteEntitiesTool = serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let to_delete: std::collections::HashSet<_> = req.entity_names.into_iter().collect(); let to_delete: std::collections::HashSet<_> = req.entity_names.into_iter().collect();
let mut missing = Vec::new(); let mut missing = Vec::new();
state.read_graph(|g| { state.read_graph(|g| {
@@ -510,7 +510,7 @@ impl McpTool for DeleteObservationsHandler {
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: DeleteObservationsTool = let req: DeleteObservationsTool =
serde_json::from_value(args).map_err(|e| e.to_string())?; serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let mut missing_entities = Vec::new(); let mut missing_entities = Vec::new();
let mut missing_observations = Vec::new(); let mut missing_observations = Vec::new();
@@ -573,7 +573,7 @@ impl McpTool for DeleteRelationsHandler {
} }
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: DeleteRelationsTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let req: DeleteRelationsTool = serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let mut deleted_count = 0; let mut deleted_count = 0;
let requested_count = req.relations.len(); let requested_count = req.relations.len();
@@ -615,7 +615,7 @@ impl McpTool for ReadGraphHandler {
} }
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: ReadGraphTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let req: ReadGraphTool = serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let max_tokens = req.max_tokens; let max_tokens = req.max_tokens;
let limit = req.limit; let limit = req.limit;
let offset = req.offset.unwrap_or(0); let offset = req.offset.unwrap_or(0);
@@ -751,7 +751,7 @@ impl McpTool for SearchNodesHandler {
} }
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: SearchNodesTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let req: SearchNodesTool = serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let limit = req.limit.unwrap_or(10); let limit = req.limit.unwrap_or(10);
let include_body = req.include_body.unwrap_or(false); let include_body = req.include_body.unwrap_or(false);
@@ -801,7 +801,7 @@ impl McpTool for OpenNodesHandler {
} }
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: OpenNodesTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let req: OpenNodesTool = serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let data = state.read_graph(|full| -> crate::error::Result<String> { let data = state.read_graph(|full| -> crate::error::Result<String> {
let targets: HashSet<&str> = req.names.iter().map(|s| s.as_str()).collect(); let targets: HashSet<&str> = req.names.iter().map(|s| s.as_str()).collect();
let mut result = BorrowedGraph::default(); let mut result = BorrowedGraph::default();
@@ -842,7 +842,7 @@ impl McpTool for VisualizeGraphHandler {
} }
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: VisualizeGraphTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let req: VisualizeGraphTool = serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let query = req.query.unwrap_or_default(); let query = req.query.unwrap_or_default();
let mut output = state.read_graph(|full| { let mut output = state.read_graph(|full| {
let mut included: HashSet<&str> = HashSet::new(); let mut included: HashSet<&str> = HashSet::new();
@@ -934,7 +934,7 @@ impl McpTool for CondenseEntityHandler {
} }
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: CondenseEntityTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let req: CondenseEntityTool = serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let mut missing = false; let mut missing = false;
if req.summarized_observations.is_empty() { if req.summarized_observations.is_empty() {
@@ -1020,7 +1020,7 @@ impl McpTool for MergeEntitiesHandler {
} }
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: MergeEntitiesTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let req: MergeEntitiesTool = serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let mut missing = false; let mut missing = false;
state.modify_graph(|master| { state.modify_graph(|master| {
if let Some(src) = master.entities.remove(&req.source_entity) { if let Some(src) = master.entities.remove(&req.source_entity) {
@@ -1116,7 +1116,7 @@ impl McpTool for GetSubgraphHandler {
} }
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: GetSubgraphTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let req: GetSubgraphTool = serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let root = req.root_entity.ok_or_else(|| { let root = req.root_entity.ok_or_else(|| {
crate::error::AppError::Internal("root_entity is required".to_string()) crate::error::AppError::Internal("root_entity is required".to_string())
})?; })?;
@@ -1211,7 +1211,7 @@ impl McpTool for SweepGraphHealthHandler {
} }
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: SweepGraphHealthTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let req: SweepGraphHealthTool = serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let auto_prune = req.auto_prune_orphans.unwrap_or(false); let auto_prune = req.auto_prune_orphans.unwrap_or(false);
let auto_prune_stale = req.auto_prune_stale_files.unwrap_or(false); let auto_prune_stale = req.auto_prune_stale_files.unwrap_or(false);
@@ -1309,7 +1309,7 @@ impl McpTool for ResolveStaleSymbolsHandler {
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: ResolveStaleSymbolsTool = let req: ResolveStaleSymbolsTool =
serde_json::from_value(args).map_err(|e| e.to_string())?; serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let auto_heal = req.auto_heal.unwrap_or(true); let auto_heal = req.auto_heal.unwrap_or(true);
let mut checked = 0; let mut checked = 0;
@@ -1367,7 +1367,7 @@ impl McpTool for SummarizeSubgraphHandler {
} }
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: SummarizeSubgraphTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let req: SummarizeSubgraphTool = serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let depth = req.depth.unwrap_or(2); let depth = req.depth.unwrap_or(2);
let (sub_entities, sub_relations) = state.read_graph(|g| { let (sub_entities, sub_relations) = state.read_graph(|g| {
+4 -4
View File
@@ -23,7 +23,7 @@ impl McpTool for ProcessLogsHandler {
} }
async fn execute(&self, args: Value, _state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, _state: Arc<MemoryState>) -> crate::error::Result<String> {
let tool_args: ProcessLogsTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let tool_args: ProcessLogsTool = serde_json::from_value(args).map_err(|e| crate::error::AppError::Internal(format!("Failed to seek file: {}", e)))?;
let safe_path = crate::handlers::utils::validate_safe_path(&tool_args.file_path)?; let safe_path = crate::handlers::utils::validate_safe_path(&tool_args.file_path)?;
match tool_args.action { match tool_args.action {
@@ -43,14 +43,14 @@ impl McpTool for ProcessLogsHandler {
let mut file = File::open(&safe_path).map_err(|e| { let mut file = File::open(&safe_path).map_err(|e| {
crate::error::AppError::Internal(format!("Failed to open file: {}", e)) crate::error::AppError::Internal(format!("Failed to open file: {}", e))
})?; })?;
let len = file.metadata().map_err(|e| e.to_string())?.len(); let len = file.metadata().map_err(|e| crate::error::AppError::Internal(format!("Failed to read file metadata: {}", e)))?.len();
let read_size = std::cmp::min(16 * 1024, len); let read_size = std::cmp::min(16 * 1024, len);
file.seek(SeekFrom::End(-(read_size as i64))) file.seek(SeekFrom::End(-(read_size as i64)))
.map_err(|e| e.to_string())?; .map_err(|e| crate::error::AppError::Internal(format!("Failed to seek file: {}", e)))?;
let mut vec_buf = Vec::new(); let mut vec_buf = Vec::new();
file.read_to_end(&mut vec_buf).map_err(|e| e.to_string())?; file.read_to_end(&mut vec_buf).map_err(|e| crate::error::AppError::Internal(format!("Failed to seek file: {}", e)))?;
let buffer = String::from_utf8_lossy(&vec_buf).to_string(); let buffer = String::from_utf8_lossy(&vec_buf).to_string();
let lines: Vec<&str> = buffer.lines().collect(); let lines: Vec<&str> = buffer.lines().collect();
+14 -14
View File
@@ -22,7 +22,7 @@ impl McpTool for LogErrorFixHandler {
} }
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: LogErrorFixTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let req: LogErrorFixTool = serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let text_to_embed = format!("Signature: {}\nSolution: {}", req.signature, req.solution); let text_to_embed = format!("Signature: {}\nSolution: {}", req.signature, req.solution);
let solution = req.solution; let solution = req.solution;
@@ -71,7 +71,7 @@ impl McpTool for SearchErrorFixesHandler {
} }
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: SearchErrorFixesTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let req: SearchErrorFixesTool = serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let limit = req.limit.unwrap_or(5); let limit = req.limit.unwrap_or(5);
let include_body = req.include_body.unwrap_or(true); let include_body = req.include_body.unwrap_or(true);
@@ -175,7 +175,7 @@ impl McpTool for LogCodeChangeHandler {
} }
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: LogCodeChangeTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let req: LogCodeChangeTool = serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let mut description = req.description; let mut description = req.description;
if let Some(range) = &req.line_range { if let Some(range) = &req.line_range {
@@ -353,7 +353,7 @@ impl McpTool for DecisionsHandler {
} }
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: DecisionsTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let req: DecisionsTool = serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
match req { match req {
DecisionsTool::Log { title, status, context, decision, consequences, namespace, repo_name, author, affected_components, alternatives_considered, supersedes, git_commit, git_branch, task_id } => { DecisionsTool::Log { title, status, context, decision, consequences, namespace, repo_name, author, affected_components, alternatives_considered, supersedes, git_commit, git_branch, task_id } => {
let ns = namespace.clone().unwrap_or_else(crate::models::default_namespace); let ns = namespace.clone().unwrap_or_else(crate::models::default_namespace);
@@ -607,7 +607,7 @@ impl McpTool for TechDebtHandler {
} }
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: TechDebtTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let req: TechDebtTool = serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
match req { match req {
TechDebtTool::Log { description, title: _, ideal_solution, git_commit, git_branch, symbol_references: _, line_range, namespace, severity, repo_name, file_path, workaround, effort_estimate } => { TechDebtTool::Log { description, title: _, ideal_solution, git_commit, git_branch, symbol_references: _, line_range, namespace, severity, repo_name, file_path, workaround, effort_estimate } => {
let ns = namespace.clone().unwrap_or_else(crate::models::default_namespace); let ns = namespace.clone().unwrap_or_else(crate::models::default_namespace);
@@ -733,7 +733,7 @@ impl McpTool for OmniSearchHandler {
} }
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: OmniSearchTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let req: OmniSearchTool = serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let limit = req.limit.unwrap_or(5); let limit = req.limit.unwrap_or(5);
let include_body = req.include_body.unwrap_or(false); let include_body = req.include_body.unwrap_or(false);
@@ -1106,7 +1106,7 @@ impl McpTool for GetProjectHealthHandler {
} }
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: GetProjectHealthTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let req: GetProjectHealthTool = serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let active_tasks = state.project.tasks.read_with(|tasks| { let active_tasks = state.project.tasks.read_with(|tasks| {
tasks tasks
.iter() .iter()
@@ -1157,7 +1157,7 @@ impl McpTool for ManageCheckpointHandler {
} }
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: ManageCheckpointTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let req: ManageCheckpointTool = serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
match req { match req {
ManageCheckpointTool::Create { name_or_id, description, namespace } => { ManageCheckpointTool::Create { name_or_id, description, namespace } => {
let name = name_or_id.ok_or_else(|| crate::error::AppError::Internal("name_or_id is required".to_string()))?; let name = name_or_id.ok_or_else(|| crate::error::AppError::Internal("name_or_id is required".to_string()))?;
@@ -1297,7 +1297,7 @@ impl McpTool for QueryLineageHandler {
} }
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: QueryLineageTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let req: QueryLineageTool = serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let q = req.query.to_lowercase(); let q = req.query.to_lowercase();
let mut timeline = Vec::new(); let mut timeline = Vec::new();
@@ -1400,7 +1400,7 @@ impl McpTool for GetNextActionableTasksHandler {
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: GetNextActionableTasksTool = let req: GetNextActionableTasksTool =
serde_json::from_value(args).map_err(|e| e.to_string())?; serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let limit = req.limit.unwrap_or(5); let limit = req.limit.unwrap_or(5);
let tasks = state.project.tasks.read_with(|t| t.clone()); let tasks = state.project.tasks.read_with(|t| t.clone());
@@ -1459,7 +1459,7 @@ impl McpTool for HypothesesHandler {
} }
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: HypothesesTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let req: HypothesesTool = serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
match req { match req {
HypothesesTool::Log { hypothesis, task_id, status, evidence } => { HypothesesTool::Log { hypothesis, task_id, status, evidence } => {
let hyp_text = hypothesis; let hyp_text = hypothesis;
@@ -1527,7 +1527,7 @@ impl McpTool for GetPreflightContextHandler {
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: GetPreflightContextTool = let req: GetPreflightContextTool =
serde_json::from_value(args).map_err(|e| e.to_string())?; serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let tasks = state.project.tasks.read_with(|t| t.clone()); let tasks = state.project.tasks.read_with(|t| t.clone());
let tech_debts = state.code.tech_debts.read_with(|d| d.clone()); let tech_debts = state.code.tech_debts.read_with(|d| d.clone());
@@ -1603,7 +1603,7 @@ impl McpTool for AgentSignalsHandler {
} }
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: AgentSignalsTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let req: AgentSignalsTool = serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
match req { match req {
AgentSignalsTool::Broadcast { sender, signal_type, payload, ttl_seconds } => { AgentSignalsTool::Broadcast { sender, signal_type, payload, ttl_seconds } => {
let sender = sender; let sender = sender;
@@ -1705,7 +1705,7 @@ impl McpTool for AutoSessionCheckpointHandler {
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: AutoSessionCheckpointTool = let req: AutoSessionCheckpointTool =
serde_json::from_value(args).map_err(|e| e.to_string())?; serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let timestamp = std::time::SystemTime::now() let timestamp = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH) .duration_since(std::time::UNIX_EPOCH)
+4 -4
View File
@@ -23,7 +23,7 @@ impl McpTool for HandoffMemosHandler {
} }
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: HandoffMemosTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let req: HandoffMemosTool = serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
match req.action { match req.action {
HandoffMemoAction::Leave => { HandoffMemoAction::Leave => {
let content = req.content.ok_or_else(|| { let content = req.content.ok_or_else(|| {
@@ -95,7 +95,7 @@ impl McpTool for AddSessionSummaryHandler {
} }
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: AddSessionSummaryTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let req: AddSessionSummaryTool = serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
state.telemetry.session_summaries.modify(|summaries| { state.telemetry.session_summaries.modify(|summaries| {
summaries.push(crate::models::SessionSummary { summaries.push(crate::models::SessionSummary {
summary: req.summary, summary: req.summary,
@@ -143,7 +143,7 @@ impl McpTool for GenerateStandupReportHandler {
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: GenerateStandupReportTool = let req: GenerateStandupReportTool =
serde_json::from_value(args).map_err(|e| e.to_string())?; serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let cutoff = crate::handlers::utils::now_secs().saturating_sub(req.hours_lookback * 3600); let cutoff = crate::handlers::utils::now_secs().saturating_sub(req.hours_lookback * 3600);
let filtered_tasks = state.project.tasks.read_with(|items| { let filtered_tasks = state.project.tasks.read_with(|items| {
@@ -194,7 +194,7 @@ impl McpTool for PromoteToEntityHandler {
} }
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: PromoteToEntityTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let req: PromoteToEntityTool = serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let entity_name = req.entity_name.clone(); let entity_name = req.entity_name.clone();
let obs = req.content.clone(); let obs = req.content.clone();
+2 -2
View File
@@ -22,7 +22,7 @@ impl McpTool for TasksHandler {
} }
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: TasksTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let req: TasksTool = serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
match req { match req {
TasksTool::Add { title, description, parent_id, dependencies, git_branch, namespace, repo_name, priority, assigned_agent, verification_command } => { TasksTool::Add { title, description, parent_id, dependencies, git_branch, namespace, repo_name, priority, assigned_agent, verification_command } => {
let description = description.unwrap_or_default(); let description = description.unwrap_or_default();
@@ -414,7 +414,7 @@ impl McpTool for MilestonesHandler {
} }
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: MilestonesTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let req: MilestonesTool = serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
match req { match req {
MilestonesTool::Add { title, namespace, target_date, description, deliverables, task_ids, repo_name } => { MilestonesTool::Add { title, namespace, target_date, description, deliverables, task_ids, repo_name } => {
let ns = namespace.unwrap_or_else(crate::models::default_namespace); let ns = namespace.unwrap_or_else(crate::models::default_namespace);
+1 -1
View File
@@ -700,7 +700,7 @@ impl McpTool for ClipboardHandler {
} }
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: ClipboardTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let req: ClipboardTool = serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
match req.action { match req.action {
ClipboardAction::Image => { ClipboardAction::Image => {
let cached_opt = { let cached_opt = {
+5 -5
View File
@@ -22,7 +22,7 @@ impl McpTool for SnippetsHandler {
} }
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: SnippetsTool = serde_json::from_value(args).map_err(|e| e.to_string())?; let req: SnippetsTool = serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
match req.action { match req.action {
SnippetAction::Store => { SnippetAction::Store => {
let name = req.name.or(req.query).or(req.id).ok_or_else(|| { let name = req.name.or(req.query).or(req.id).ok_or_else(|| {
@@ -231,7 +231,7 @@ impl McpTool for ReadDirectoryArchitectureHandler {
async fn execute(&self, args: Value, _state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, _state: Arc<MemoryState>) -> crate::error::Result<String> {
let tool_args: ReadDirectoryArchitectureTool = let tool_args: ReadDirectoryArchitectureTool =
serde_json::from_value(args).map_err(|e| e.to_string())?; serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let dir = tool_args.directory.clone(); let dir = tool_args.directory.clone();
let result = tokio::task::spawn_blocking(move || -> crate::error::Result<String> { let result = tokio::task::spawn_blocking(move || -> crate::error::Result<String> {
@@ -301,7 +301,7 @@ impl McpTool for ReadDirectoryArchitectureHandler {
} }
summary.push_str(&format!("Architecture of {}:\n", dir)); summary.push_str(&format!("Architecture of {}:\n", dir));
visit_dirs(path, &mut summary, 0).map_err(|e| e.to_string())?; visit_dirs(path, &mut summary, 0).map_err(|e| crate::error::AppError::Internal(format!("Failed to read directory: {}", e)))?;
Ok(summary) Ok(summary)
}) })
@@ -330,7 +330,7 @@ impl McpTool for SemanticCodeSearchHandler {
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let tool_args: SemanticCodeSearchTool = let tool_args: SemanticCodeSearchTool =
serde_json::from_value(args).map_err(|e| e.to_string())?; serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let results = state let results = state
.search() .search()
@@ -388,7 +388,7 @@ impl McpTool for ManageSubagentNamespaceHandler {
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> { async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let req: ManageSubagentNamespaceTool = let req: ManageSubagentNamespaceTool =
serde_json::from_value(args).map_err(|e| e.to_string())?; serde_json::from_value(args).map_err(|e| crate::error::AppError::BadRequest(format!("Schema validation failed. Your JSON arguments do not match the expected tool schema: {}", e)))?;
let subagent_ns = format!("subagent-{}", req.subagent_id); let subagent_ns = format!("subagent-{}", req.subagent_id);
match req.action { match req.action {