Commit Graph

207 Commits

Author SHA1 Message Date
Eugene Mikhantyev
58bb08a252 feat: add find_orphaned_wires schematic analysis tool
Detects wire segments with at least one dangling endpoint — an endpoint
not connected to a component pin, net label, or another wire.  These
cause ERC 'wire end unconnected' violations and are a common symptom of
incomplete routing or stray stub wires.

Algorithm uses exact KiCad IU (10 000 IU/mm) coordinate matching,
consistent with wire_connectivity.py:
  1. Build an endpoint-frequency map for all wires (IU precision)
  2. Collect anchored IU points: component pins (via PinLocator),
     net labels / global_labels, power symbol pins
     (via _parse_virtual_connections)
  3. An endpoint is dangling when it is touched by exactly one wire AND
     is not an anchored point; the containing wire is reported

Does not require the KiCad UI to be running.

Changes:
  python/commands/schematic_analysis.py — find_orphaned_wires() function
  python/kicad_interface.py             — handler + route registration
  python/schemas/tool_schemas.py        — MCP schema entry
  src/tools/schematic.ts                — TypeScript server.tool() call
  tests/test_schematic_analysis.py      — 7 integration tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 14:44:12 +01:00
Eugene Mikhantyev
94125eda7f fix: add pin-snapping and coordinate feedback to net label tools
add_schematic_net_label now accepts optional componentRef + pinNumber to
snap the label directly to the exact pin endpoint via PinLocator, removing
all approximation risk.  The response always includes actual_position and,
when snapping was used, snapped_to_pin — so the caller gets confirmation
of exactly where the label landed.

connect_to_net return type changed from bool to Dict, returning
pin_location, label_location, and wire_stub on success so agents no
longer need a separate verification call to confirm placement.

connect_passthrough updated to check result.get("success") against the
new dict return.  tool_schemas.py and schematic.ts updated to match
(position is now optional, componentRef/pinNumber/labelType/orientation
added, connect_to_net schema field names corrected).

17 new unit tests in tests/test_net_label_pin_snapping.py.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 14:12:11 +01:00
Michael Parment
01011487d0 fix: merge upstream type annotations into create_schematic signature
Combined our path parameter fix with upstream's type annotation additions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 10:43:13 +02:00
Michael Parment
b3ca93a98d fix: create_schematic now respects the path parameter
Previously the path argument to create_schematic() was accepted by the
tool schema but silently ignored in SchematicManager.create_schematic()
(python/commands/schematic.py). The schematic file was always written
using only the bare filename, resolving to the MCP server's working
directory.

On systems where that directory is not writable (e.g. Program Files,
OneDrive-synced folders) this caused:
  [Errno 13] Permission denied: 'myproject.kicad_sch'

Fix:
- Add path: Optional[str] = None parameter to SchematicManager.create_schematic()
- Compute output_path as os.path.join(path, base_name) when path is given
- Forward the resolved path from _handle_create_schematic() into create_schematic()

Tests: added tests/test_create_schematic_path.py with three unit tests
covering: path respected, no-path fallback, and no double-suffix on .kicad_sch names.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 10:27:53 +02:00
Eugene Mikhantyev
9b1024a8f3 chore: enable strict mypy checks and fix pre-commit mypy hook
Add type annotations to all previously untyped functions and remove 9
suppressed error codes (call-arg, assignment, return-value, operator,
has-type, dict-item, misc, list-item, annotation-unchecked) by fixing
the underlying type issues.

Add [[tool.mypy.overrides]] with ignore_missing_imports for KiCAD-specific
modules (pcbnew, sexpdata, skip, cairosvg, kipy, PIL) so the pre-commit
mypy hook passes in its isolated venv. Add types-requests and pytest to
additional_dependencies in .pre-commit-config.yaml.

