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, int? MaxTurns); [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, cfg.MaxTurns); } [McpServerTool, Description("Set a list's default model/system prompt/agent path/max turns. Passing all four as null clears the list config.")] public async Task SetListConfig( string listId, string? model = null, string? systemPrompt = null, string? agentPath = null, int? maxTurns = null, CancellationToken cancellationToken = default) { _ = await _lists.GetByIdAsync(listId, cancellationToken) ?? throw new InvalidOperationException($"List {listId} not found."); var m = model.NullIfBlank(); var sp = systemPrompt.NullIfBlank(); var ap = agentPath.NullIfBlank(); if (m is null && sp is null && ap is null && maxTurns is null) await _lists.DeleteConfigAsync(listId, cancellationToken); else await _lists.SetConfigAsync(new ListConfigEntity { ListId = listId, Model = m, SystemPrompt = sp, AgentPath = ap, MaxTurns = maxTurns, }, cancellationToken); await _broadcaster.ListUpdated(listId); } [McpServerTool, Description("Set per-task config overrides (model/system prompt/agent path/max turns). Pass null for any field to clear that override.")] public async Task SetTaskConfig( string taskId, string? model = null, string? systemPrompt = null, string? agentPath = null, int? maxTurns = null, CancellationToken cancellationToken = default) { _ = await _tasks.GetByIdAsync(taskId, cancellationToken) ?? throw new InvalidOperationException($"Task {taskId} not found."); await _tasks.UpdateAgentSettingsAsync(taskId, model.NullIfBlank(), systemPrompt.NullIfBlank(), agentPath.NullIfBlank(), maxTurns, ct: cancellationToken); await _broadcaster.TaskUpdated(taskId); } [McpServerTool, Description("Get per-task config overrides (model/system prompt/agent path/max turns). Returns null if no override is set on this task.")] public async Task GetTaskConfig(string taskId, CancellationToken cancellationToken) { var task = await _tasks.GetByIdAsync(taskId, cancellationToken) ?? throw new InvalidOperationException($"Task {taskId} not found."); if (task.Model is null && task.SystemPrompt is null && task.AgentPath is null && task.MaxTurns is null) return null; return new TaskConfigDto(task.Model, task.SystemPrompt, task.AgentPath, task.MaxTurns); } }