The MCP server's reader queues at most 64 lines for the engine and
stops reading past that until the engine catches up. The reply to a
line that is not JSON, or that is longer than the line limit, skipped
that check: while a call had run for less than the busy limit (two
seconds by default), or while the engine was behind, every such line
added a reply to the queue. In the new test, 192 lines that are not
JSON leave 192 replies queued on main.
These replies now wait for room as requests do, and still go out at
once when the running call has passed the busy limit.
The MCP server read one line, ran it and answered it before reading the next,
so notifications/cancelled was never seen during a call and every request
(even ping) waited behind a running export.
- vectorcraft_doc::cancel: a thread-local cancel token and progress sink that
long work polls. Checkpoints: PDF pages, PDF flattening, geometry bake,
raster-effect flattening, drawing objects, raster artboards, and before any
file is written. A cancelled command returns EngineError::Cancelled and
changes nothing.
- Server::serve reads on its own thread: notifications/cancelled drops a
queued request or stops the running one (no reply, as the MCP spec says),
engine-free requests (ping, the list methods, prompts/get) are answered at
once, a request that would wait behind a call running for 2 s is refused
with -32003 naming that call, and _meta.progressToken gets
notifications/progress (page n of m). Queue and output are bounded.
- The remote backend stops waiting for the app when the call is cancelled.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>