Files
ClaudeDo/src/ClaudeDo.Worker/External/ListMcpTools.cs
T
mika kuns c871f35513 chore(worker): external MCP tools return explicit results instead of empty responses
set_task_config/set_list_config now echo which fields were set vs cleared, get_list_config/get_task_config return an explicit found=false instead of null, and delete_list/run_task_now/reset_failed_task/remove_task_attachment return a confirmation record — matching the found/ok convention already used by batch_get_tasks and get_task_log.
2026-08-05 10:58:28 +02:00

78 lines
3.2 KiB
C#

using System.ComponentModel;
using ClaudeDo.Data.Models;
using ClaudeDo.Data.Repositories;
using ClaudeDo.Worker.Hub;
using ModelContextProtocol.Server;
namespace ClaudeDo.Worker.External;
public sealed record ListSummaryDto(string Id, string Name, string? WorkingDir, string DefaultCommitType);
public sealed record DeleteListResult(bool Deleted, string Id);
[McpServerToolType]
public sealed class ListMcpTools
{
private readonly ListRepository _lists;
private readonly HubBroadcaster _broadcaster;
public ListMcpTools(ListRepository lists, HubBroadcaster broadcaster)
{
_lists = lists;
_broadcaster = broadcaster;
}
[McpServerTool, Description("Create a new task list. workingDir sets the git repo tasks run against; commitType defaults to 'chore'.")]
public async Task<ListSummaryDto> CreateList(
string name, string? workingDir = null, string? commitType = null, CancellationToken cancellationToken = default)
{
if (string.IsNullOrWhiteSpace(name))
throw new InvalidOperationException("name is required.");
var entity = new ListEntity
{
Id = Guid.NewGuid().ToString(),
Name = name,
WorkingDir = workingDir.NullIfBlank(),
DefaultCommitType = commitType.NullIfBlank() ?? CommitTypeRegistry.DefaultType,
CreatedAt = DateTime.UtcNow,
};
await _lists.AddAsync(entity, cancellationToken);
await _broadcaster.ListUpdated(entity.Id);
return ToDto(entity);
}
[McpServerTool, Description("Rename a list and/or change its working dir and default commit type. Pass null to leave a field unchanged.")]
public async Task<ListSummaryDto> UpdateList(
string listId, string? name = null, string? workingDir = null, string? commitType = null,
CancellationToken cancellationToken = default)
{
var entity = await _lists.GetByIdAsync(listId, cancellationToken)
?? throw new InvalidOperationException($"List {listId} not found.");
if (name is not null && string.IsNullOrWhiteSpace(name))
throw new InvalidOperationException("name cannot be blank.");
if (name is not null) entity.Name = name;
if (workingDir is not null)
entity.WorkingDir = workingDir.NullIfBlank();
if (commitType is not null)
entity.DefaultCommitType = commitType.NullIfBlank() ?? CommitTypeRegistry.DefaultType;
await _lists.UpdateAsync(entity, cancellationToken);
await _broadcaster.ListUpdated(listId);
return ToDto(entity);
}
[McpServerTool, Description("Delete a list and its tasks. Irreversible. Returns { deleted: true, id } on success.")]
public async Task<DeleteListResult> DeleteList(string listId, CancellationToken cancellationToken)
{
_ = await _lists.GetByIdAsync(listId, cancellationToken)
?? throw new InvalidOperationException($"List {listId} not found.");
await _lists.DeleteAsync(listId, cancellationToken);
await _broadcaster.ListUpdated(listId);
return new DeleteListResult(true, listId);
}
private static ListSummaryDto ToDto(ListEntity l) =>
new(l.Id, l.Name, l.WorkingDir, l.DefaultCommitType);
}