feat(worker): run both MCP servers stateless
Set Stateless = true on the internal (/mcp on the SignalR port) and external MCP HTTP transports. Two effects: - No Mcp-Session-Id, so a worker restart can no longer 404 a session that outlives it -- ConPTY tiles in the UI process and externally registered claude sessions keep working across a restart. - A 2026-07-28 client is no longer refused back to the initialize handshake. A stateful server rejects that revision on purpose (see the SDK's StreamableHttpHandler.s_sessionSupportingProtocolVersions), so the new per-request protocol path was unreachable regardless of SDK version. Nothing here used the stateful-only features (sampling, elicitation, resource subscriptions, unsolicited notifications). In-tool progress notifications ride the POST's own response stream and are unaffected -- which matters, since ~20 tools use them to hold off the client's 300s idle abort. All three consumers (TaskRunner, PlanningSessionManager, the installer's RegisterMcpStep) already register type: "http", so dropping the legacy SSE endpoint breaks nothing. Verified against the running worker across two restarts: tools/list returns 57 tools over a bare POST with no initialize and no session id, and a full 2026-07-28 tools/call round-trip returns real data.
This commit is contained in:
@@ -256,4 +256,5 @@ list-only — there is no task-level override — and is written via `set_list_c
|
||||
- The worker runs standalone — start it separately from the UI. Loopback only (127.0.0.1).
|
||||
- `--permission-mode auto` by default; legacy `bypassPermissions` settings map to `auto` at dispatch time. `acceptEdits`, `plan`, `default` pass through unchanged.
|
||||
- Worktree branches follow `claudedo/{id}`.
|
||||
- **Both MCP servers run `Stateless = true`** (`Program.cs`). No `Mcp-Session-Id`, so a worker restart can't 404 a session that outlives it, and a 2026-07-28 client isn't refused back to the initialize handshake. The trade: **no** sampling, elicitation, resource subscriptions, unsolicited notifications, or legacy SSE endpoint — don't reach for those. In-tool progress notifications ride the POST's own response stream and work in both modes. All three consumers (`TaskRunner`, `PlanningSessionManager`, the installer's `RegisterMcpStep`) already use `type: "http"`.
|
||||
- **An MCP tool that can run longer than ~5s reports progress.** Staying silent lets the MCP client abort after 300s idle while the worker keeps working — the caller sees an abort even though the operation is still running. `Lifecycle/ProgressReporter` is the one implementation (elapsed-time reporting via `RunAsync`, per-item `i/n` via `ReportItem`) — thread an `IProgress<ProgressNotificationValue>? progress = null` parameter through instead of writing another polling loop.
|
||||
|
||||
Reference in New Issue
Block a user