feat(routing): add add_gnd_stitching_vias MCP tool with all-layer collision (#191)
Drop GND stitching vias across the board with collision checking
against every non-GND segment, via, and pad on every copper layer.
PTH vias penetrate the full stackup, so an F.Cu-only check (the most
common shortcut) silently creates shorts on inner / B.Cu copper —
this implementation explicitly walks all layers.
grid Regular grid across the board interior. Default
spacing 5mm.
around_refs Densify around specified footprints (e.g. MCUs,
switching regulators, RF parts). Configurable
density via densifyRadius.
in_zones Restrict placements to candidates inside the filled
polygons of GND copper zones, so each new via lands
on copper that's already a GND equipotential.
Recommended on boards where the GND zone is fragmented:
these vias actually stitch real polygons rather than
floating on silkscreen.
All three strategies use the same collision check + intra-call
clump-prevention, so passing `["grid", "around_refs", "in_zones"]`
is a safe kitchen-sink configuration.
- Auto-detect GND net (tries GND / GROUND / VSS / /GND in order)
OR explicit `gndNet` parameter.
- Per-via geometry control: viaSize, viaDrill, clearance.
- edgeMargin: keep-out distance from board edge.
- maxVias: cap on total placements (useful for incremental work).
- dryRun: return placements without modifying the board — for
previewing before committing.
- Validates viaDrill < viaSize, rejects unknown strategy names,
surfaces clear errors when GND net can't be resolved or the
board outline is missing.
Approach ported from morningfire-pcb-automation
(https://github.com/NiNjA-CodE/morningfire-pcb-automation,
scripts/ground/add_gnd_vias.py). The original parses the PCB text
with regex and writes vias by string concatenation; this port reads
obstacles via the pcbnew API (handles rotated footprints, integrates
with the live in-memory board so two sequential calls see each
other's placements, picks up net codes from the loaded board) and
adds the in_zones strategy, the maxVias cap, and dry-run mode.
Credit is in the docstring, the TypeScript wrapper comment, the MCP
tool description (visible to clients), and the CHANGELOG entry.
tests/test_add_gnd_stitching_vias.py — 18 cases, all passing.
Uses mocked pcbnew objects so the suite runs under both the conftest
stub and a real pcbnew install.
- grid strategy fills empty board with correct count
- collision blocks via near a signal track (with extent assertion)
- GND-net obstacles are correctly ignored
- around_refs densifies near footprints with bounded extent
- in_zones rejects candidates outside HitTestFilledArea
- dryRun does NOT call board.Add
- actual run calls board.Add per placement
- maxVias caps total placements
- intra-call clump prevention (asserts pairwise distance)
- viaDrill >= viaSize is rejected
- unknown strategy name is rejected
- missing GND net returns clear error payload
- no board loaded returns clear error
- named GND net (e.g. VSS) is honoured even when GND also exists
- direct unit tests for _point_to_segment_distance_nm helper
Real-board smoke test on TuneForge_TF001 (4-layer, 44 footprints):
- GND net auto-detected
- grid spacing 4mm: 141 placements, 129 blocked by collision
- grid + in_zones: 140 placed, 15 rejected by zone membership,
115 blocked by collision
python/commands/routing.py (+impl, ~370 LOC)
python/kicad_interface.py (+handler registration)
python/schemas/tool_schemas.py (+MCP schema)
src/tools/routing.ts (+TypeScript surface, builds clean)
tests/test_add_gnd_stitching_vias.py (+18 tests)
CHANGELOG.md (+Unreleased -> New MCP Tools)
This commit is contained in:
36
CHANGELOG.md
36
CHANGELOG.md
@@ -42,6 +42,42 @@ All notable changes to the KiCAD MCP Server project are documented here.
|
||||
|
||||
### New MCP Tools
|
||||
|
||||
- `add_gnd_stitching_vias` — Drop GND stitching vias across the board with
|
||||
collision checking against every non-GND segment, via, and pad on every
|
||||
copper layer. PTH vias penetrate the full stackup, so an F.Cu-only check
|
||||
(the most common shortcut) silently creates shorts on inner / B.Cu
|
||||
copper — this implementation explicitly walks all layers.
|
||||
|
||||
Combines three placement strategies, freely composable:
|
||||
|
||||
- `grid` — regular grid across the board interior.
|
||||
- `around_refs` — densify around named footprints (good for tucking
|
||||
extra ground under MCUs, switching regulators, or RF parts).
|
||||
- `in_zones` — restrict candidates to points inside the filled
|
||||
polygons of GND copper zones, so each new via actually stitches
|
||||
real ground polygons together rather than floating on silkscreen.
|
||||
|
||||
Also supports per-via geometry control (`viaSize`, `viaDrill`,
|
||||
`clearance`, `edgeMargin`), an `maxVias` cap for incremental work,
|
||||
auto-detection of the GND net (tries `GND` / `GROUND` / `VSS` /
|
||||
`/GND`), and a `dryRun` mode that returns the placements that
|
||||
*would* be made without modifying the board — useful for previewing
|
||||
before committing.
|
||||
|
||||
Returns `{ placed: [{x, y, unit}, ...], summary: {placed_count,
|
||||
candidates_evaluated, skipped_by_zone_membership,
|
||||
skipped_by_collision, ...} }`.
|
||||
|
||||
Approach ported from
|
||||
[morningfire-pcb-automation](https://github.com/NiNjA-CodE/morningfire-pcb-automation)
|
||||
(`scripts/ground/add_gnd_vias.py`). The original parses the PCB
|
||||
text with regex and writes new vias by string concatenation; this
|
||||
port reads obstacles via the pcbnew API so it handles rotated
|
||||
footprints correctly, integrates with the in-memory board (two
|
||||
sequential calls see each other's placements), picks up net codes
|
||||
from the live board, and adds the `in_zones` strategy + the
|
||||
`maxVias` cap + dry-run.
|
||||
|
||||
- `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
|
||||
|
||||
Reference in New Issue
Block a user