Also fixes several real bugs uncovered by stricter checks: incorrect static
calls to instance methods in swig_backend, wrong return type on get_size,
missing value param in BoardAPI.place_component, variable shadowing in
kicad_process.py, unqualified LibraryManager reference in kicad_interface,
and missing top-level Path import.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 23:50:54 +01:00
William Viana
0bc00b1451 fix: prevent pcbnew stdout noise from causing sync_schematic_to_board timeouts
The TS<->Python communication channel uses stdout for JSON responses.
pcbnew's C++ SWIG layer can write warnings and diagnostics directly to
C-level stdout (fd 1), corrupting the JSON framing. The TS parser then
never sees valid JSON and the command times out after 30 seconds.

Three changes fix this:

1. Python stdout redirect: In main(), save the original stdout fd for
   exclusive JSON response use, then redirect fd 1 to stderr so all
   pcbnew C++ output goes to logs instead of the response pipe.

2. Robust TS JSON parser: tryParseResponse() now uses newline-delimited
   parsing as a fallback. The Python side writes single-line JSON
   terminated by \n; the parser uses this as the completion signal
   instead of brace-matching, which prevents premature resolution of
   truncated chunked responses. Non-JSON preamble lines are logged
   and stripped.

3. Fix stray print() calls: Converted print() to logger in
   component_schematic.py and library_schematic.py so they don't
   leak to stdout during normal operations.

