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 TaskConfigDto(string? Model, string? SystemPrompt, string? AgentPath); [McpServerToolType] public sealed class ConfigMcpTools { private readonly ListRepository _lists; private readonly TaskRepository _tasks; private readonly HubBroadcaster _broadcaster; public ConfigMcpTools(ListRepository lists, TaskRepository tasks, HubBroadcaster broadcaster) { _lists = lists; _tasks = tasks; _broadcaster = broadcaster; } [McpServerTool, Description("Get a list's default config (model, system prompt, agent path). Returns null if no config is set.")] public async Task GetListConfig(string listId, CancellationToken cancellationToken) { var cfg = await _lists.GetConfigAsync(listId, cancellationToken); return cfg is null ? null : new TaskConfigDto(cfg.Model, cfg.SystemPrompt, cfg.AgentPath); } [McpServerTool, Description("Set a list's default model/system prompt/agent path. Passing all three as null clears the list config.")] public async Task SetListConfig( string listId, string? model, string? systemPrompt, string? agentPath, CancellationToken cancellationToken) { _ = await _lists.GetByIdAsync(listId, cancellationToken) ?? throw new InvalidOperationException($"List {listId} not found."); var m = Nullify(model); var sp = Nullify(systemPrompt); var ap = Nullify(agentPath); if (m is null && sp is null && ap is null) await _lists.DeleteConfigAsync(listId, cancellationToken); else await _lists.SetConfigAsync(new ListConfigEntity { ListId = listId, Model = m, SystemPrompt = sp, AgentPath = ap, }, cancellationToken); await _broadcaster.ListUpdated(listId); } [McpServerTool, Description("Set per-task config overrides (model/system prompt/agent path). Pass null for any field to clear that override.")] public async Task SetTaskConfig( string taskId, string? model, string? systemPrompt, string? agentPath, CancellationToken cancellationToken) { _ = await _tasks.GetByIdAsync(taskId, cancellationToken) ?? throw new InvalidOperationException($"Task {taskId} not found."); await _tasks.UpdateAgentSettingsAsync(taskId, Nullify(model), Nullify(systemPrompt), Nullify(agentPath), cancellationToken); await _broadcaster.TaskUpdated(taskId); } private static string? Nullify(string? s) => string.IsNullOrWhiteSpace(s) ? null : s; }