using System.ComponentModel; using ClaudeDo.Data.Models; using ClaudeDo.Data.Repositories; using ClaudeDo.Worker.Agents; using ClaudeDo.Worker.Lifecycle; using ModelContextProtocol.Server; using TaskStatus = ClaudeDo.Data.Models.TaskStatus; namespace ClaudeDo.Worker.External; [McpServerToolType] public sealed class AgentMcpTools { private readonly AgentFileService _agents; public AgentMcpTools(AgentFileService agents) => _agents = agents; [McpServerTool, Description("List available agent definition files (name, description, path) for use as a task's agent path.")] public async Task> ListAgents(CancellationToken cancellationToken) => await _agents.ScanAsync(cancellationToken); } [McpServerToolType] public sealed class LifecycleMcpTools { private readonly TaskRepository _tasks; private readonly TaskResetService _reset; public LifecycleMcpTools(TaskRepository tasks, TaskResetService reset) { _tasks = tasks; _reset = reset; } [McpServerTool, Description("Reset a failed task: discards its worktree and returns it to Idle so it can be run again. Only Failed tasks are accepted.")] public async Task ResetFailedTask(string taskId, CancellationToken cancellationToken) { var task = await _tasks.GetByIdAsync(taskId, cancellationToken) ?? throw new InvalidOperationException($"Task {taskId} not found."); if (task.Status != TaskStatus.Failed) throw new InvalidOperationException($"Task {taskId} is {task.Status}, not Failed. Only failed tasks can be reset via this tool."); await _reset.ResetAsync(taskId, cancellationToken); } }