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:
17
CHANGELOG.md
17
CHANGELOG.md
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user