The MCP server wedged the IDE on a list — head-of-line blocking, and why killing the process was the only release (RFC O/P/R) A head-of-line blocking bug in Loomcycle's MCP server caused an IDE to hang indefinitely when a slow tool call blocked all subsequent frames on a single goroutine. The issue was amplified by cross-runtime interruption wake delays and provider outages, requiring a process kill to recover. Three coordinated fixes in v0.23.0—concurrent dispatch, per-call timeouts, and a thin-client topology—eliminate the failure class at multiple levels. Day two of the operator-via-MCP series. Mid-experiment, the operator's IDE a fresh Claude Code session driving loomcycle through the plugin's stdio MCP server hung on a list runs tool confirmation. The user approved the call. Nothing happened. The only way out was to kill the loomcycle mcp process from another terminal. Source-reading v0.22.0's internal/api/mcp/server.go found a single load-bearing footnote lines 102-115 : "Frames are dispatched SEQUENTIALLY on a single goroutine. Concurrent tools/call is a v0.9.x optimisation — not implemented." The comment was honest; it was also wrong about the priority. Combined with an unbounded spawn run handler no per-call timeout , one slow run blocked every subsequent frame in the OS pipe behind it — even a cheap list runs, even a cancel run. Classic head-of-line blocking on a single-consumer stream. The list was the victim, not the cause. Three amplifiers turned "slow" into "wedged for an hour": F15 cross-runtime interruption wake made an interruption-held run block to the 1-hour interruption.default timeout ms; provider outages the day this happened coincided with an Opus 4.7/4.8 incident on Anthropic's side stalled spawn run on retries; F16 accumulated SSE clients + heartbeating runs added resource pressure on top. Why killing the process was the only release: ctx cancellation is polled only between frames, so cancelling the parent context doesn't preempt an in-flight handler. A cancel run frame would itself be HOL-blocked behind the occupier. SIGTERM on the loomcycle mcp PID ends the process; stdin closes; the wedged call dies with it; the IDE sees the MCP transport drop and reconnects. Three coordinated PRs in v0.23.0 close the failure class at three levels: RFC O 377 makes stdio dispatch concurrent on bounded goroutines the writeMu for stdout framing already existed, only used by the notification path; now it serializes every response . Independent tool calls run concurrently; initialize/initialized stay sequential. The HOL class is gone. RFC P 380 wraps spawn run in a transport-level context.WithTimeout, configurable per operator. A provider stall or unkillable run no longer keeps the handler alive forever. Composed with RFC O, the bound is hard. RFC R 381 ships the thin-client topology: loomcycle mcp --upstream launches a stdio MCP server that proxies to a single full runtime over HTTP/gRPC. Every tool call lands on the one runtime that owns the in-process bus; the cross-process bus-Notify problem dissolves interruption resolve from a thin client hits the same in-process bus the blocking ask waits on . F15 stops being reachable in normal use. Breaking change in the same release 383 : loomcycle mcp --no-http is removed — the pattern that needed it two full runtimes side-by-side with HTTP suppressed on one is the pattern that caused F15. A real fix for the original code path — durable cross-runtime wake via the system/interrupts/resolved channel — shipped two days later 400 for multi-host HA topologies that genuinely need multiple full runtimes. The thin-client pattern stays the recommended default. None of the three PRs would have been sufficient alone: concurrent dispatch without timeout still allows a goroutine slot to be tied up indefinitely; timeout without concurrent dispatch still produces "list hung for 5 minutes" before the timeout fires; thin-client without the other two still HOL-blocks a single transport on a single runtime. The three together remove the failure class at three different levels. The engineering lesson: a "we'll fix it later" comment on a load-bearing concurrency property is a P1 bug, not a roadmap item. The runtime documentation said the limit; the operators' code didn't read the documentation. The first real workload to touch the limit looked like complete system failure.