From "I want a board that does X" to a wired .kicad_pcb EasyEDA can auto-route and JLCPCB can build — in a single Claude Code conversation. kicad-jlcpcb is a Claude Code plugin + MCP server that automates the tedious half of going from idea to fab.
FAQ
kicad-jlcpcb is a Claude Code plugin with 1 hand-picked skill for automation work, indexed on Flowy. Install it with the command on its page. It includes kicad-jlcpcb-workflow. Its skills do not fire on their own yet. Request auto-invocation to have Flowy route them as you prompt. Free and open source.
$ npx -y skills add BeckhamLabsLLC/kicad-jlcpcb --agent claude-code
From "I want a board that does X" to a wired
.kicad_pcbEasyEDA can auto-route and JLCPCB can build — in a single Claude Code conversation.
kicad-jlcpcb is a Claude Code plugin + MCP server that automates the tedious half of going from idea to fab. It sources LCSC parts with a hard preference for JLCPCB basic-library stock, auto-fetches pin maps from EasyEDA, places KiCad-stdlib footprints, wires every net by pin name (not pad number), and hands off a .kicad_pcb that EasyEDA can route and order in two clicks.
┌─ you ──────────────────────────────────┐
│ /pcb-new An ESP32-C3 soil-moisture │
│ sensor, USB-C, 3.3V LDO... │
└────────────────┬───────────────────────┘
│
┌─────────────▼─────────────┐
│ kicad-jlcpcb MCP server │
│ • source parts (LCSC) │
│ • fetch pin maps │
│ • place + wire footprints│
│ • save .kicad_pcb │
└─────────────┬─────────────┘
│
drag into easyeda.com
│
Auto Route
│
Order via JLCPCB
Three recurring friction points in small-batch PCB work, automated:
GPIO10?" — You stop reading datasheets to build netlists. The plugin queries EasyEDA by LCSC C-number, caches the pin-name → pad-number map, and lets you reference pins by their functional names..kicad_pcb" and hands off to EasyEDA's cloud auto-router, which works on real designs./pcb-new (from a description) and /pcb-from-bom (from a CSV).part-sourcer — finds the best JLCPCB-stocked part for a generic spec.kicad-jlcpcb-workflow — the full reference the LLM consults while driving the workflow..kicad_jlcpcb_session.json so /pcb-new can resume mid-flow after a Claude Code restart.| Component | Version | Notes |
|---|---|---|
| Python | 3.10 – 3.13 | Tested on all four |
| KiCad | 8.0+ | kicad-cli on PATH, pcbnew Python bindings for pcb_generate |
| EasyEDA account | free | Only needed for the final routing + ordering step |
Install KiCad:
sudo dnf install kicadsudo add-apt-repository ppa:kicad/kicad-9.0-releases && sudo apt install kicadsudo pacman -Syu kicadDistributed via GitHub only — no PyPI, no marketplace. Clone and install locally.
git clone https://github.com/BeckhamLabsLLC/kicad-jlcpcb.git
cd kicad-jlcpcb
python -m venv .venv
source .venv/bin/activate # Windows: .\.venv\Scripts\activate
pip install -e ".[dev]"
The editable install puts a kicad-jlcpcb entry-point script in the venv's bin/. .mcp.json calls that script directly; if the venv isn't active when Claude Code launches, point .mcp.json at the absolute path:
{
"mcpServers": {
"kicad-jlcpcb": {
"command": "/abs/path/to/kicad-jlcpcb/.venv/bin/kicad-jlcpcb",
"args": []
}
}
}
If you'd rather install into your user Python without a venv, substitute pip install -e . after cd kicad-jlcpcb and skip the venv lines. The entry-point lands in ~/.local/bin instead.
/plugin marketplace add /abs/path/to/kicad-jlcpcb
/plugin install kicad-jlcpcb@local
Restart Claude Code so the MCP server registers.
kicad-jlcpcb --help # should print nothing (MCP servers speak JSON-RPC on stdio), exit 0
Pick a small idea — an ESP32-C3 board with one sensor, a USB-C port, and an LDO works well. Run:
/pcb-new An ESP32-C3 soil-moisture sensor with two capacitive probes,
USB-C 5V in, a 3.3V LDO, status LED, and JST-PH battery header.
Place it on an 80x60 mm board.
Claude walks you through:
detect_kicad — verify the toolchain (< 1 s)create_project — scaffold .kicad_pro + .kicad_sch + session filelcsc_search per spec (first run populates the 17 MB jlcparts cache)pcb_generate — fetches EasyEDA pin maps (~12 s per unique IC, first run only), places footprints, wires nets, saves .kicad_pcbeasyeda_handoff — prints the import instructionsThe full trace with real timings and tool outputs: examples/soilnode-esp32/walkthrough.md.
First run: ~90 s. Subsequent runs on similar designs: under 10 s.
Set expectations honestly before you start:
.kicad_pcb gets handed to EasyEDA. Freerouting 2.1.0's CLI is buggy and can't handle RF matching networks; nothing else works headlessly well enough to ship.pip install kicad-jlcpcb.| Stage | Tool | Purpose |
|---|---|---|
| Setup | detect_kicad | Probe kicad-cli version, return install hint if missing |
| Setup | create_project | Scaffold .kicad_pro + subdirs + session file |
| Setup | load_project | Validate existing .kicad_pro; surfaces resumable session state |
| Resume | session_resume | Report where a prior workflow left off for a project dir |
| Sourcing | lcsc_search | Free-text part search, basic-only by default |
| Sourcing | lcsc_resolve_bom | Batch BOM resolution with cost-impact warnings |
| Sourcing | fetch_part_library | Placeholder symbol/footprint fetch into project libs/ |
| Pin maps | part_pin_map | Fetch pin-name → pad-number map from EasyEDA |
| Schematic | sch_generate | Emit .kicad_sch from a netlist spec |
| Schematic | sch_run_erc | Run kicad-cli sch erc and parse the report |
| PCB | pcb_generate | Main tool. Auto-fetches pin maps, places footprints, wires every net, saves .kicad_pcb |
| Terminal | easyeda_handoff | Recommended terminal tool. Produces EasyEDA import instructions |
| Legacy | package_for_jlcpcb | For users routing in KiCad: export Gerbers + package a JLCPCB upload zip |
Full input-schema definitions are in src/kicad_jlcpcb_mcp/server.py under _tool_definitions().
pcb_generate consumes a JSON-serializable dict:
{
"name": "demo",
"board": {"width_mm": 80, "height_mm": 60, "layer_count": 2},
"components": [
{
"ref": "U1",
"value": "ESP32-C3-WROOM-02",
"lcsc": "C2934560",
"lib": "RF_Module",
"fp": "ESP32-C3-WROOM-02"
}
],
"nets": {
"3V3": [["U1", "3V3"], ["C1", "1"]],
"GND": [["U1", "GND"], ["C1", "2"]],
"SPI_SCK": [["U1", "GPIO10"], ["U2", "SCK"]]
}
}
Key rules:
3V3, GPIO10, SCK). The plugin resolves them via EasyEDA's pinmap."1", "2".lib and fp are KiCad-stdlib library + footprint names. See /usr/share/kicad/footprints/ for the catalog.Full worked spec: examples/soilnode-esp32/spec.json.
src/kicad_jlcpcb_mcp/
server.py ← MCP server + 13 tool definitions
session.py ← per-project state (.kicad_jlcpcb_session.json)
project.py ← .kicad_pro create / load / validate
kicad_cli.py ← async wrapper for kicad-cli (KiCad 8/9)
lcsc_client.py ← jlcparts mirror + SQLite cache + basic-tier filter
part_library.py ← EasyEDA client (EasyEdaRateLimiter + pin-map cache)
pcb.py ← pcbnew-based .kicad_pcb generator
schematic.py ← netlist spec → .kicad_sch
gerber_pack.py ← KiCad 8/9 Protel extension normalizer + JLCPCB zip
sexpr.py ← s-expression reader/writer
config.py ← module-level constants
All HTTP goes through lcsc_client and part_library. All KiCad CLI invocations go through kicad_cli. pcbnew is lazy-imported inside pcb.py so the rest of the plugin runs fine when KiCad isn't installed (most tools don't need it).
PYTHONPATH=src pytest tests/ # 212 tests (6 skipped without KiCad)
With KiCad's pcbnew bindings available:
KICAD_INSTALLED=1 PYTHONPATH=src pytest tests/ -v # runs integration suite too
Coverage spans subprocess wrapping, HTTP mocking, SQLite cache, s-expression round-trip, schematic emission, Gerber renaming, EasyEDA pin-map parsing, rate-limit / retry, session persistence, MCP tool routing, and real pcbnew board generation.
Lint:
ruff check .
ruff format --check .
Full guide: TROUBLESHOOTING.md. Most common issues:
| Symptom | Fix |
|---|---|
kicad-jlcpcb command not found | pip install -e . from the clone, restart Claude Code |
ImportError: No module named pcbnew | Install KiCad; don't try to pip install pcbnew (it ships with KiCad) |
| First run stalls ~12 s per IC | Expected — EasyEDA rate limit. Cached forever after first fetch. |
Footprint not found | Check /usr/share/kicad/footprints/<lib>.pretty/ for the exact name |
/pcb-new offers to resume when you wanted a clean start | Delete .kicad_jlcpcb_session.json or pick a new project name |
Earlier releases tried to route the board headlessly with Freerouting and produce a JLCPCB Gerber zip directly. That didn't work for real boards — Freerouting 2.1.0 has CLI bugs, can't route RF matching networks, and won't save partial results.
Phase 1.6 takes the pragmatic win: the plugin wires everything up, EasyEDA routes and orders. The tradeoff is opening a browser tab and clicking two buttons; in exchange you get reliability the open-source tooling can't match and a one-click path to a JLCPCB order.
.kicad_pcb.See CONTRIBUTING.md for dev setup, test running, and PR conventions. All contributors follow the Code of Conduct. Bug reports: open an issue.
MIT — see LICENSE.
.claude-plugin/
plugin.json
.github/
ISSUE_TEMPLATE/
bug_report.md
feature_request.md
PULL_REQUEST_TEMPLATE.md
workflows/
lint.yml
test.yml
.gitignore
.mcp.json
agents/
part-sourcer.md
CHANGELOG.md
CODE_OF_CONDUCT.md
commands/
pcb-from-bom.md
pcb-new.md
CONTRIBUTING.md
examples/
soilnode-esp32/
expected-bom.csv
README.md
spec.json
walkthrough.md
LICENSE
pyproject.toml
README.md
skills/
kicad-jlcpcb-workflow/
references/
jlcpcb-rules.md
lcsc-search.md
troubleshooting.md
SKILL.md
src/
kicad_jlcpcb_mcp/
__init__.py
__main__.py
config.py
gerber_pack.py
kicad_cli.py
lcsc_client.py
part_library.py
pcb.py
project.py
schematic.py
server.py
session.py
sexpr.py
tests/
__init__.py
test_gerber_pack.py
test_kicad_cli.py
test_lcsc_client.py
test_part_library.py
test_pcb.py
test_project.py
test_schematic.py
test_server.py
test_session.py
test_sexpr.py
TROUBLESHOOTING.md© 2026 Flowy · Free and open source
Built for Claude Code · Not affiliated with Anthropic