feat(component): add check_courtyard_overlaps MCP tool (#189)

Detects courtyard overlaps between footprints and flags courtyards that
extend past the board outline. Returns overlap pairs with intersection
extents (mm), per-component boundary violations, and a placement summary.

The killer feature for AI-driven workflows is the `positions` parameter,
which accepts hypothetical placements `{ref: [x, y]}` or
`{ref: [x, y, rotation_degrees]}`. The tool evaluates the proposed
placement WITHOUT writing to the board file — so an AI agent can validate
a move_component / place_component before committing it, instead of the
current loop of write -> run DRC -> parse violations -> revert.

## Implementation

- Uses the real courtyard polygons from pcbnew (`fp.GetCourtyard(F_CrtYd)`
  or B_CrtYd) for accurate AABBs even on custom and rotated footprints.
- Falls back to `fp.GetBoundingBox()` when no F/B.Courtyard polygon is
  present.
- For virtual rotation, rotates the four AABB corners and re-axis-aligns.
  Conservative: the rotated-AABB is always >= the rotated-polygon, so
  overlap reports are never false-negatives (may be marginally
  over-cautious on diagonal rectangles, which is the right error bias
  for a placement validator).
- Optional `margin` parameter expands every courtyard by N mm — useful
  for enforcing a manufacturing keepout wider than the symbol's
  declared courtyard.

## Attribution

The approach is ported from morningfire-pcb-automation
(https://github.com/NiNjA-CodE/morningfire-pcb-automation), specifically
`scripts/placement/check_overlaps.py`. The upstream uses a static
per-footprint-type courtyard lookup table; this implementation reads
the real polygons from pcbnew so it works on any footprint without
maintaining a table. Attribution is in the function docstring, the
TypeScript wrapper, the tool's description (visible to MCP clients),
and the CHANGELOG entry.

## Tests

12 pytest cases in tests/test_check_courtyard_overlaps.py, all passing:

  - No overlaps when spaced; overlap detected on intersect
  - Margin pushes borderline pairs into overlap
  - `refs` filter restricts the check
  - Boundary violations are flagged; `include_boundary=false` suppresses
  - Virtual position does not mutate the footprint (asserts
    `SetPosition` is never called)
  - Virtual rotation swaps a tall-narrow courtyard's x/y extents
  - No-board-loaded returns clean error payload
  - Bad position spec (wrong arity) returns clean error payload
  - GetCourtyard() OutlineCount=0 -> fallback to GetBoundingBox()
  - `board_outline` override replaces the Edge.Cuts bbox

Tests use mocked pcbnew objects so they run under both the conftest stub
and a real pcbnew install. Real-board smoke test on a 44-footprint
production board succeeds: 1 known overlap detected (SW1<->SW2), 0
boundary violations, virtual placement test reports 6 expected overlaps.

## Files touched

- python/commands/component.py            (impl + helpers)
- python/kicad_interface.py               (tool registration)
- python/schemas/tool_schemas.py          (MCP schema entry)
- src/tools/component.ts                  (TypeScript surface, builds clean)
- tests/test_check_courtyard_overlaps.py  (12 cases)
- CHANGELOG.md                            (Unreleased -> New MCP Tools)
This commit is contained in:
NiNjA-CodE
2026-05-18 21:03:34 -06:00
committed by GitHub
parent aff498ae76
commit 983ffc3793
6 changed files with 697 additions and 0 deletions

View File

@@ -42,6 +42,23 @@ All notable changes to the KiCAD MCP Server project are documented here.
### New MCP Tools
- `check_courtyard_overlaps` — Detect courtyard overlaps between footprints
and (optionally) flag courtyards that extend past the board outline.
Returns overlap pairs with intersection extents (mm), per-component
boundary violations, and a placement summary. Accepts a `positions` dict
of hypothetical placements (with optional rotation) so an AI agent can
validate a proposed `move_component` / `place_component` before
committing it — closing the feedback loop that previously required
writing the move, running DRC, parsing violations, and reverting.
Approach ported from
[morningfire-pcb-automation](https://github.com/NiNjA-CodE/morningfire-pcb-automation)
(`scripts/placement/check_overlaps.py`). The original uses a static
per-footprint-type courtyard lookup table; this implementation reads
the real courtyard polygons (or pad bounding box fallback) from the
loaded board for accuracy on custom and rotated footprints, and adds
virtual placement + clearance margin support.
- `query_zones` — Query copper zones (filled pours) on the board with optional
filters by net, layer, or bounding box. Returns one entry per zone with its
net, layers, priority, fill state, min thickness, bounding box, and filled