Copper
Copper is an MCP server that lets an AI design real KiCad boards end-to-end, from schematics and part sourcing through PCB layout, checks, renders, and fab-ready output.
Create, open, summarize, and switch KiCad projects; snapshot, diff, and restore design files.
Read and atomically edit schematics by pin/net name; auto-layout or tidy sheets without changing the circuit.
Search, import, and inspect real LCSC/JLCPCB parts, source a BOM, and find in-stock alternatives.
Search KiCad symbol/footprint libraries and repair library tables.
Run KiCad ERC/DRC plus engineering design reviews with actionable fixes.
Read, sync, place, and edit PCBs; set outlines, holes, layers, rules, and net classes.
Route boards with a built-in guided router or Freerouting; add explicit tracks/vias and copper pours.
Render schematics, PCB layers, and 3D views; focus on user-pointed areas via Copper Canvas or KiCad selection.
Export Gerbers, drill, BOM, placement, PDF/SVG/STEP/etc., and generate fab order packs with stock checks.
Build the whole board in one call and automatically checkpoint before mutating tools write.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Copper Design a 30 x 40 mm USB-C powered ESP32-C3 board with a status LED"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
copper-kicad-mcp
Copper connects your AI app to KiCad, so it can design real boards you can order: schematic, LCSC parts, PCB layout and routing, KiCad's own ERC and DRC, renders and JLCPCB fab files.
Install
You need KiCad 10. Then pick one:
You use | Do this |
Windows, any AI app | Run |
Claude Desktop | Double-click |
Claude Code | The two plugin commands below |
Cursor, VS Code, Windsurf, Codex, Zed and others |
|
A terminal | The one-line installer below |
# Claude Code
claude plugin marketplace add claynicholson/copper-kicad-mcp
claude plugin install copper@copper# Windows (PowerShell)
powershell -ExecutionPolicy Bypass -c "irm https://raw.githubusercontent.com/claynicholson/copper-kicad-mcp/main/installer/install.ps1 | iex"# macOS / Linux
curl -LsSf https://raw.githubusercontent.com/claynicholson/copper-kicad-mcp/main/installer/install.sh | shWindows is tested end to end. The macOS and Linux routes are new: if one fails, please open an issue.
Setup finds KiCad, brings your libraries and settings along, connects your AI apps and makes a test call. It asks before each step and backs up everything it changes. To paste a config instead, Cursor, Claude Desktop and Windsurf take this entry (docs/INSTALL.md has the others):
{ "mcpServers": { "copper": { "command": "npx", "args": ["-y", "copper-kicad"] } } }npx -y copper-kicad setup --demo runs the setup page on a throw-away folder, so you can look first. If something
does not work, npx -y copper-kicad doctor (or copper doctor after the Windows or one-line install) names the
fix. More in docs/INSTALL.md.
Related MCP server: KiCAD MCP Server
What it does
Ask for something like "Design a USB-C powered ESP32-C3 board with a status LED, 30 x 40 mm". Your AI then works through it the way an engineer would:
It connects pins to nets by name (
U1.PA9 → USB_DP), never by coordinates.It searches LCSC/JLCPCB for real parts (Basic parts first, live stock) and imports each part's symbol and footprint, plus its 3D model when EasyEDA has one.
KiCad's ERC and DRC re-run after every change, and each finding comes with a ready fix.
It places parts and routes the board: a staged router with length matching, differential pairs and width classes, copper pours, and Freerouting.
It looks at its work: schematic, layer and ray-traced 3D renders go back to the model.
It writes Gerbers, drill, BOM and placement files for JLCPCB (or PCBWay, OSH Park, generic), zipped.
Copper has 31 tools and works with any MCP app and any model. The model is your AI app's: the Copper server never calls one.
Boards made with Copper
All six pass KiCad 10's ERC and DRC with 0 errors and 0 unconnected items. Layer art and fab files (Gerbers, drill, BOM, placement) are on coppereda.com.
Docs
Install · Configuration · Parts providers · Fab profiles · KiCad compatibility · Architecture · Changelog · Contributing · Security
Privacy
Copper runs on your machine. Your designs stay there, and there is no telemetry. It goes online only to:
search and download parts: LCSC, JLCPCB and EasyEDA, with the jlcsearch.tscircuit.com mirror as a fallback
check for a newer KiCad (gitlab.com) during
setupanddoctor;COPPER_NO_UPDATE_CHECK=1turns that offdownload Freerouting (GitHub) and a Java runtime (Adoptium), about 120 MB once, when you ask for autorouting
sign in to GitHub, if you link it without the GitHub CLI
Installing fetches a little more: the npx launcher installs Pillow from PyPI if KiCad's Python lacks it, and the
one-line installers fetch uv, a Python 3.12 build and Pillow.
The MCP server and CLI never call a language model. The package also holds copper_kicad.agent, a chat sidecar for
a separate desktop app; nothing in the server or CLI starts it.
License
MIT. Copper is an independent project, not affiliated with KiCad, LCSC, JLCPCB or any other vendor named here.
Available Tools
31 toolsboard_buildBuild the board (sync to DRC)ADestructive
The whole board in ONE call: update the PCB from the schematic, outline, placement, routing, ground pour and
KiCad's DRC + ERC, with one compact report (a line per stage, error groups with fixes, fab_ready, next). Use it
instead of pcb_sync, pcb_setup, pcb_place, pcb_route, pcb_pour and verify one after another.
width/height (mm) apply when the board has no outline (omit both to size it from the parts) or with
outline='replace'. An existing outline, existing tracks and placed parts are kept: on a board that already has
copper only new footprints are placed and only missing connections are routed.
If the result has pending, the time box was reached: call board_build() again to continue.
Example: board_build(width=50, height=32)
Inputs: keep, pour, holes, image, +11 more.
checkpointCheckpointsADestructive
Snapshot / list / diff / restore the project's design files (.kicad_sch, .kicad_pcb, .kicad_pro, rules, lib tables) in .copper/snapshots. action: 'create' (label optional) · 'list' · 'diff' (id optional, default newest: what changed since) · 'restore' (id required; snapshots the current state first, refuses if the file is open in KiCad). Mutating tools snapshot by themselves before they write. Example: checkpoint(action='diff')
Inputs: action (required), id, label, project.
copper_helpTool helpARead-onlyIdempotent
Worked examples, op catalogues and argument details for one Copper tool: the long-form help that is kept out of
the tool list. Call it before your first non-trivial use of a tool, or when a call came back BAD_ARGUMENT / BAD_OP.
Omit tool to list every tool with a one-line summary. Example: copper_help(tool='sch_apply')
Inputs: tool.
copper_statusCopper statusARead-onlyIdempotent
Start here. Shows Copper + KiCad versions and installs, what works on this machine (kicad-cli, KiCad's pcbnew Python for
board edits, live IPC socket, Freerouting/Java for autorouting), the active project (+ whether it's open in KiCad, last ERC/DRC counts),
recent projects, tool modules that failed to load, session (what this session's Copper calls cost so far) and next: the single
most useful next call. detail='credits' returns the per-tool table instead: calls, result bytes, images, estimated tokens.
Inputs: detail.
design_reviewDesign reviewARead-onlyIdempotent
Engineering review of the schematic netlist (and the board, if any): catches what passes ERC but kills boards.
Decoupling, I2C pull-ups, crystal load caps, USB-C CC resistors, USB ESD, regulator caps and feedback-divider voltage, floating EN/RESET/BOOT pins,
LED resistors, undriven rails, part sourcing (+ the fab's assembly-class fee), missing footprints, label typos, thin power-path tracks, thermal pads without vias.
Read-only. Each finding has a fix. checks: subset of the enum (default all but schematic_style).
Example: design_review(checks=['decoupling','usb_c_cc'])
Inputs: limit, checks, project.
exportExportAIdempotent
Export any other manufacturing/documentation output with kicad-cli; the files are verified to exist and be non-empty. kind: pdf_schematic | svg (schematic, one per sheet) | pcb_pdf | step | glb | vrml | ipc2581 (BOM columns from the part-number/MPN fields) | odb | netlist (KiCad s-expr) | bom (CSV grouped by Value/Footprint/part number) | pos (CSV, mm, both sides, DNP excluded) | drill | gerbers | render3d (PNG) | stats (board statistics JSON) | ipcd356. out: file (or folder for svg/drill/gerbers); default /copper-out/export/. For a fab's order pack use fab_export instead. Examples: export(kind='step') · export(kind='pdf_schematic') · export(kind='pcb_pdf', layers=['F.Cu','Edge.Cuts'])
Inputs: kind (required), out, view, layers, +1 more.
fab_exportFab order packAIdempotent
Produce the order pack for a PCB fab: Gerbers + Excellon drill zipped, a BOM CSV and a placement (centroid/CPL) CSV, all in the format of a fab PROFILE. Writes to /copper-out/fab/. profile: omit to use the project's configured profile (fab.profile in the Copper config; 'jlcpcb' out of the box). Built in: 'jlcpcb' (Protel gerbers; BOM 'Comment, Designator, Footprint, LCSC Part #'; CPL 'Designator, Mid X, Mid Y, Layer, Rotation' with JLC rotation corrections), 'pcbway', 'oshpark' (bare boards) and 'generic' (Gerber X2 + Excellon + KiCad position file + plain BOM with MPN/Manufacturer — for any other fab). Users add their own as JSON in $COPPER_HOME/fabs/ or /.copper/fabs/. profile='list' returns every available profile with its rules and notes (nothing is exported).
It first runs ERC + DRC (zones refilled, schematic parity) and REFUSES (error FAB_BLOCKED, listing blockers with fixes) for whatever
the profile says blocks an order: ERC errors, DRC errors, unrouted nets, parity issues, no board outline, an empty board and — for
profiles that need one per part, like jlcpcb — assembled parts without the profile's part number.
Fix the blockers (each comes with the next tool call); pass waive=[codes] ONLY for things the user consciously accepts:
'erc','drc','unrouted','parity','parts','outline','empty' or 'all'. assembly=false skips BOM + placement (bare PCB order).
With assembly it also asks the parts provider for live stock of every BOM part (for boards boards, default 5): parts with zero /
too little stock or not listed come back in warnings (code 'stock': affected refs + a ready parts_alternatives fix per part). That never blocks;
waive=['stock'] acknowledges it. Offline (or with check_stock=false), stock.not_checked and the first order note say stock was NOT checked.
Every output is checked (non-empty, complete layer set, zip readable). Returns board size, layers, min track/drill, part counts,
summary.assembly_fees (Basic / Preferred / Extended counts, the fee total, extended_refs = which parts cause it) when the
profile has part classes, and order notes.
Examples: fab_export() · fab_export(profile='generic') · fab_export(waive=['parts']) · fab_export(assembly=false)
Inputs: waive, boards, layers, out_dir, +4 more.
focusFocus (what the user points at)AIdempotent
What the user is pointing at. Call it when they say "this part", "here", "that corner" instead of guessing. action: get (default; the latest click / box in the Copper Canvas or selection in KiCad's PCB editor; wait=N waits up to N s for their next one) | resolve (no human: what is inside box=[x0,y0,x1,y1] or nearest near=[x,y] mm on document='schematic' | 'pcb') | open (start the Copper Canvas viewer and return its URL) | clear. Returns focus {document, mode, box_mm | point_mm, refs, pins, nets, age_s}, items with value / footprint / position, and a cropped PNG with the focus outlined. Empty refs with a box or point means the user means that AREA. Use refs / pins in sch_apply, pcb_place, pcb_route; box_mm in render(crop=...). Examples: focus() · focus(wait=60) · focus(action='resolve', document='pcb', box=[100,100,120,115])
Inputs: box, near, side, wait, +8 more.
libraryKiCad librariesAIdempotent
Search and inspect the KiCad symbol and footprint libraries this machine has (global + project tables): find a valid lib_id / footprint before sch_apply place, and read exact pin names. action: search_symbols (query = part number, name or keywords) | search_footprints (query; filters = footprint globs) | symbol_info (lib_id -> pins with number, name, type, unit; default footprint) | footprint_info (fp_id -> pads, courtyard, 3D model) | list (libraries in the active tables) | repair (fix "library not found": rebuilds missing or stale global tables; dry_run defaults to TRUE). Examples: library(action='search_symbols', query='USB C receptacle') · library(action='symbol_info', lib_id='Device:R')
Inputs: action (required), lib, kind, pins, +7 more.
parts_alternativesPart alternativesARead-onlyIdempotent
In-stock substitutes for a part — use when a part is out of stock, in a dear assembly class (JLC Extended:
~$3 setup fee), or too expensive. target: a part number (→ same package, same value / same MPN family; for lcsc Basic > Preferred >
Extended, then stock) or a free-text spec ('100nF 0402'). For ICs the alternatives are the same MPN family from other
makers/packagings — check the datasheet pinout before swapping. Apply with sch_apply set_field (the result's next gives the op).
Example: parts_alternatives(target='C15401')
Inputs: lcsc, limit, target, provider, +1 more.
parts_getPart detailARead-onlyIdempotent
Full detail for one part by its provider part number. The provider is found from the id (a C-number is LCSC;
'name:id' names one) or provider.
lcsc: JLC assembly stock + Basic/Preferred/Extended class + price ladder + attrition (authoritative for JLC PCBA), LCSC retail
stock (a different pool — labelled), parameters, datasheet URL, whether EasyEDA has a symbol/footprint/3D model, and whether
parts_import would use a KiCad stock symbol+footprint or import from EasyEDA.
Other providers: the catalogue record (mpn, manufacturer, value, package, stock, symbol/footprint, extra supplier fields).
Use before committing to an unfamiliar part, or to check stock/class of a part already on the schematic.
Example: parts_get(part='C2040')
Inputs: lcsc, part, easyeda, provider.
parts_importImport partAIdempotent
Make a provider's part usable in this project: returns the lib_id + footprint for sch_apply place. sch_apply
{"op":"place","part":...} calls this by itself; use it directly to inspect a part first or to force a source.
prefer='auto' (default) uses KiCad's stock symbol + footprint when it verifiably fits, else converts the provider's
symbol, footprint and 3D model into project libraries (registered in the project's lib tables); 'easyeda' forces the
provider's drawing, 'stock' fails if there is no stock fit. Footprint pads are checked against symbol pins and
KiCad itself loads the result. preview=true returns pictures of the symbol and footprint.
Example: parts_import(part='C165948')
Inputs: lcsc, part, prefer, preview, +3 more.
parts_searchSearch partsARead-onlyIdempotent
Find parts. The project's parts providers are asked in order and the first with results answers (provider in the
result says which; 'local' = the user's own catalogue file, 'kicad' = generic library parts). Results are ranked by
spec match, then by the provider's part class (parts without a setup fee first), stock and price.
query: a value spec ('10k 0603', '100nF 16V 0402 X7R', 'LED red 0603', '12MHz crystal', 'LDO 3.3V SOT-223'), an MPN
('AMS1117-3.3') or a category phrase ('USB-C 16P', 'Header 1x4 2.54mm').
Each result: provider, id (the provider's part number), mpn, package, stock, price, match ('partial' = not every
term confirmed) and next = the exact sch_apply op. Passives by spec and known part numbers need no search:
sch_apply place resolves and imports them itself.
Example: parts_search(query='USB-C 16P', limit=5)
Inputs: query (required), live, limit, package, +5 more.
parts_source_bomSource BOMAIdempotent
BOM sourcing pass: give every schematic component (all sheets) a part from the project's parts providers. Run it once
the schematic has values and footprints, before the fab pack. Per component it decides from an existing MPN field,
then value + footprint package, then an MPN in the footprint name; existing part numbers are kept (overwrite=true
re-picks) and checked against stock and package. Writes the provider's part-number field plus MPN / Manufacturer
(write=false reports only). Returns summary (sourced %, parts by class, setup-fee and cost estimates), lines
(decided), manual (could not decide: reason + options) and stock_risks.
Example: parts_source_bom(write=false) to preview, then parts_source_bom()
Inputs: live, write, boards, project, +5 more.
pcb_editEdit PCB itemsADestructive
Low-level PCB escape hatch — a batch of ops applied in one transaction (all or nothing), then DRC: {"op":"add_track","points":[[x,y],[x,y],...],"width":0.25,"layer":"F.Cu","net":"GND"} {"op":"add_via","at":[x,y],"net":"GND","size":0.6,"drill":0.3} (or "points":[[x,y],...]) {"op":"delete","refs":["R7"]} | {"uuids":[...]} | {"nets":["SDA"]} (tracks+vias of those nets) | {"all_tracks":true} | {"zone_nets":["GND"]} {"op":"add_text","text":"v1.0","at":[x,y],"layer":"F.SilkS","size":1.0,"rot":0} {"op":"set_field","ref":"U1","field":"LCSC","value":"C12345","visible":false} {"op":"move","ref":"R1","x":110,"y":105,"rot":90,"side":"top"} (locked part: add "unlock":true) {"op":"lock"|"unlock","refs":["J1"]} (or "all":true) Coordinates are mm (board coordinates as in pcb_read; track/via uuids from pcb_read(what=["tracks"])). Deleting a footprint that is in the schematic only lasts until the next pcb_sync — delete the symbol instead. Prefer pcb_place / pcb_route / pcb_pour when they fit.
Inputs: ops (required), render, project, while_open.
pcb_placePlace footprintsA
Place footprints. auto=true: connectivity-driven placement inside the outline (connectors on the edges, decoupling caps at their IC pin, crystal at the MCU, RF antennas on an edge), courtyard-legal on a 0.5 mm grid; several candidates are scored for elegance and the best is written. Locked parts and keep=[..] stay put; refs=[..] places only those around what is there. On a routed board, placing everything is refused unless clear_tracks=true. overhang={"J1": 1.2} lets a side-entry connector stick out past the edge. moves=[{ref, x, y, rot, side, lock}]: exact positions in mm (board coordinates, as pcb_read), applied after auto placement. Returns the ratsnest length before/after and the elegance score. Examples: pcb_place(auto=true) · pcb_place(moves=[{"ref":"J1","x":101,"y":115,"rot":90}])
Inputs: auto, keep, refs, moves, +11 more.
pcb_pourCopper pour / zonesAIdempotent
Copper pour: a zone for one net (default GND) over the whole outline on the chosen layers (default F.Cu + B.Cu), then fill every zone and re-run DRC. Pads the fill cannot reach get a solid connection or a via; what still cannot join is reported with its position. stitch=true adds stitching vias. A pour on an inner layer is a plane. Re-running replaces the net's zone; remove=true deletes it; fill_only=true just refills after moving or routing. Examples: pcb_pour() · pcb_pour(net="GND", stitch=true) · pcb_pour(net="+3V3", layers=["In2.Cu"]) · pcb_pour(fill_only=true)
Inputs: net, layers, remove, render, +11 more.
pcb_readRead PCBARead-onlyIdempotent
Read the PCB. With no arguments: a digest (footprint, track, via and unrouted counts, outline size, layers). what: any of summary | footprints (ref, value, position mm, rotation, side) | nets | pads | tracks (every segment with its uuid; combine with net) | widths (per-net copper summary) | zones | drawings. refs: only these footprints. net: only that net. drc=true also runs KiCad DRC. source='live' reads the board open in the running KiCad editor. Example: pcb_read(what=["footprints"], refs=["U1"]) · pcb_read(what=["nets"], net="GND")
Inputs: drc, net, refs, what, +3 more.
pcb_routeRoute (Freerouting / explicit)ADestructive
Route the board. mode='auto' (default without tracks): autoroute every unrouted connection with Freerouting (Java and the router are downloaded once into $COPPER_HOME/tools on first use). Existing tracks and vias are kept; a result that is worse than before is reverted; the new tracks are then polished (polish=false skips that). Can take minutes on dense boards. 2 layers: pcb_route(ignore_nets=["GND"]) then pcb_pour(net="GND", stitch=true). 4 layers: pour the inner planes first. tracks=[{"from":"U1.3","to":"C3.1","width":0.3,"layer":"F.Cu","waypoints":[[x,y]]}]: explicit connections; refuses to join different nets or to cross other nets' copper. pcb_route_guided is the built-in deterministic router (no download); board_build() picks for you. Examples: pcb_route() · pcb_route(tracks=[{"from":"J1.1","to":"U1.3","width":0.5}])
Inputs: mode, nets, finish, passes, +10 more.
pcb_route_guidedGuided autorouteADestructive
Built-in deterministic router (no download): same plan + same board gives the same copper; KiCad's DRC judges the
result and copper it rejects is removed again. No plan = built-in heuristics.
plan (all optional, mm, net globs ok): order [nets], global {grid, via_cost, style, layers, time_budget_s,
engine: "v2" (default) | "guided"},
nets {"": {priority, width, layers, avoid:[[x0,y0,x1,y1]], corridor:[[x,y],..], max_vias, skip}},
diff_pairs [{p, n, gap, width}], regions [{rect, cost | forbid:true, layers, nets}]. Unknown fields are rejected.
ripup: none (default, keep existing tracks) | nets (re-route nets) | all. dry_run / compare never write.
Returns routed/total, failed [{net, from, to, reason, where, blocked_by}], per-net length and vias, DRC counts,
findings with fixes. A net with a pour only gets the pads the pour misses connected; ground without one is left
for pcb_pour. Routing nothing leaves the board untouched.
Examples: pcb_route_guided() · pcb_route_guided(ripup="all", plan={"order":["/USB_D?","*"]})
Inputs: nets, plan, ripup, detail, +5 more.
pcb_route_planRouting plan analysisARead-onlyIdempotent
Analyse the board for routing (read-only) and return what you need to write a plan for pcb_route_guided: board and
rules, a net table (kind, pads, unrouted, class), pours, keep-outs, a congestion map with hot spots, and
suggested_plan (the built-in heuristics as an editable plan) with plan_schema. Skip it to route with defaults.
heatmap=true attaches the congestion picture. ripup='all' analyses as if all unlocked tracks were removed.
Example: pcb_route_plan() -> edit suggested_plan -> pcb_route_guided(plan=...)
Inputs: nets, ripup, heatmap, project.
pcb_setupBoard outline, holes, rulesAIdempotent
Board setup: outline, corner mounting holes, copper layer count, fab design rules + net classes, silkscreen text size. Only what you pass is changed. Outline, one of: width x height mm rectangle (optional radius; REPLACES the existing outline), polygon, auto_size=true (smallest comfortable rectangle for the parts, unrouted boards only), or outline_file='case.step' (STEP, DXF, SVG, STL; 'auto' = the one file in mechanical/): the board body or an enclosure's cavity with its arcs, cutouts and mounting holes; an uncertain pick lists candidates (outline_pick), outline_dry_run=true only analyses. First setup applies the design rules of the project's fab profile (rules='fab'). power_nets adds nets / patterns to the Power net class. Examples: pcb_setup(width=40, height=30) · pcb_setup(width=50, height=50, radius=2, holes='M3', layers=4) · pcb_setup(outline_file='mechanical/case.step', outline_dry_run=true) · pcb_setup(power_nets=['VBAT','SW'], power_track=0.8)
Inputs: via, holes, rules, width, +26 more.
pcb_syncUpdate PCB from schematicAIdempotent
Update the PCB from the schematic (KiCad's "Update PCB from Schematic"); creates the .kicad_pcb if missing. Adds missing footprints beside the outline, updates fields, swaps changed footprints in place, assigns every pad's net and keeps existing positions. Copper follows renamed nets; copper left from deleted parts is reported. remove_extra=true deletes footprints (and their orphaned copper) that are no longer in the schematic. Refuses if the schematic has unannotated or duplicate references. board_build() runs this and the following steps. Example: pcb_sync()
Inputs: render, project, while_open, remove_extra, +1 more.
project_createCreate projectA
Create a new KiCad project (.kicad_pro, .kicad_sch, .kicad_pcb) and make it active. Refuses to overwrite an existing project. template: '2layer' (default) | '4layer' | 'blank' (KiCad defaults, no fab rules). fab: the fab profile whose design rules the project gets (default: the configured one). board_size: [width_mm, height_mm] draws a rectangular outline. dir: the parent folder (the project goes in dir/), or the project folder itself when it ends in ; default Documents/Copper/. KiCad re-loads the files (ERC + DRC) before success is reported. Example: project_create(name='usb-sensor', board_size=[50,30])
Inputs: name (required), dir, fab, rev, +4 more.
project_openOpen projectAIdempotent
Make an existing KiCad project the active one (all other tools then default to it). path: project folder,
.kicad_pro, .kicad_sch or .kicad_pcb. Returns a short overview + next steps (project_summary has the full digest).
A project argument on any other tool affects only that call; project_open is what changes the active project.
Example: project_open(path='C:/Users/me/Documents/KiCad/robot/robot.kicad_pro')
Inputs: path (required), allow_format_upgrade.
project_summaryProject summaryARead-onlyIdempotent
Compact digest of the active (or given) project: sheets, components by kind, ICs, nets, power rails, % of parts with a
part number (and which are missing one), missing footprints, board size/layers/tracks/vias/zones, the active parts providers + fab
profile (config), last ERC/DRC counts (and whether they are stale), and next steps.
Read-only and cheap; call it when you (re)start work on a design.
Inputs: project.
renderRenderARead-onlyIdempotent
Look at the design: returns PNG image(s) the model can see. Use after edits to check layout, and with crop to zoom on a finding's at.
target: 'schematic' (every sheet, or sheet='name' for one), 'pcb' (2D layers), 'pcb3d' (raytraced 3D).
layers (pcb): default all copper + silkscreen + front mask + outline (no F.Fab: its value texts sit on top of the reference
designators); pass e.g. ['F.Cu','Edge.Cuts'] to choose. view: pcb → top|bottom; pcb3d → top|bottom|iso|iso_bottom|front.
crop: [x0,y0,x1,y1] in mm document coordinates (schematic / pcb top view). width: pixels, ≤ 2400 (default 1400).
Example: render(target='schematic', crop=[90,40,180,110])
Inputs: target (required), crop, view, sheet, +3 more.
sch_applySchematic: apply opsADestructive
Edit the schematic with ONE atomic batch of ops (all succeed or nothing is written). Put a whole sub-circuit, or the
whole design, in a single call. Creates the .kicad_sch if missing. One call edits one sheet.
Pins are 'REF.PIN', PIN = number or name ('U1.PA9', 'J1.VBUS', 'R1.2'); a name on several pins connects them all.
Never compute coordinates: connect by NET NAME and Copper anchors the label or power symbol on the pin. New parts
take a temporary 'id' (one word) used in pins ('led.A'); the result's refs maps id to reference. Parts without
'at' are laid out automatically, and a sheet only Copper has arranged is re-drawn as titled functional blocks
(layout='keep' never does that; nothing is redrawn unless the netlist is proven identical).
ops (objects with "op"):
place: lib_id | lcsc "C25804" | part (+provider) | spec "10k 0402" (resolved by the parts providers); id, ref, value, footprint, fields {LCSC:..}, near (ref/id), group mcu|power|connector|passive, at [x,y], rot, mirror, unit, dnp
connect: pin | pins [..], net (power names like GND, +3V3, VBUS become power symbols; kind:'global' between sheets)
power: pin(s), net · no_connect: pin | pins · pwr_flag: net · wire: from, to | points · label: net + pin | at
set_field: ref, field, value | fields · move: ref, at | by, rot, mirror · swap: ref + lib_id | lcsc | part | footprint
delete: ref | label | wire_at [x,y] | dangling:true · disconnect: pin(s) · rename_net: from, to · text: text, at The result has what changed, the netlist check of every requested connection and KiCad's ERC with a ready
fixper issue, so a separate verify call is not needed. Example: ops=[{"op":"place","lib_id":"Regulator_Linear:AMS1117-3.3","id":"ldo"},{"op":"place","spec":"10uF 0805","id":"cin"}, {"op":"connect","pins":["ldo.VI","cin.1"],"net":"VBUS"},{"op":"connect","pins":["ldo.GND","cin.2"],"net":"GND"}]
Inputs: ops (required), sheet, layout, verify, +4 more.
sch_readSchematic: readARead-onlyIdempotent
Read the schematic compactly: before editing an existing design, and to find exact pin names.
query: summary (default, counts) | components (ref, value, lib_id, footprint, LCSC, position) | pins (every pin of ref
with number, name, type and its net) | nets (net -> ['REF.PIN', ...], KiCad's full net names) | labels |
unconnected (pins ERC will flag, each with a ready fix). filter = case-insensitive substring.
Example: sch_read(query='pins', ref='U1') · sch_read(query='nets', filter='USB')
Inputs: net, ref, limit, query, +3 more.
sch_tidySchematic: tidy layoutADestructive
Re-draw a schematic sheet so it reads like a hand-drawn professional sheet WITHOUT changing the circuit: titled
functional blocks in signal-flow columns, canonical drawings per idiom (LDO, op-amp loop, crystal, LED chain), support
parts wired at the pin they serve, supplies up and grounds down, design notes, smallest paper that fits. Nothing is
written unless KiCad's netlist of the WHOLE project is identical before and after and ERC reports nothing new. A sheet
wired by hand is left alone (style_used: 'kept') unless force=true; sheets with sheet symbols, buses or several
instances are refused. style 'pro2' (default); when the checks refuse it a simpler style is drawn: style_used says
which, fallback says why.
Example: sch_tidy() · sch_tidy(sheet='power.kicad_sch', dry_run=true) · sch_tidy(blocks=[{"id":"U2","title":"MCU"}])
Inputs: force, paper, route, sheet, +9 more.
verifyVerify (ERC/DRC/review)ARead-onlyIdempotent
Run KiCad's own checks and get actionable findings. Use after EVERY batch of edits (sch_apply, pcb_*), and before fab_export.
what: list of 'erc' (schematic electrical rules), 'drc' (board rules + unrouted nets + schematic↔board parity; zones are refilled in memory,
the file is not modified) and 'review' (engineering heuristics, see design_review). Default: ['erc'] plus 'drc' when a board exists.
Each finding has severity, type, message, refs (pins like 'U1.3' / footprints), at [x,y] mm (on sheet for sub-sheets) and fix = the exact
next tool call, already pointed at the right sub-sheet. Repeats of one problem are merged into one entry with count + all refs.
next is the single most useful call to make now; new / fixed compare with the previous run. Checks run on the SAVED files.
Example: verify(what=['erc','drc'])
Inputs: what, limit, parity, refill, +1 more.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 31 tools
Most tools target clearly distinct phases (project, schematic, PCB, parts, export), and descriptions explicitly steer between abstraction levels such as board_build vs individual pcb_* steps or pcb_edit vs pcb_place. A few boundaries still blur: design_review overlaps verify(what='review'), and multiple routing entry points require judgment.
Names are consistently snake_case with domain prefixes (sch_, pcb_, parts_, project_, copper_, fab_) and mostly action suffixes. Minor deviations are single-word tools (checkpoint, library, render, verify, focus, export) and the noun_noun parts_alternatives.
31 tools is heavy for a single MCP server and exceeds the typical 15-tool comfort zone, increasing context and selection overhead. The domain is broad and some tools are justified, but board_build already bundles several pcb_* workflows, so consolidation is possible.
The surface covers the full KiCad lifecycle: project setup, schematic read/edit, library and part sourcing, PCB sync/place/route/pour/edit, ERC/DRC/review, checkpoints, rendering, and fab/export. No obvious operational gaps appear for PCB design automation.
Maintenance
Related MCP Connectors
Design, route, check, review and export manufacturable PCBs from plain language; KiCad import.
EasyGerber brings AI printed circuit board (PCB) design, layout, and routing to MCP-compatible assistants. Describe a circuit or start from firmware pin assignments, search published electronic components, and build schematics using catalog parts with their footprints and available 3D models. Create and revise boards, generate layouts with automatic component placement and routing, inspect previews, and check saved layouts for blocking design issues. Export manufacturing ZIPs containing Gerber and drill files, a bill of materials, and component placement data, or download an editable EasyGerber (.egb) file. Start without signing up. Your agent uses one private board reference to create and continue a board, including catalog access, edits, layout, checks, previews, and exports, without a separate guest setup step or token to manage. To keep the board in your account or work with permitted saved personal or organization boards, complete EasyGerber sign-in and OAuth consent, then resume the same task. Account permissions, plan limits, and generation billing apply; support depends on your MCP client and installed integration.
Turn datasheets into source-backed JSON contracts, pinout matrices, and KiCad CAD for AI agents.
Design circuits, simulate and verify embedded firmware, and lay out PCBs with AI agents.
Related MCP Servers
- AlicenseAqualityDmaintenanceEnables AI assistants to read and modify KiCAD PCB designs through the KiCAD IPC API, providing tools for board queries, footprint placement, track creation, DRC, and export.14MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to interact with KiCAD for PCB design automation. Users can design PCBs using natural language, including component placement, routing, checks, and export.61 npmMIT
- AlicenseBqualityCmaintenanceEnables AI assistants to interact with KiCAD for PCB design automation, including schematic editing, component placement, routing, DRC/ERC, and export.10038 npm2MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI assistants to design and edit PCBs through natural language, including project setup, schematic editing, component placement, custom symbol and footprint generation, routing, DRC/ERC checks, and production file export. It also integrates JLCPCB parts catalog data, Freerouting automation, and visual snapshots for cross-platform Windows, Linux, and macOS workflows.61 npmMIT