Migrate KiCad MCP server to MCP 2026-07-28 - #371
Conversation
|
Status update rather than a merge verdict. Two things happened to this draft's content today:
That leaves this draft carrying two more independently valuable pieces: the IPC open-document detection and the disk-rewrite/revert refusal on the footprint path. Both are wanted as standalone PRs against current main if you have the time; they are small and would merge on their own evidence. I will leave this draft open a couple of weeks in case you want to slice those out yourself — otherwise I will extract them the same way as the correlation fix, with the same credit. |
) The Node-Python bridge was a single-slot, ID-free protocol. One 30s timeout permanently desynced it: request A times out and its handler slot is cleared, request B dispatches into the slot, A's late response arrives and resolves B's handler with A's result — silent wrong-answer cross-talk, off by one for every response after. The reporter's 'no pending request' warnings were the second-order symptom; their diagnosis of the mechanism was exactly right. Requests now carry a bridge-local requestId echoed back by Python as _requestId. Responses are consumed as newline-delimited frames; a response whose ID does not match the pending request is discarded with a log line. Timeout callbacks abandon only their own request, and the response buffer is no longer cleared on dispatch or timeout, so a partial frame from a timed-out command completes and is discarded by ID instead of corrupting the next response. The warmup path uses the same mechanism. Second finding from the same report: concurrent server processes rotating one shared log file collide on Windows (WinError 32). Logs are now per-PID with a 7-day sweep of stale files. Implementation adapted from PR mixelpixx#371 (Sergey Lukin / kerby2000), which carries this fix inside a larger MCP SDK 2.0 migration; the correlation slice stands alone and is taken here with credit, onto the current SDK1 server rather than the migrated one. Their tests are kept as written. Fixes mixelpixx#373. Co-authored-by: Sergey Lukin <lukin.s.v@gmail.com> Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Summary
2025-11-25and modern2026-07-28clients from the existing STDIO entry pointkicad-serverexecutable through the canonical migrated implementationWhy
MCP
2026-07-28removes protocol-level session state, while KiCad's Python backend still owns one active in-memory project. The migration needs an explicit application-level project identity without breaking existing clients that rely on the implicit current project.The review also found two integrity hazards around that identity: handle validation could race with a queued project switch, and a Python response arriving after a timeout could be assigned to the next request. Both are now protected end to end.
Root causes fixed
get_project_infocould not mint a recovery handle for an already-open projectCompatibility and impact
2025-11-252026-07-28and receive private cache metadataprojectHandleremains optional for legacy compatibility but is recommended for modern project-bound calls^20.19.0,^22.13.0, or>=24.0.0Validation
npm cinpm run buildnpm run lint:tsnpm run test:ts- 8 files, 82 tests passednpm run test:protocolwith the hermetic backend - both protocol eras, 221 tools, handle lifecycle, cache hintsnpm run test:protocolwith the real KiCad Python environment - both protocol eras and project-handle lifecycle passedpre-commit run --all-files --show-diff-on-failure- all hooks passednpm auditandnpm audit --omit=dev- 0 vulnerabilitiesA diagnostic full local Python run collected 1,816 tests: 1,768 passed and 35 skipped. The remaining 13 were local-environment failures (missing Java plus Windows inherited-handle/shared-log isolation); the affected tests pass in isolation where applicable, and CI provisions Java for the freerouting suites.