feat(worker): map MCP HTTP endpoint and broadcast TaskUpdated

- Add PlanningMcpContextAccessor (Option A) to read PlanningMcpContext
  from HttpContext.Items set by PlanningTokenAuthMiddleware
- Annotate PlanningMcpService with [McpServerToolType]/[McpServerTool]
  and remove PlanningMcpContext ctx parameter from all tool methods
- Broadcast TaskUpdated(parentTaskId) via HubBroadcaster after every
  mutation in PlanningMcpService
- Refactor PlanningSessionManager to accept IDbContextFactory for
  singleton-safe use in DI; keep direct-repo ctor for tests
- Register PlanningSessionManager (singleton), IPlanningTerminalLauncher,
  PlanningMcpContextAccessor, PlanningMcpService, and MCP server in
  Program.cs; wire PlanningTokenAuthMiddleware and MapMcp("/mcp")
- Update PlanningMcpServiceTests with fake HttpContext accessor and
  no-op HubBroadcaster (avoids Moq dependency)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
mika kuns
2026-04-23 23:12:24 +02:00
parent 99c6a71e4c
commit 6cb20a9213
5 changed files with 178 additions and 36 deletions

View File

@@ -3,6 +3,7 @@ using ClaudeDo.Data.Git;
using ClaudeDo.Data.Repositories;
using ClaudeDo.Worker.Config;
using ClaudeDo.Worker.Hub;
using ClaudeDo.Worker.Planning;
using ClaudeDo.Worker.Runner;
using ClaudeDo.Worker.Services;
using Microsoft.EntityFrameworkCore;
@@ -51,6 +52,22 @@ builder.Services.AddSingleton(sp => new DefaultAgentSeeder(
builder.Services.AddSingleton<QueueService>();
builder.Services.AddHostedService(sp => sp.GetRequiredService<QueueService>());
// Planning session services.
var planningSessionsDir = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
".todo-app", "planning-sessions");
builder.Services.AddSingleton(sp =>
new PlanningSessionManager(
sp.GetRequiredService<IDbContextFactory<ClaudeDoDbContext>>(),
planningSessionsDir));
builder.Services.AddSingleton<IPlanningTerminalLauncher, WindowsTerminalPlanningLauncher>();
builder.Services.AddHttpContextAccessor();
builder.Services.AddScoped<PlanningMcpContextAccessor>();
builder.Services.AddScoped<PlanningMcpService>();
builder.Services.AddMcpServer()
.WithHttpTransport()
.WithTools<PlanningMcpService>();
// Loopback-only bind. Firewall is irrelevant for 127.0.0.1.
builder.WebHost.UseUrls($"http://127.0.0.1:{cfg.SignalRPort}");
@@ -75,7 +92,9 @@ catch (Exception ex)
app.Logger.LogWarning(ex, "Default agent seeding failed");
}
app.UseMiddleware<PlanningTokenAuthMiddleware>();
app.MapHub<WorkerHub>("/hub");
app.MapMcp("/mcp");
app.Logger.LogInformation("ClaudeDo.Worker listening on http://127.0.0.1:{Port} (db: {Db})",
cfg.SignalRPort, cfg.DbPath);