Also adds sync_schematic_to_board to the longRunningCommands list for
an appropriate timeout value.
2026-04-03 11:24:42 -07:00
Eugene Mikhantyev
d58283ef0a feat: synthesize wires for touching-pin connections on component move
When moving a schematic component whose pins directly touch pins of
stationary components (no wire segment, just pin-to-pin contact),
synthesize bridge wires to preserve the electrical connection after
the move. Also fixes duplicate-pin-position collision in old_to_new
map and updates symbol reference assignment to use setAllReferences.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 23:41:42 +01:00
Eugene Mikhantyev
a152b75db3 feat: move_schematic_component with wire preservation (drag behavior)
When moving a schematic component, connected wires are stretched/shifted
to follow the component (like KiCAD's drag behaviour), preserving
connectivity instead of leaving dangling wire stubs.

Also fixes property labels (value, reference, etc.) so they shift with
the symbol rather than staying at their original positions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 20:34:22 +01:00
Eugene Mikhantyev
c44bd9205d style: sort Python imports with isort
Add isort configuration (profile=black, line_length=100) to pyproject.toml,
add isort pre-commit hook, and auto-sort imports across all Python source files.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-29 13:02:24 +01:00
Eugene Mikhantyev
75cead0860 style: apply Black formatting to all Python files
Add [tool.black] config to pyproject.toml and Black hook to
.pre-commit-config.yaml (rev 26.3.1), then auto-format all Python
source and test files with line-length=100, target-version=py310.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-29 13:01:08 +01:00
Eugene Mikhantyev
eee5bfb9ed chore: set up pre-commit framework with general hooks
Add .pre-commit-config.yaml with pre-commit-hooks v5.0.0 (trailing
whitespace, end-of-file fixer, yaml/json checks, large file guard,
merge conflict detection). Add minimal pyproject.toml. Auto-fix
trailing whitespace and missing end-of-file newlines across the
codebase.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-29 12:58:36 +01:00
Eugene Mikhantyev
3e84957698 style: apply Black formatting to pin_locator.py
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 12:38:17 +01:00
Eugene Mikhantyev
7d53272cb1 fix: replace hardcoded contributor paths in __main__ blocks
Replace /home/chris/... absolute paths with Path(__file__)-relative
equivalents in wire_manager.py and pin_locator.py so the test
scripts work on any machine.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 12:28:27 +01:00
Eugene Mikhantyev
038beb6d26 refactor: use module-level Symbol constants in delete_wire and delete_label
Replace inline Symbol() allocations with the existing _SYM_WIRE/_SYM_PTS/_SYM_XY
constants and new _SYM_AT/_SYM_LABEL constants for consistency.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 12:22:54 +01:00
Eugene Mikhantyev
a11dd5fac9 style: apply Black and Prettier formatting to PR-changed files
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 12:22:54 +01:00
mixelpixx
a76c5bc74b Merge pull request #61 from Mehanik/fix/tool-schema-descriptions
feat: add_schematic_wire & add_schematic_junction with pin snapping and polyline routing
2026-03-28 15:40:58 -04:00
mixelpixx
ac1ea89eb5 Merge pull request #74 from mfiumara/feature/move-component-layer-option
Add layer option to move_component tool
2026-03-27 20:31:13 -04:00
George Evangelopoulos
7ab88adaed kicad_mod parser 2026-03-27 20:22:17 +01:00
George Evangelopoulos
b467d1cff9 fixed broken tool due to naming inconsistencies 2026-03-27 19:52:54 +01:00
Mattia Fiumara
dd388470be Add layer option to move_component to support flipping components
Adds an optional `layer` parameter (e.g., 'F.Cu', 'B.Cu') to the
move_component tool. When specified, the component is flipped to
the target layer if it's not already on it. The response now also
includes the component's layer after the move.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 18:09:24 +01:00
mixelpixx
b02c3ba6fe Merge pull request #71 from LeahArmstrong/fix/jlcpcb-download-and-search
fix: JLCPCB database download and FTS search

Thanks! you rock.  JLCPCB parts things has been a headache. I will look over the whole implementation this weekend.
2026-03-24 20:53:27 -04:00
Eugene Mikhantyev
3bd3c3a962 feat: add wire/junction tools with pin-snapping and T-junction support
- Rename add_schematic_connection → add_schematic_wire with waypoints[] parameter
- Add snapToPins (default true) to snap wire endpoints to nearest pin
- Expose add_schematic_junction as an MCP tool
- Break existing wires at new wire endpoints for T-junction support
- Remove orphaned add_connection / add_wire / get_pin_location from ConnectionManager
- Update tool registry to reflect renamed schematic tools in TS layer
- Add 76 tests for wire/junction handler dispatch, schema validation, and WireManager corner cases
- Apply Black and Prettier formatting to changed files

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 21:46:36 +00:00
Eugene Mikhantyev
9f89437918 chore: apply Black formatting and add tests for get_wire_connections
- Apply Black formatting to wire_connectivity.py, kicad_interface.py,
  and tool_schemas.py (changed files only)
- Add python/tests/conftest.py with pcbnew/skip C-extension stubs
- Add python/tests/test_wire_connectivity.py with 29 unit tests covering
  schema validation, handler dispatch, parameter validation, and core
  logic (_to_iu, _parse_wires, _build_adjacency, _find_connected_wires,
  get_wire_connections)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 19:26:25 +00:00
Eugene Mikhantyev
018f4a278d refactor: switch get_wire_connections to exact IU matching throughout
Remove the 0.5mm query tolerance in favour of exact integer-unit matching
on all coordinate lookups (seed, label bridging, pin matching), mirroring
KiCad's own connectivity algorithm. Callers must supply exact wire endpoint
coordinates (e.g. from list_schematic_wires).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 19:24:38 +00:00
Eugene Mikhantyev
8414784b78 docs: clarify get_wire_connections requires endpoint coordinates
Update tool description and Python docstring to make clear that the
query point must be at a wire endpoint or junction — midpoints of
wire segments are not matched.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 19:24:38 +00:00
Eugene Mikhantyev
de0eca2ed7 refactor: remove redundant junction processing from wire connectivity
Shared-endpoint adjacency already connects all wires meeting at the same
point, making explicit junction handling a no-op duplicate.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 19:24:38 +00:00
Eugene Mikhantyev
f120034846 refactor: extract wire connectivity into module with KiCad-native IU matching
Move wire connectivity logic from _handle_get_wire_connections into
commands/wire_connectivity.py. Use KiCad's internal integer unit system
(10,000 IU/mm) with exact coordinate matching instead of tolerance-based
float comparison, mirroring how KiCad itself determines connectivity.

Key improvements:
- Exact integer matching for wire endpoints (O(1) dict lookup vs O(n) grid scan)
- Junction support for T-connections
- Multi-unit symbol support (removed incorrect processed_refs dedup)
- Single public API: get_wire_connections()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 19:24:38 +00:00
Leah Armstrong
ca40a2b332 fix: JLCPCB database download and FTS search
The JLCSearch API (jlcsearch.tscircuit.com) /components/list.json
endpoint ignores the offset parameter, returning the same 100 parts
on every request. This caused download_jlcpcb_database to loop
indefinitely, importing duplicate data for hours while blocking the
single-threaded Python process.

- Add download_jlcpcb.py: standalone script that downloads the
  pre-built jlcparts database from yaqwsx/jlcparts GitHub Pages
  (~1GB compressed, 7M+ parts, completes in ~4 minutes)
- Fix FTS search: add prefix wildcards to search terms so partial
  MPN matches work (e.g. "BQ25895" now finds "BQ25895RTWR")
2026-03-24 12:04:29 -04:00
Eugene Mikhantyev
59bd4c4acf style: apply Black formatting to changed files
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 21:37:05 +00:00
Eugene Mikhantyev
be11948a44 fix: negate y-axis in graphics transform for correct symbol bounding boxes
Library symbols use y-up coordinates while schematics use y-down. The
_transform_local_point function was not negating y, causing asymmetric
symbols (e.g. power:VEE) to have their bounding boxes computed in the
wrong direction — missing overlaps with adjacent components.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 21:36:50 +00:00
Eugene Mikhantyev
1ef4ce5cab refactor: remove find_unconnected_pins tool (redundant with run_erc)
KiCad's native ERC already checks for unconnected pins with better
accuracy (hierarchical sheets, bus connections, custom rules). Remove
the reimplemented version and its dead helper _parse_no_connects.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 21:36:50 +00:00
Eugene Mikhantyev
dc3dc06af1 feat: use real symbol body graphics for bounding boxes
Parse graphical elements (rectangle, polyline, circle, arc, bezier) from
lib_symbols definitions to compute accurate symbol bounding boxes instead
of relying on pin positions with hardcoded degenerate expansion. This
fixes bbox accuracy for ICs (previously too small), tiny 2-pin passives
(previously too large), and single-pin symbols.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 21:36:50 +00:00
Eugene Mikhantyev
0ab7428b84 fix: address PR review issues for schematic analysis tools
Eliminate repeated file parsing by extracting _extract_lib_symbols helper
that walks already-parsed sexp_data once instead of re-reading the file
per symbol via PinLocator. Support diagonal wire overlap detection using
cross-product parallelism and 1D projection. Fix wire region inclusion to
use AABB intersection for pass-through wires. Normalize view region
coordinates. Clarify tolerance docstrings across Python, TS, and schema.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 21:36:50 +00:00
Eugene Mikhantyev
76ad44121c fix: rename check_wire_collisions to find_wires_crossing_symbols and detect pass-through wires
Wires that start at a component pin but continue through the body were
incorrectly suppressed as "valid connections." Now nudges the pin endpoint
toward the other end and re-tests intersection — if the shortened segment
still hits the bbox, the wire passes through and is flagged.

Renamed the tool from check_wire_collisions to find_wires_crossing_symbols
across all layers (Python, handler, schema, TypeScript) to clarify that it
finds wires crossing over component symbols, which is unacceptable in
schematics.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 21:36:50 +00:00
Eugene Mikhantyev
3ab93b241f fix: find_overlapping_elements uses bounding-box intersection instead of center distance
The overlap detection was comparing center-to-center Euclidean distance with
a 0.5mm tolerance, missing components whose bodies physically overlap but have
different centers (e.g. a resistor placed inside an opamp triangle). Now uses
AABB intersection on pin-derived bounding boxes, matching the approach already
used by check_wire_collisions. Extracted shared bbox logic into
_compute_symbol_bbox_direct and _aabb_overlap helpers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 21:36:50 +00:00
Eugene Mikhantyev
6b09d93df2 fix: check_wire_collisions now detects wires that short two pins of the same component
Previously, the endpoint suppression logic skipped any wire where at least
one endpoint touched a pin, hiding the case where both endpoints are pins
of the same component (a direct pin-to-pin short through the body).

Replace the single endpoint_matches_pin loop with separate start_at_pin /
end_at_pin checks; suppress only when exactly one endpoint is at a pin.
Add regression test to cover this case.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 21:36:50 +00:00
Eugene Mikhantyev
1bfa608729 fix: apply unannotated-reference fix to find_unconnected_pins and get_elements_in_region
The same reference-lookup bug fixed in check_wire_collisions (where
PinLocator.get_all_symbol_pins always resolves to the first symbol
with a given reference) also affected:

- find_unconnected_pins: would check wrong pin positions for all
  unannotated components after the first, producing false connected/
  unconnected reports.
- get_elements_in_region: would return wrong pin coordinates for
  unannotated components in the queried region.

Both now use _compute_pin_positions_direct (fetching pin defs by
lib_id and applying each symbol's own position/rotation/mirror),
matching the fix already applied to check_wire_collisions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 21:36:50 +00:00
Eugene Mikhantyev
53564cbc58 fix: check_wire_collisions reports false positives for unannotated components
PinLocator.get_all_symbol_pins resolves symbols by reference designator,
so when multiple components share the same unannotated reference (e.g. "Q?"),
it always returned the first match's pin positions. Every duplicate then
got an identical bounding box, causing a single wire to be flagged against
all N instances instead of only the ones it actually crosses.

Fix: add _compute_pin_positions_direct() that computes absolute pin positions
directly from each symbol's own (at x y rotation) and (mirror ...) data plus
pin definitions fetched by lib_id — no reference-name lookup involved.
Also extend _parse_symbols to capture mirror_x/mirror_y flags.

Add regression test: two "R?" at different positions, wire crossing only
one → must produce 0 collisions against the far-away component.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 21:36:50 +00:00
Eugene Mikhantyev
764b8db3d3 feat: add schematic analysis tools (read-only)
Add five new read-only schematic analysis MCP tools:
- get_schematic_view_region: export cropped schematic region as PNG/SVG
- find_unconnected_pins: list pins with no wire/label/power connection
- find_overlapping_elements: detect duplicate symbols, stacked labels, collinear wire overlaps
- get_elements_in_region: list all symbols/wires/labels in a bounding box
- check_wire_collisions: detect wires passing through component bodies

Includes Python handler dispatch, tool schemas, TypeScript server bindings,
the schematic_analysis command module, and a full test suite (28 tests passing).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 21:36:50 +00:00
Cabbache
d3ef768ad0 KiCAD 10 support 2026-03-21 23:18:30 +01:00
Jeff Laflamme
7f1b072d00 Add Docker/Podman support for Freerouting autorouter
Auto-detects runtime: Java 21+ direct or Docker/Podman fallback.
Discovers docker/podman via PATH instead of hardcoding.
README includes one-time setup with JAR download + Docker pull.
31 tests covering both execution modes.
2026-03-20 12:01:19 +07:00
Jeff Laflamme
53a8b3ff3e Add Freerouting autoroute integration
4 new MCP tools: autoroute (full DSN→Freerouting→SES pipeline),
export_dsn, import_ses, check_freerouting. Requires Java 11+ and
freerouting.jar. Includes 21 test cases and README usage examples.
2026-03-20 11:33:37 +07:00
Eugene Mikhantyev
f562035f79 test: add schematic tools tests and apply black formatting
- Add python/tests/conftest.py with MagicMock stubs for pcbnew/skip
- Add python/tests/test_schematic_tools.py with 29 tests covering
  WireManager.delete_wire, WireManager.delete_label (unit + integration),
  and parameter validation for all 11 new _handle_* methods
- Apply black formatting to component_schematic.py, wire_manager.py,
  and kicad_interface.py

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-15 22:48:24 +00:00
Eugene Mikhantyev
4dc351660c fix: apply sexpdata round-trip write to delete_schematic_net_label
delete_schematic_net_label was using kicad-skip's write() which silently
discards in-memory _elements mutations. Replaced with WireManager.delete_label()
that uses the same sexpdata round-trip approach already used by delete_schematic_wire.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 01:08:49 +00:00
Eugene Mikhantyev
9d9234abd0 fix: replace kicad-skip mutation with sexpdata in delete_schematic_wire
kicad-skip's write() serializes from original parsed data, silently
discarding in-memory _elements mutations. Switch to the same sexpdata
approach used by add_wire: parse, find matching wire, delete the entry,
write back. Also adds WireManager.delete_wire() static method.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 00:39:23 +00:00
Eugene Mikhantyev
2956b4fa9d fix: use _elements.remove() for kicad-skip collections lacking remove method
ElementCollection in kicad-skip doesn't implement remove(), causing
'WireCollection object has no attribute remove' errors. Access the
underlying _elements list directly for wire, label, and symbol deletion.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 00:27:17 +00:00
Tom
3d9497ebe5 fix: snapshot saves logs+prompt to logs/ subdir; routing via_x under start pad; router disabled 2026-03-11 11:20:05 +01:00
Tom
3e329cbf6b fix: route_pad_to_pad auto-inserts via when pads are on different copper layers
- Detects F.Cu<->B.Cu layer mismatch in route_pad_to_pad
- Splits route into: trace on start layer + via at midpoint + trace on end layer
- route_trace description warns: use route_pad_to_pad for cross-layer routing
- route_pad_to_pad description highlights automatic via insertion
2026-03-07 15:46:54 +01:00
Tom
2e36f96c55 fix: board outline position and rounded corners (3 bugs)
Bug 1 — Rounded corners missing (src/tools/board.ts schema)
  Symptom: Claude sends shape='rectangle' + radius=2.5, but the Zod schema
  only listed 'rectangle', 'circle', 'polygon' as valid shapes. The JS
  handler never passed cornerRadius through the IPC path, and Python only
  generated arcs for shape='rounded_rectangle'. Result: 4 straight lines,
  no arcs.
  Fix: Added 'rounded_rectangle' and 'cornerRadius' to the Zod schema in
  src/tools/board.ts so Claude can send the correct shape directly.
  Also added a Python-side auto-upgrade: if shape='rectangle' and
  cornerRadius>0, silently promote to 'rounded_rectangle' so legacy
  callers still work (python/commands/board/outline.py).

Bug 2 — Board outline placed at (-w/2, -h/2) instead of (0, 0)
  Symptom: A 30x30 mm board outline was placed centred at the origin
  (start -15 -15) ... (end 15 15) instead of the expected top-left at
  (0,0) → (30,30).
  Root cause: src/tools/board.ts extracted x/y from params and renamed
  them to centerX/centerY before forwarding to Python:
      const { x, y, ...otherParams } = params;
      callKicadScript('add_board_outline', { centerX: x, centerY: y, ...otherParams })
  Python received centerX=0, centerY=0 and used that as the board centre,
  placing the outline at (-15,-15)→(+15,+15).
  Fix: Pass x/y directly as top-left corner coordinates. Python already
  contains the correct logic: center = x + width/2, y + height/2. Removed
  the incorrect rename in board.ts:
      callKicadScript('add_board_outline', { shape, ...params })

Bug 3 — print() on stdout corrupted JSON-RPC protocol → Timeout
  Symptom: Claude Desktop reported 'Timeout' for add_board_outline even
  though Python completed the command in <5 ms. KiCAD was falsely launched.
  Root cause: Debug print() statements written to stdout (the same channel
  used for JSON-RPC responses) injected non-JSON lines into the protocol.
  Node.js could not parse the response → timeout → Claude Desktop invented
  a 'KiCAD UI required' workaround.
  Fix: Removed all print() calls from outline.py. Logger.info/debug writes
  to the log file (~/.kicad-mcp/logs/kicad_interface.log) and is safe.

Files changed:
  src/tools/board.ts               — Zod schema + removed centerX/centerY rename
  python/commands/board/outline.py — auto-upgrade rectangle+radius, remove print()
2026-03-07 14:52:45 +01:00
Tom
91fe6a379c feat: dev mode — auto-copy MCP session log to project dir on export_gerber (KICAD_MCP_DEV=1) 2026-03-07 12:45:52 +01:00