kicad-forge
# kicad-forge
[](https://github.com/mpeyal/kicad-forge/actions/workflows/tests.yml)
[](https://www.python.org/)
[](LICENSE)
One MCP server for KiCad **analysis + authoring + simulation**. Reads and writes
KiCad files directly as S-expressions, so nothing here needs KiCad installed
except the two things that genuinely do (cross-checking netlists with
`kicad-cli`, and reading the stock symbol libraries).
Built and tested in one session. **141/141 tests pass** — 113 unit, 28 over the
live MCP protocol. Read the *Honest status* section before you trust it with a
board you are paying to fabricate.
---
## Install
```bash
git clone https://github.com/mpeyal/kicad-forge.git
cd kicad-forge
pip install mcp
```
That is the only dependency. Everything else is the standard library.
Register with Claude Desktop — `%APPDATA%\Claude\claude_desktop_config.json`:
```json
{
"mcpServers": {
"kicad-forge": {
"command": "C:\\Program Files\\KiCad\\10.0\\bin\\python.exe",
"args": ["C:\\path\\to\\kicad-forge\\run_server.py"]
}
}
}
```
Using **KiCad's bundled Python** is recommended but not required — it is not
needed for parsing (this server never imports `pcbnew`), but it guarantees
`kicad-cli` is on PATH for `verify_netlist`. Any Python 3.10+ works.
Claude Code:
```bash
claude mcp add kicad-forge -s user -- python -m kicad_forge.server
```
> [!IMPORTANT]
> **If Claude Desktop came from the Microsoft Store**, `%APPDATA%` is
> virtualised and the config is NOT at `AppData\Roaming\Claude\`. It lives at:
>
> ```
> %LOCALAPPDATA%\Packages\Claude_<id>\LocalCache\Roaming\Claude\claude_desktop_config.json
> ```
>
> Editing the non-packaged path appears to work and silently does nothing —
> no server, and no log file to tell you why. If you add an entry and no
> `mcp-server-<name>.log` ever appears in `%LOCALAPPDATA%\Claude\Logs`, you
> are editing the wrong file.
Verify: ask *"what are kicad-forge's capabilities?"* — the `capabilities` tool
reports the version, whether KiCad's symbol libraries were found, whether a
SPICE engine was found, and the full coverage manifest.
---
## The 18 tools
**Analysis**
| Tool | Does |
|---|---|
| `analyze_project` | Full review: components, nets, analog/digital checks, PCB routing, DFM |
| `list_components` | Components with prefix/value filters |
| `list_nets` | Netlist derived geometrically from the files |
| `trace_connections` | Every connection from a component or one pin |
| `verify_netlist` | **Diffs our netlist against `kicad-cli`'s own export** |
**PCB**
| Tool | Does |
|---|---|
| `pcb_statistics` | Layers, dimensions, footprints, tracks, vias, zones |
| `pcb_connectivity` | Union-find copper graph: routed / unrouted / islanded nets |
| `list_footprints` | Footprints, filterable by board side |
**Authoring** (atomic writes)
| Tool | Does |
|---|---|
| `create_kicad_project` | `.kicad_pro` + `.kicad_sch` + `.kicad_pcb`, optional outline |
| `add_component` | Place a symbol from KiCad's libraries or the built-in set |
| `add_generic_ic` | Rectangular IC from a pin list, for parts in no library |
| `add_wire` / `add_label` | Wires and local/global/hierarchical labels |
| `component_pin_positions` | Exact pin coordinates, so wires land on pins |
**Simulation**
| Tool | Does |
|---|---|
| `export_spice_netlist` | SPICE netlist; active devices are *skipped*, never guessed |
| `simulate_subcircuits` | Auto-generates testbenches, runs them, compares to analytics |
| `run_spice` | Run an arbitrary deck |
---
## Write safety
You asked for no safety layer, and there is none: no dry-run gating, no `.bak`
files, no confirmation prompts. Writes go straight through.
What is kept, because it is the absence of a bug rather than a safety feature:
1. **Atomic replace.** Serialise to a temp file in the same directory → `fsync`
→ `os.replace()` (atomic on Windows and POSIX). A crash mid-write leaves the
original file untouched instead of truncated.
2. **Verify before replace.** The serialised bytes are re-parsed and compared
to the source tree. A mismatch raises and writes nothing.
3. **Atom text is preserved verbatim.** `1.270000` stays `1.270000`; `0.1` stays
`0.1`. Numbers are never round-tripped through `float()` and reformatted.
That last point is why the round-trip is **byte-identical** on real KiCad files —
your git diffs show only what actually changed.
**Still: keep your projects in git.** Nothing above protects you from a logic bug.
---
## Honest status
### Verified
- **Verified against real LTspice 24.1.9.** Decks generated by this tool were
executed by LTspice on Windows:
| Testbench | Analytical | LTspice | Error |
|---|---|---|---|
| RC low-pass 10k/100n | 159.154943092 Hz | 159.154943622 Hz | 3.3e-7 % |
| Divider 100k/100k | 0.500000000 V | 0.500000000 V | 0 % |
The LTspice `.log` files are checked in under `tests/fixtures/ltspice/` and
asserted on every run.
- **100% agreement with KiCad's own netlist exporter.** A 24-component ESP32
board was generated by this tool, opened in **Eeschema 10.0.5**, and its
netlist exported by KiCad. All **18 nets match exactly** — same pin
membership, same net names, zero missing, zero invented. KiCad's `.net` file
is checked in as `tests/fixtures/esp32_sensor_kicad_reference.net` and is
asserted against on every test run.
- **Byte-identical round trip** on real KiCad 9 `.kicad_sch` and `.kicad_pcb`.
- **Known-answer detector maths**, hand-computed and asserted exactly:
regulator Vout 5.1956 V, divider ratio 0.153976, RC cutoff 159.1549 Hz,
I²C rise time 398.2 ns.
- **55 component-value spellings** (`4k7`, `1R0`, `2u2`, `100nF/50V`,
`1uF 0805`, `4.7 kOhm`, …).
- **Pin geometry** against hand-computed transforms at 0/90/180/270° and both
mirrors; all pins land on KiCad's 1.27 mm grid.
- **Cross-validated with `kiutils`**, an independent third-party parser: it
reads the schematics this tool writes and agrees on the component set.
- **28 checks over the real MCP protocol** — subprocess, stdio, handshake,
`tools/list`, `tools/call`.
### Not verified
- **No large-corpus validation.** kicad-happy is regression-tested against
5,800+ real projects. This has been checked against one real KiCad-exported
netlist, two real KiCad files, and fixtures it generated itself. Expect
format edge cases on real-world boards — run `verify_netlist` on your own
designs, which is exactly what it is for.
- **PCB authoring is not implemented.** Only project scaffolding and board
outline. No footprint placement, no routing, no Gerber export.
### Deliberately not implemented
`detectors.COVERAGE` lists this in the tool output too, so the model using the
server sees it rather than reading an empty findings list as a clean board:
EMC / radiated emissions · thermal / junction temperature · component lifecycle
& EOL · MPN sourcing · voltage derating · signal integrity & impedance ·
differential-pair skew · datasheet extraction · power sequencing · Gerber
verification.
**An empty findings list is not a clean bill of health.** For those domains use
kicad-happy, which implements them properly.
### Known limitations
- I²C detection is name-based; a bus with unconventional net names is missed.
- Divider detection is topological — it reports voltage-sensing dividers too.
- RC filter detection requires the cap's far side to be ground.
- PCB pad/track contact uses bounding boxes; rotated non-rectangular pads are
approximated.
- Arc tracks are measured by their chord, so arc-heavy boards under-report
total track length.
- The `VREF_TABLE` covers 28 regulators. Unknown parts report `needs-data`
rather than guessing a Vref.
---
## Where this fits
It does not replace kicad-happy — that has 61 detectors and a 5,800-project
regression corpus, and this does not. What this adds is the combination you
asked for in one server: **authoring and simulation and analysis**, with no
`pcbnew`/SWIG dependency and no KiCad required for the read path.
A reasonable split: this for authoring and netlist/SPICE work, kicad-happy for
the review pass before you order boards.
---
## Tests
```bash
python kicad_forge/tests/test_suite.py # 113 unit tests
python kicad_forge/tests/test_mcp_protocol.py # 28 protocol tests
python kicad_forge/tests/make_fixture.py # regenerate the known-answer fixture
```
MIT.
TDQS
Scored across 18 tools
Tools map to distinct actions and resources, so an agent can usually tell list_components from list_nets or pcb_statistics. The slight overlap comes from the SPICE-related tools and analyze_project, which can approach similar territory but are differentiated by purpose and output.
Most tools follow a clear snake_case verb_noun or area_noun pattern: list_*, add_*, pcb_*, simulate_*, run_*. A few names like capabilities and component_pin_positions are noun phrases rather than verb-first actions, but the overall style is consistent enough to navigate.
With 18 tools the server is slightly above the typical well-scoped 3-15 range, but the tool set spans schematic analysis, PCB analysis, project creation, and simulation. Each tool has a distinct job, so the larger count is justified rather than bloated.
The server covers project creation, additive schematic editing, net tracing, PCB statistics/connectivity, and SPICE workflows well. However, it lacks update, remove, or move operations for components, wires, and labels, leaving the editing lifecycle incomplete for a design tool.