@@ -165,25 +165,19 @@ func (s *Server) registerTools(mcpServer *server.MCPServer) {
func (s *Server) handleSetGoal(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
s.logger.Info("Received project_management__set_goal tool call")
- // Extract parameters
- arguments := request.GetArguments()
- title, ok := arguments["title"].(string)
- if !ok || title == "" {
- return createErrorResult("Error: title parameter is required and must be a string"), nil
- }
-
- description, ok := arguments["description"].(string)
- if !ok {
- return createErrorResult("Error: description parameter is required and must be a string"), nil
+ // Parse and validate request
+ var req SetGoalRequest
+ if err := parseAndValidate(request.GetArguments(), &req); err != nil {
+ return createErrorResult(fmt.Sprintf("Invalid request: %v", err)), nil
}
// Set goal
- if err := s.planner.SetGoal(title, description); err != nil {
+ if err := s.planner.SetGoal(req.Title, req.Description); err != nil {
s.logger.Error("Failed to set goal", "error", err)
return createErrorResult(fmt.Sprintf("Error setting goal: %v", err)), nil
}
- goalText := formatGoalText(title, description)
+ goalText := formatGoalText(req.Title, req.Description)
response := fmt.Sprintf("Goal \"%s\" saved! You probably want to add one or more tasks now.", goalText)
return createSuccessResult(response), nil
}
@@ -192,31 +186,20 @@ func (s *Server) handleSetGoal(ctx context.Context, request mcp.CallToolRequest)
func (s *Server) handleChangeGoal(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
s.logger.Info("Received project_management__change_goal tool call")
- // Extract parameters
- arguments := request.GetArguments()
- title, ok := arguments["title"].(string)
- if !ok || title == "" {
- return createErrorResult("Error: title parameter is required and must be a string"), nil
- }
-
- description, ok := arguments["description"].(string)
- if !ok {
- return createErrorResult("Error: description parameter is required and must be a string"), nil
- }
-
- reason, ok := arguments["reason"].(string)
- if !ok || reason == "" {
- return createErrorResult("Error: reason parameter is required and must be a string"), nil
+ // Parse and validate request
+ var req ChangeGoalRequest
+ if err := parseAndValidate(request.GetArguments(), &req); err != nil {
+ return createErrorResult(fmt.Sprintf("Invalid request: %v", err)), nil
}
// Change goal
- if err := s.planner.ChangeGoal(title, description, reason); err != nil {
+ if err := s.planner.ChangeGoal(req.Title, req.Description, req.Reason); err != nil {
s.logger.Error("Failed to change goal", "error", err)
return createErrorResult(fmt.Sprintf("Error changing goal: %v", err)), nil
}
- goalText := formatGoalText(title, description)
- response := fmt.Sprintf("Goal changed to \"%s\" (reason: %s). You probably want to add one or more tasks now.", goalText, reason)
+ goalText := formatGoalText(req.Title, req.Description)
+ response := fmt.Sprintf("Goal changed to \"%s\" (reason: %s). You probably want to add one or more tasks now.", goalText, req.Reason)
return createSuccessResult(response), nil
}
@@ -224,37 +207,18 @@ func (s *Server) handleChangeGoal(ctx context.Context, request mcp.CallToolReque
func (s *Server) handleAddTasks(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
s.logger.Info("Received project_management__add_tasks tool call")
- // Extract parameters
- arguments := request.GetArguments()
- tasksRaw, ok := arguments["tasks"]
- if !ok {
- return createErrorResult("Error: tasks parameter is required"), nil
- }
-
- // Convert to slice of interfaces
- tasksSlice, ok := tasksRaw.([]any)
- if !ok {
- return createErrorResult("Error: tasks parameter must be an array"), nil
+ // Parse and validate request
+ var req AddTasksRequest
+ if err := parseAndValidate(request.GetArguments(), &req); err != nil {
+ return createErrorResult(fmt.Sprintf("Invalid request: %v", err)), nil
}
- // Parse tasks
- tasks := make([]planning.TaskInput, 0, len(tasksSlice))
- for _, taskRaw := range tasksSlice {
- taskMap, ok := taskRaw.(map[string]any)
- if !ok {
- return createErrorResult("Error: each task must be an object"), nil
- }
-
- title, ok := taskMap["title"].(string)
- if !ok || title == "" {
- return createErrorResult("Error: each task must have a non-empty title"), nil
- }
-
- description, _ := taskMap["description"].(string)
-
+ // Convert MCP task inputs to planning task inputs
+ tasks := make([]planning.TaskInput, 0, len(req.Tasks))
+ for _, mcpTask := range req.Tasks {
tasks = append(tasks, planning.TaskInput{
- Title: title,
- Description: description,
+ Title: mcpTask.Title,
+ Description: mcpTask.Description,
})
}
@@ -288,9 +252,14 @@ func (s *Server) handleAddTasks(ctx context.Context, request mcp.CallToolRequest
func (s *Server) handleGetTasks(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
s.logger.Info("Received project_management__get_tasks tool call")
- // Extract parameters
- arguments := request.GetArguments()
- statusFilter, _ := arguments["status"].(string)
+ // Parse and validate request
+ var req GetTasksRequest
+ if err := parseAndValidate(request.GetArguments(), &req); err != nil {
+ return createErrorResult(fmt.Sprintf("Invalid request: %v", err)), nil
+ }
+
+ // Default status to "all" if empty
+ statusFilter := req.Status
if statusFilter == "" {
statusFilter = "all"
}
@@ -309,47 +278,18 @@ func (s *Server) handleGetTasks(ctx context.Context, request mcp.CallToolRequest
func (s *Server) handleUpdateTaskStatuses(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
s.logger.Info("Received project_management__update_task_statuses tool call")
- // Extract parameters
- arguments := request.GetArguments()
- tasksRaw, ok := arguments["tasks"]
- if !ok {
- return createErrorResult("Error: tasks parameter is required"), nil
- }
-
- // Convert to slice of interfaces
- tasksSlice, ok := tasksRaw.([]any)
- if !ok {
- return createErrorResult("Error: tasks parameter must be an array"), nil
+ // Parse and validate request
+ var req UpdateTaskStatusesRequest
+ if err := parseAndValidate(request.GetArguments(), &req); err != nil {
+ return createErrorResult(fmt.Sprintf("Invalid request: %v", err)), nil
}
- if len(tasksSlice) == 0 {
- return createErrorResult("Error: at least one task update is required"), nil
- }
-
- // Parse task updates
- updates := make([]planning.TaskUpdate, 0, len(tasksSlice))
- for _, taskRaw := range tasksSlice {
- taskMap, ok := taskRaw.(map[string]any)
- if !ok {
- return createErrorResult("Error: each task update must be an object"), nil
- }
-
- taskID, ok := taskMap["task_id"].(string)
- if !ok || taskID == "" {
- return createErrorResult("Error: each task update must have a non-empty task_id"), nil
- }
-
- statusStr, ok := taskMap["status"].(string)
- if !ok || statusStr == "" {
- return createErrorResult("Error: each task update must have a non-empty status"), nil
- }
-
- // Parse status
- status := planning.ParseStatus(statusStr)
-
+ // Convert MCP task update inputs to planning task updates
+ updates := make([]planning.TaskUpdate, 0, len(req.Tasks))
+ for _, mcpUpdate := range req.Tasks {
updates = append(updates, planning.TaskUpdate{
- TaskID: taskID,
- Status: status,
+ TaskID: mcpUpdate.TaskID,
+ Status: planning.ParseStatus(mcpUpdate.Status),
})
}
@@ -368,35 +308,14 @@ func (s *Server) handleUpdateTaskStatuses(ctx context.Context, request mcp.CallT
func (s *Server) handleDeleteTasks(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
s.logger.Info("Received project_management__delete_tasks tool call")
- // Extract parameters
- arguments := request.GetArguments()
- taskIDsRaw, ok := arguments["task_ids"]
- if !ok {
- return createErrorResult("Error: task_ids parameter is required"), nil
- }
-
- // Convert to slice of interfaces
- taskIDsSlice, ok := taskIDsRaw.([]any)
- if !ok {
- return createErrorResult("Error: task_ids parameter must be an array"), nil
- }
-
- if len(taskIDsSlice) == 0 {
- return createErrorResult("Error: at least one task ID is required"), nil
- }
-
- // Parse task IDs
- taskIDs := make([]string, 0, len(taskIDsSlice))
- for _, taskIDRaw := range taskIDsSlice {
- taskID, ok := taskIDRaw.(string)
- if !ok || taskID == "" {
- return createErrorResult("Error: each task ID must be a non-empty string"), nil
- }
- taskIDs = append(taskIDs, taskID)
+ // Parse and validate request
+ var req DeleteTasksRequest
+ if err := parseAndValidate(request.GetArguments(), &req); err != nil {
+ return createErrorResult(fmt.Sprintf("Invalid request: %v", err)), nil
}
// Delete tasks
- if err := s.planner.DeleteTasks(taskIDs); err != nil {
+ if err := s.planner.DeleteTasks(req.TaskIDs); err != nil {
s.logger.Error("Failed to delete tasks", "error", err)
return createErrorResult(fmt.Sprintf("Error deleting tasks: %v", err)), nil
}