{"id":"4dda0878-4b2b-495d-a46a-018e24fab627","slug":"kicad-jlcpcb","kind":"mcp","name":"kicad-jlcpcb","summary":"Claude Code plugin that turns a PCB idea into a wired .kicad_pcb ready for EasyEDA auto-routing and one-click JLCPCB ordering — LCSC part sourcing, EasyEDA pin-map auto-fetch, and session-persisted wo","owner":"BeckhamLabsLLC","repoUrl":"https://github.com/BeckhamLabsLLC/kicad-jlcpcb","license":"MIT","licenseTier":"permissive","trust":"community","stars":25,"match":null,"fewStars":false,"format":"mcp","createdAt":null,"addedAt":"2026-10-14T05:04:16.688Z","logoUrl":"https://avatars.githubusercontent.com/u/249525284?v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["developer-tools","browser-web","cloud-infra"],"tags":["anthropic","claude-code","claude-code-plugin","eda","electronics","gerber","hardware","jlcpcb"],"runtime":"python","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-14T05:07:11.198Z","sample":false,"url":"https://conduits.dev/tools/kicad-jlcpcb","language":"Python","transports":["stdio"],"install":{"pypi":"kicad-jlcpcb"},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"# kicad-jlcpcb\n\n[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n[![Python 3.10+](https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12%20%7C%203.13-blue.svg)](#requirements)\n[![KiCad 8+](https://img.shields.io/badge/kicad-8.0%2B-informational.svg)](https://www.kicad.org/)\n[![tests](https://github.com/BeckhamLabsLLC/kicad-jlcpcb/actions/workflows/test.yml/badge.svg)](https://github.com/BeckhamLabsLLC/kicad-jlcpcb/actions/workflows/test.yml)\n[![upstream contract](https://github.com/BeckhamLabsLLC/kicad-jlcpcb/actions/workflows/contract.yml/badge.svg)](https://github.com/BeckhamLabsLLC/kicad-jlcpcb/actions/workflows/contract.yml)\n[![MCP](https://img.shields.io/badge/MCP-server-8A2BE2.svg)](https://modelcontextprotocol.io/)\n\n> 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.\n\n`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.\n\n```text\n┌─ you ──────────────────────────────────┐\n│  /pcb-new An ESP32-C3 soil-moisture    │\n│          sensor, USB-C, 3.3V LDO...    │\n└────────────────┬───────────────────────┘\n                 │\n   ┌─────────────▼─────────────┐\n   │  kicad-jlcpcb MCP server  │\n   │  • source parts (LCSC)    │\n   │  • fetch pin maps         │\n   │  • place + wire footprints│\n   │  • save .kicad_pcb        │\n   └─────────────┬─────────────┘\n                 │\n       drag into easyeda.com\n                 │\n             Auto Route\n                 │\n          Order via JLCPCB\n```\n\n---\n\n## Why this plugin\n\nThree recurring friction points in small-batch PCB work, automated:\n\n1. **\"Is this part basic or extended on JLCPCB?\"** — You stop needing to cross-reference LCSC's UI. The plugin queries the JLCPCB catalog directly, caches the answer, and always prefers basic-tier (no $3/part assembly setup fee).\n2. **\"What's the right pad number for this IC's `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.\n3. **\"Why is my auto-router failing?\"** — You stop fighting Freerouting on RF boards. The plugin stops at \"wired `.kicad_pcb`\" and hands off to EasyEDA's cloud auto-router, which works on real designs.\n\n---\n\n## Quick tour\n\n- **Two slash commands**: `/pcb-new` (from a description) and `/pcb-from-bom` (from a CSV).\n- **One agent**: `part-sourcer` — finds the best JLCPCB-stocked part for a generic spec.\n- **One skill**: `kicad-jlcpcb-workflow` — the full reference the LLM consults while driving the workflow.\n- **14 MCP tools** covering setup, sourcing, schematic, PCB generation, EasyEDA handoff, and session resume.\n- **Session persistence** — each project writes a `.kicad_jlcpcb_session.json` so `/pcb-new` can resume mid-flow after a Claude Code restart.\n\n---\n\n## Requirements\n\n| Component | Version | Notes |\n|---|---|---|\n| Python | 3.10 – 3.13 | Tested on all four in CI |\n| KiCad | 8.0 – 10.x | `kicad-cli` on `PATH` or in a standard install location; `pcbnew` Python bindings for `pcb_generate`. Only the 8.0 floor is enforced — KiCad 11 removed the SWIG bindings and will pass detection, then fail at `pcb_generate`. See [TROUBLESHOOTING](TROUBLESHOOTING.md) |\n| EasyEDA account | free | Only needed for the final routing + ordering step |\n| Network | required | Part data is fetched live — see below |\n\n### Data dependencies\n\nPart sourcing depends on two **third-party, unofficial** services. Neither is\nrun by JLCPCB, and neither is run by us. Both are overridable, so a fork can\npoint at a mirror without touching code:\n\n| Service | Used for | Override |\n|---|---|---|\n| [`jlcsearch.tscircuit.com`](https://github.com/tscircuit/jlcsearch) | Catalog search, JLCPCB stock, basic/extended tier | `KJLC_JLCSEARCH_BASE` |\n| `easyeda.com` | Exact C-number lookup, symbols, pin maps | `KJLC_EASYEDA_BASE` |\n\nResolved parts are cached in `~/.cache/kicad-jlcpcb/lcsc_parts.sqlite` for 24\nhours. There is no bulk catalog download.\n\n> **Why the overrides exist.** v0.1.0 hardcoded a single third-party URL. Upstream\n> retired that data layout, the URL started returning 404, and part sourcing\n> broke silently for months before anyone noticed\n> ([#1](https://github.com/BeckhamLabsLLC/kicad-jlcpcb/issues/1)). A weekly CI job\n> now tests both services directly, and you can repoint either one yourself.\n\nInstall KiCad:\n\n- **Fedora 40+:** `sudo dnf install kicad`\n- **Ubuntu 22.04+:** `sudo add-apt-repository ppa:kicad/kicad-9.0-releases && sudo apt install kicad`\n- **Arch:** `sudo pacman -Syu kicad`\n- **macOS:** [kicad.org/download](https://www.kicad.org/download/)\n\n---\n\n## Install\n\n```\n/plugin marketplace add BeckhamLabsLLC/claude-plugins\n/plugin install kicad-jlcpcb@beckhamlabs-plugins\n```\n\nRestart Claude Code, then run `/mcp` and look for `kicad-jlcpcb`.\n\nThat is the whole install. You do not need to clone the repo, and you do not\nneed to install anything with `pip` — the plugin resolves its own two\ndependencies (`mcp`, `httpx`) on first launch via [uv](https://docs.astral.sh/uv/),\nwhich most Python toolchains already have:\n\n```bash\ncurl -LsSf https://astral.sh/uv/install.sh | sh    # if you do not have it\n```\n\nIf you would rather not use uv, install the dependencies into whichever Python\n`python3` resolves to and the plugin will use them directly:\n\n```bash\npython3 -m pip install mcp httpx\n```\n\nKiCad itself is a separate install — see [Requirements](#requirements).\n\n<details>\n<summary>Installing from a clone instead (contributors)</summary>\n\n```bash\ngit clone https://github.com/BeckhamLabsLLC/kicad-jlcpcb.git\ncd kicad-jlcpcb\npip install -e \".[dev]\"\n```\n\nThen register the clone as a local marketplace, which is what makes Claude Code\nexpand `${CLAUDE_PLUGIN_ROOT}` for the MCP server:\n\n```\n/plugin marketplace add /abs/path/to/kicad-jlcpcb\n/plugin install kicad-jlcpcb@beckhamlabs\n```\n\nNote the marketplace name differs from the published one: the repo's own\n`.claude-plugin/marketplace.json` declares `beckhamlabs`, while the aggregator\nrepo declares `beckhamlabs-plugins`.\n\nDo **not** register the checkout by enabling its `.mcp.json` as a project\nserver. `${CLAUDE_PLUGIN_ROOT}` is only substituted for plugin-provided MCP\nconfigs; in project scope it stays a literal string and the server cannot be\nfound. See [TROUBLESHOOTING](TROUBLESHOOTING.md).\n\n</details>\n\n### Sanity check\n\n`/mcp` in Claude Code should list `kicad-jlcpcb` with its 14 tools. If it\nreports the server failed, see [TROUBLESHOOTING](TROUBLESHOOTING.md) — the\nfirst step there prints the actual reason, which Claude Code does not show you.\n\nFrom a clone, you can also check the whole path end to end — that the server\nstarts, registers its handlers, and answers a real tool call:\n\n```bash\npython3 bin/launch.py --version     # prints the version, exits 0\npython3 scripts/check_protocol.py   # initialize -> tools/list -> tools/call\n```\n\nRun the launcher with no arguments and it will appear to hang — that is\ncorrect. An MCP server speaks JSON-RPC on stdio and is waiting for a client.\n\n---\n\n## Five-minute quick-start\n\nPick a small idea — an ESP32-C3 board with one sensor, a USB-C port, and an LDO works well. Run:\n\n```\n/pcb-new An ESP32-C3 soil-moisture sensor with two capacitive probes,\n         USB-C 5V in, a 3.3V LDO, status LED, and JST-PH battery header.\n         Place it on an 80x60 mm board.\n```\n\nClaude walks you through:\n\n1. `detect_kicad` — verify the toolchain (< 1 s)\n2. `create_project` — scaffold `.kicad_pro` + `.kicad_sch` + session file\n3. Decomposes the description into ~12 generic part specs\n4. `lcsc_search` per spec (live catalog query, cached locally for 24 h)\n5. **BOM checkpoint** — shows every resolved part, flags extended-tier ones with cost warnings, and waits for your confirmation\n6. `pcb_generate` — fetches EasyEDA pin maps (~12 s each, only for parts whose nets reference pins by *name*, first run only), places footprints, wires nets, saves `.kicad_pcb`\n7. `easyeda_handoff` — prints the import instructions\n\nThe full trace with real timings and tool outputs: **[`examples/soilnode-esp32/walkthrough.md`](examples/soilnode-esp32/walkthrough.md)**.\n\nFirst run: ~90 s. Subsequent runs on similar designs: under 10 s.\n\n---\n\n## What the plugin does **not** do\n\nSet expectations honestly before you start:\n\n- ❌ **Auto-route traces.** That's why the `.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.\n- ❌ **Beautiful placement.** The three-band grid (connectors on top, ICs in the middle, passives below) is functional, not pretty. You rearrange in EasyEDA before routing.\n- ❌ **Design review.** There's no DRC integration (yet — see Roadmap). The plugin trusts your spec and relies on KiCad / EasyEDA to catch rule violations.\n- ❌ **PyPI distribution.** Install through the Claude Code marketplace. There is no `pip install kicad-jlcpcb`.\n\n---\n\n## MCP tool surface\n\n| Stage | Tool | Purpose |\n|---|---|---|\n| Setup | `detect_kicad` | Probe `kicad-cli` version, return install hint if missing |\n| Setup | `create_project` | Scaffold `.kicad_pro` + subdirs + session file |\n| Setup | `load_project` | Validate existing `.kicad_pro`; surfaces resumable session state |\n| Resume | `session_resume` | Report where a prior workflow left off for a project dir |\n| Resume | `session_confirm_bom` | Record the user's BOM approval so a restart doesn't re-ask |\n| Sourcing | `lcsc_search` | Free-text part search, basic-only by default |\n| Sourcing | `lcsc_resolve_bom` | Batch BOM resolution with cost-impact warnings |\n| Sourcing | `fetch_part_library` | Symbol + footprint from EasyEDA's real geometry into project `libs/` |\n| Pin maps | `part_pin_map` | Fetch pin-name → pad-number map from EasyEDA |\n| Schematic | `sch_generate` | Emit `.kicad_sch` from a netlist spec |\n| Schematic | `sch_run_erc` | Run `kicad-cli sch erc` and parse the report |\n| PCB | **`pcb_generate`** | **Main tool.** Auto-fetches pin maps, places footprints, wires every net, saves `.kicad_pcb` |\n| Terminal | **`easyeda_handoff`** | **Recommended terminal tool.** Produces EasyEDA import instructions |\n| Legacy | `package_for_jlcpcb` | For users routing in KiCad: export Gerbers + package a JLCPCB upload zip |\n\nFull input-schema definitions are in [`src/kicad_jlcpcb_mcp/server.py`](src/kicad_jlcpcb_mcp/server.py) under `_tool_definitions()`.\n\n---\n\n## PCB spec format\n\n`pcb_generate` consumes a JSON-serializable dict:\n\n```json\n{\n  \"name\": \"demo\",\n  \"board\": {\"width_mm\": 80, \"height_mm\": 60, \"layer_count\": 2},\n  \"components\": [\n    {\n      \"ref\": \"U1\",\n      \"value\": \"ESP32-C3-WROOM-02\",\n      \"lcsc\": \"C2934560\",\n      \"lib\": \"RF_Module\",\n      \"fp\": \"ESP32-C3-WROOM-02\"\n    }\n  ],\n  \"nets\": {\n    \"3V3\":     [[\"U1\", \"3V3\"], [\"C1\", \"1\"]],\n    \"GND\":     [[\"U1\", \"GND\"], [\"C1\", \"2\"]],\n    \"SPI_SCK\": [[\"U1\", \"GPIO10\"], [\"U2\", \"SCK\"]]\n  }\n}\n```\n\nKey rules:\n\n- Reference IC pins by their **functional name** (`3V3`, `GPIO10`, `SCK`). The plugin resolves them via EasyEDA's pinmap.\n- For passives (R, C, L, D), use bare pad numbers: `\"1\"`, `\"2\"`.\n- `lib` and `fp` are KiCad-stdlib library + footprint names. The plugin finds KiCad's footprint directory automatically on Linux, macOS, Windows and Flatpak; override with `KJLC_FOOTPRINT_DIR` or `pcb_generate`'s `lib_dir`.\n\nFull worked spec: **[`examples/soilnode-esp32/spec.json`](examples/soilnode-esp32/spec.json)**.\n\n---\n\n## Architecture\n\n```\nsrc/kicad_jlcpcb_mcp/\n  server.py         ← MCP server + 14 tool definitions\n  session.py        ← per-project state (.kicad_jlcpcb_session.json)\n  project.py        ← .kicad_pro create / load / validate\n  kicad_cli.py      ← async wrapper for kicad-cli (KiCad 8–10)\n  lcsc_client.py    ← jlcsearch + EasyEDA lookup, SQLite cache, basic-tier filter\n  part_library.py   ← EasyEDA client (EasyEdaRateLimiter + pin-map cache)\n  pcb.py            ← pcbnew-based .kicad_pcb generator\n  schematic.py      ← netlist spec → .kicad_sch\n  gerber_pack.py    ← Protel extension normalizer + JLCPCB zip\n  sexpr.py          ← s-expression reader/writer\n  config.py         ← module-level constants\n```\n\nAll 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).\n\n---\n\n## Testing\n\n```bash\npytest tests/       # offline suite; nothing here touches the network\n```\n\nTwo suites are gated behind environment variables because they need something\nthe default run can't assume:\n\n```bash\nKICAD_INSTALLED=1 pytest tests/ -v                          # needs pcbnew\nKJLC_NETWORK_TESTS=1 pytest tests/test_network_contract.py  # hits live APIs\n```\n\nThe offline suite covers subprocess wrapping, HTTP mocking, the SQLite cache,\ns-expression round-trip, schematic emission, Gerber renaming, EasyEDA pin-map\nparsing, rate-limit / retry, session persistence, MCP tool routing, and real\n`pcbnew` board generation.\n\n**`test_network_contract.py` earns its own paragraph.** Every other test is\nmocked, which is why the whole suite stayed green for four months while part\nsourcing was completely broken in the field. The contract tests assert the\n*shape* of live upstream responses — never a specific price or stock figure —\nand run weekly in CI. If that badge goes red, part sourcing is broken for\neveryone; please open an issue.\n\nLint:\n\n```bash\nruff check .\nruff format --check .\n```\n\n---\n\n## Troubleshooting\n\nFull guide: **[`TROUBLESHOOTING.md`](TROUBLESHOOTING.md)**. Most common issues:\n\n| Symptom | Fix |\n|---|---|\n| MCP server shows as failed / `CONNECTION_CLOSED` | Run `python3 bin/launch.py --version` by hand — it prints what is missing. Usually: install `uv`, or `python3 -m pip install mcp httpx`. |\n| `ImportError: No module named pcbnew` | Install KiCad; don't try to `pip install pcbnew` (it ships with KiCad) |\n| First run stalls ~12 s per part | Expected — EasyEDA rate limit, and only for parts whose nets use pin *names*. Cached forever after the first fetch. |\n| `Footprint not found` | The error names how many libraries were found and suggests near matches. If none were found, set `KJLC_FOOTPRINT_DIR`. |\n| `/pcb-new` offers to resume when you wanted a clean start | Delete `.kicad_jlcpcb_session.json` or pick a new project name |\n\n---\n\n## What you get, and what to check\n\nThe plugin produces a `.kicad_pcb` with real footprints and every net wired,\nplus a JLCPCB upload zip. Two things are worth checking before you order:\n\n**Part geometry comes from EasyEDA.** Symbols carry the real pin names and\nnumbers, and footprints the real pad positions, sizes and drills — EasyEDA,\nLCSC and JLCPCB share a parent company, so this is the same data JLCPCB\nassembles against. When EasyEDA has no geometry for a part, a placeholder is\nwritten instead and `fetch_part_library` says so in `warnings`. **A\nplaceholder footprint will not match the real part** — replace it from\nKiCad's standard libraries before ordering.\n\n**CPL rotations are passed through, not corrected.** JLCPCB's expected\norientation differs from KiCad's for some packages. Footprints generated from\nEasyEDA already share JLCPCB's convention; footprints you take from KiCad's\nstandard libraries may not. The plugin says so rather than applying a guess\nthat silently rotates parts — check JLCPCB's assembly preview after upload and\nfix anything that looks wrong there.\n\n---\n\n## Design rationale: why the handoff\n\nEarlier 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.\n\nSo the plugin takes the pragmatic win: **it 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.\n\n---\n\n## Roadmap\n\n- **Next** — auto-placement that respects functional groupings (power domain, RF block, analog front-end), DRC integration, differential-pair awareness, and a per-package CPL rotation table so JLCPCB orientations need no manual correction.\n- **Later** — vision-based schematic extraction: drop in a photo of a hand-drawn schematic, out comes a wired `.kicad_pcb`.\n\n---\n\n## Contributing\n\nSee **[`CONTRIBUTING.md`](CONTRIBUTING.md)** for dev setup, test running, and PR conventions. All contributors follow the [Code of Conduct](CODE_OF_CONDUCT.md). Bug reports: [open an issue](https://github.com/BeckhamLabsLLC/kicad-jlcpcb/issues).\n\n---\n\n## License\n\nMIT — see **[`LICENSE`](LICENSE)**.\n"}