Refactor: Migrate unwrap calls to AppError in MCP handlers
This commit is contained in:
1 parent
4e1a633dbd
commit
0e866f2465
12 files changed
+276
-326
No files matched your search
@@ -18,7 +18,7 @@ impl McpTool for AddTaskHandler {
|
||||
crate::mcp::tool_def::<AddTaskTool>("add_task", "Execute add_task")
|
||||
}
|
||||
|
||||
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> Result<String, String> {
|
||||
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
|
||||
let req: AddTaskTool = serde_json::from_value(args).map_err(|e| e.to_string())?;
|
||||
let now = crate::handlers::utils::now_secs();
|
||||
let task_id = uuid::Uuid::new_v4().to_string();
|
||||
@@ -59,7 +59,7 @@ impl McpTool for DeleteTaskHandler {
|
||||
crate::mcp::tool_def::<DeleteTaskTool>("delete_task", "Execute delete_task")
|
||||
}
|
||||
|
||||
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> Result<String, String> {
|
||||
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
|
||||
let req: DeleteTaskTool = serde_json::from_value(args).map_err(|e| e.to_string())?;
|
||||
let mut deleted_count = 0;
|
||||
let mut actually_deleted = Vec::new();
|
||||
@@ -114,7 +114,7 @@ impl McpTool for DeleteTaskHandler {
|
||||
][0]
|
||||
.clone())
|
||||
} else {
|
||||
Err("Task not found. Please use the list_active_tasks tool to verify the correct task ID.".to_string())
|
||||
Err(crate::error::AppError::Internal("Task not found. Please use the list_active_tasks tool to verify the correct task ID.".to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -134,7 +134,7 @@ impl McpTool for UpdateTaskStatusHandler {
|
||||
)
|
||||
}
|
||||
|
||||
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> Result<String, String> {
|
||||
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
|
||||
let req: UpdateTaskStatusTool = serde_json::from_value(args).map_err(|e| e.to_string())?;
|
||||
let mut found = false;
|
||||
let mut blocked = false;
|
||||
@@ -250,14 +250,14 @@ impl McpTool for UpdateTaskStatusHandler {
|
||||
});
|
||||
|
||||
if blocked {
|
||||
Err(format!(
|
||||
Err(crate::error::AppError::Internal(format!(
|
||||
"Error: Cannot transition task. {}",
|
||||
blocker_details
|
||||
))
|
||||
)))
|
||||
} else if found {
|
||||
Ok("Task status updated.".to_string())
|
||||
} else {
|
||||
Err("Task not found. Please use the list_active_tasks tool to verify the correct task ID.".to_string())
|
||||
Err(crate::error::AppError::Internal("Task not found. Please use the list_active_tasks tool to verify the correct task ID.".to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -277,7 +277,7 @@ impl McpTool for ListActiveTasksHandler {
|
||||
)
|
||||
}
|
||||
|
||||
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> Result<String, String> {
|
||||
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
|
||||
let req: ListActiveTasksTool = serde_json::from_value(args).map_err(|e| e.to_string())?;
|
||||
let data = state.tasks.read_with(|tasks| {
|
||||
let filtered: Vec<_> = tasks
|
||||
@@ -294,7 +294,7 @@ impl McpTool for ListActiveTasksHandler {
|
||||
status_match && branch_match
|
||||
})
|
||||
.collect();
|
||||
serde_json::to_string(&filtered).map_err(|e| e.to_string())
|
||||
Ok::<String, crate::error::AppError>(serde_json::to_string(&filtered)?)
|
||||
})?;
|
||||
Ok(data)
|
||||
}
|
||||
@@ -315,7 +315,7 @@ impl McpTool for SetAcceptanceCriteriaHandler {
|
||||
)
|
||||
}
|
||||
|
||||
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> Result<String, String> {
|
||||
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
|
||||
let req: SetAcceptanceCriteriaTool =
|
||||
serde_json::from_value(args).map_err(|e| e.to_string())?;
|
||||
let mut success = false;
|
||||
@@ -337,7 +337,7 @@ impl McpTool for SetAcceptanceCriteriaHandler {
|
||||
if success {
|
||||
Ok("Acceptance criteria set successfully.".to_string())
|
||||
} else {
|
||||
Err("Task not found. Please use the list_active_tasks tool to verify the correct task ID.".to_string())
|
||||
Err(crate::error::AppError::Internal("Task not found. Please use the list_active_tasks tool to verify the correct task ID.".to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -357,7 +357,7 @@ impl McpTool for VerifyAcceptanceCriteriaHandler {
|
||||
)
|
||||
}
|
||||
|
||||
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> Result<String, String> {
|
||||
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
|
||||
let req: VerifyAcceptanceCriteriaTool =
|
||||
serde_json::from_value(args).map_err(|e| e.to_string())?;
|
||||
let mut success = false;
|
||||
@@ -386,7 +386,7 @@ impl McpTool for VerifyAcceptanceCriteriaHandler {
|
||||
} else if already_met {
|
||||
Ok("Acceptance criteria was already met.".to_string())
|
||||
} else {
|
||||
Err("Acceptance criteria or task not found.".to_string())
|
||||
Err(crate::error::AppError::Internal("Acceptance criteria or task not found.".to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -403,7 +403,7 @@ impl McpTool for AddMilestoneHandler {
|
||||
crate::mcp::tool_def::<AddMilestoneTool>("add_milestone", "Execute add_milestone")
|
||||
}
|
||||
|
||||
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> Result<String, String> {
|
||||
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
|
||||
let req: AddMilestoneTool = serde_json::from_value(args).map_err(|e| e.to_string())?;
|
||||
state.milestones.modify(|ms| {
|
||||
ms.push(crate::models::Milestone {
|
||||
@@ -430,7 +430,7 @@ impl McpTool for UpdateMilestoneHandler {
|
||||
crate::mcp::tool_def::<UpdateMilestoneTool>("update_milestone", "Execute update_milestone")
|
||||
}
|
||||
|
||||
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> Result<String, String> {
|
||||
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
|
||||
let req: UpdateMilestoneTool = serde_json::from_value(args).map_err(|e| e.to_string())?;
|
||||
let mut found = false;
|
||||
state.milestones.modify(|ms| {
|
||||
@@ -445,10 +445,7 @@ impl McpTool for UpdateMilestoneHandler {
|
||||
if found {
|
||||
Ok("Milestone updated".to_string())
|
||||
} else {
|
||||
Err(
|
||||
"Milestone not found. Please verify the milestone ID using list_milestones."
|
||||
.to_string(),
|
||||
)
|
||||
Err(crate::error::AppError::Internal("Milestone not found. Please verify the milestone ID using list_milestones.".to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -465,7 +462,7 @@ impl McpTool for ListMilestonesHandler {
|
||||
crate::mcp::tool_def::<ListMilestonesTool>("list_milestones", "Execute list_milestones")
|
||||
}
|
||||
|
||||
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> Result<String, String> {
|
||||
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
|
||||
let req: ListMilestonesTool = serde_json::from_value(args).map_err(|e| e.to_string())?;
|
||||
let data = state.milestones.read_with(|items| {
|
||||
let filtered: Vec<_> = items
|
||||
@@ -478,7 +475,7 @@ impl McpTool for ListMilestonesHandler {
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
serde_json::to_string(&filtered).map_err(|e| e.to_string())
|
||||
Ok::<String, crate::error::AppError>(serde_json::to_string(&filtered)?)
|
||||
})?;
|
||||
Ok(data)
|
||||
}
|
||||
@@ -502,14 +499,13 @@ mod tests {
|
||||
"acceptance_criteria": ["Stop the noise", "Reach lightspeed"],
|
||||
});
|
||||
|
||||
let res = add_handler.execute(args, state.clone()).await.unwrap();
|
||||
let res = add_handler.execute(args, state.clone()).await.map_err(|e| crate::error::AppError::Internal(e.to_string()))?;
|
||||
assert!(res.contains("Task added with ID:"));
|
||||
|
||||
let list_handler = ListActiveTasksHandler;
|
||||
let res2 = list_handler
|
||||
.execute(json!({}), state.clone())
|
||||
.await
|
||||
.unwrap();
|
||||
.await.map_err(|e| crate::error::AppError::Internal(e.to_string()))?;
|
||||
assert!(res2.contains("Fix the hyperdrive"));
|
||||
}
|
||||
|
||||
@@ -524,8 +520,7 @@ mod tests {
|
||||
json!({"title": "Test", "description": "test"}),
|
||||
state.clone(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
.await.map_err(|e| crate::error::AppError::Internal(e.to_string()))?;
|
||||
|
||||
let id_start = res.find("ID: ").unwrap() + 4;
|
||||
let task_id = res[id_start..].trim();
|
||||
@@ -535,14 +530,13 @@ mod tests {
|
||||
"id": task_id,
|
||||
"status": "done"
|
||||
});
|
||||
let res3 = update_handler.execute(args, state.clone()).await.unwrap();
|
||||
let res3 = update_handler.execute(args, state.clone()).await.map_err(|e| crate::error::AppError::Internal(e.to_string()))?;
|
||||
assert_eq!(res3, "Task status updated.");
|
||||
|
||||
let list_handler = ListActiveTasksHandler;
|
||||
let res4 = list_handler
|
||||
.execute(json!({}), state.clone())
|
||||
.await
|
||||
.unwrap();
|
||||
.await.map_err(|e| crate::error::AppError::Internal(e.to_string()))?;
|
||||
assert!(!res4.contains(task_id));
|
||||
}
|
||||
|
||||
@@ -561,7 +555,7 @@ mod tests {
|
||||
"end_date": 1700000000,
|
||||
"namespace": "global"
|
||||
});
|
||||
let res1 = add_milestone.execute(args_ms, state.clone()).await.unwrap();
|
||||
let res1 = add_milestone.execute(args_ms, state.clone()).await.map_err(|e| crate::error::AppError::Internal(e.to_string()))?;
|
||||
assert!(res1.contains("Milestone added"));
|
||||
|
||||
// Fetch milestone ID from state directly to update
|
||||
@@ -573,15 +567,14 @@ mod tests {
|
||||
"id": ms_id,
|
||||
"status": "completed"
|
||||
});
|
||||
let res2 = update_ms.execute(args_ums, state.clone()).await.unwrap();
|
||||
let res2 = update_ms.execute(args_ums, state.clone()).await.map_err(|e| crate::error::AppError::Internal(e.to_string()))?;
|
||||
assert_eq!(res2, "Milestone updated");
|
||||
|
||||
// List Milestones
|
||||
let list_ms = ListMilestonesHandler;
|
||||
let res3 = list_ms
|
||||
.execute(json!({"namespace": "global"}), state.clone())
|
||||
.await
|
||||
.unwrap();
|
||||
.await.map_err(|e| crate::error::AppError::Internal(e.to_string()))?;
|
||||
assert!(res3.contains("completed"));
|
||||
assert!(res3.contains("Release 1.0"));
|
||||
|
||||
@@ -592,8 +585,7 @@ mod tests {
|
||||
json!({"title": "Test", "description": "desc"}),
|
||||
state.clone(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
.await.map_err(|e| crate::error::AppError::Internal(e.to_string()))?;
|
||||
let task_id = res_task[res_task.find("ID: ").unwrap() + 4..].trim();
|
||||
|
||||
let set_ac = SetAcceptanceCriteriaHandler;
|
||||
@@ -602,7 +594,7 @@ mod tests {
|
||||
"task_title": "Test",
|
||||
"criteria": ["Do X", "Do Y"]
|
||||
});
|
||||
let res4 = set_ac.execute(args_ac, state.clone()).await.unwrap();
|
||||
let res4 = set_ac.execute(args_ac, state.clone()).await.map_err(|e| crate::error::AppError::Internal(e.to_string()))?;
|
||||
assert_eq!(res4, "Acceptance criteria set successfully.");
|
||||
|
||||
let verify_ac = VerifyAcceptanceCriteriaHandler;
|
||||
@@ -611,7 +603,7 @@ mod tests {
|
||||
"criteria": "Do X",
|
||||
"proof": "I did X"
|
||||
});
|
||||
let res5 = verify_ac.execute(args_vac, state.clone()).await.unwrap();
|
||||
let res5 = verify_ac.execute(args_vac, state.clone()).await.map_err(|e| crate::error::AppError::Internal(e.to_string()))?;
|
||||
assert!(res5.contains("Acceptance criteria verified"));
|
||||
}
|
||||
|
||||
@@ -626,8 +618,7 @@ mod tests {
|
||||
json!({"title": "Parent", "description": "p"}),
|
||||
state.clone(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
.await.map_err(|e| crate::error::AppError::Internal(e.to_string()))?;
|
||||
let parent_id = parent[parent.find("ID: ").unwrap() + 4..]
|
||||
.trim()
|
||||
.to_string();
|
||||
@@ -637,15 +628,13 @@ mod tests {
|
||||
json!({"title": "Child", "description": "c", "parent_id": parent_id}),
|
||||
state.clone(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
.await.map_err(|e| crate::error::AppError::Internal(e.to_string()))?;
|
||||
let _child_id = child[child.find("ID: ").unwrap() + 4..].trim().to_string();
|
||||
|
||||
let del_task = DeleteTaskHandler;
|
||||
let res_del = del_task
|
||||
.execute(json!({"id": parent_id}), state.clone())
|
||||
.await
|
||||
.unwrap();
|
||||
.await.map_err(|e| crate::error::AppError::Internal(e.to_string()))?;
|
||||
assert!(res_del.contains("Deleted task and its children (2 total)."));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user