
easyeda-mcp
io.github.zzvllvzz/easyeda-mcp
Read and draw EasyEDA Pro schematics and PCBs through a bridge extension, with guarded edits.
Documentation
easyeda-mcp
An MCP server that lets Claude Code (or any MCP client) read and draw schematics and PCBs in EasyEDA Pro.
A tiny extension inside the editor does one thing: it runs the JavaScript the server sends, with access to the eda API, and returns the result. All tool logic lives in the server, so fixes and new tools never require reinstalling the extension.
Edits are guarded: sch_draw and pcb_draw apply a whole batch of operations or nothing, and take the change back by themselves when it shorts two named nets on the schematic or adds a design rule error on the board.
Requirements
- EasyEDA Pro desktop client 3.x (tested on 3.2.209 for Windows).
- Node.js 20 or newer on
PATH. - Claude Code, or another MCP client that runs stdio servers.
Install
1. The bridge extension in EasyEDA Pro
- Download
easyeda-mcp-bridge.eextfrom the latest release. - In EasyEDA Pro open the extension manager and import the file.
- Allow the extension External Interaction. It needs it to reach the local server.
- Restart EasyEDA. The extension starts only when the editor starts.
The extension connects to ws://127.0.0.1:49731 by itself and reconnects when the link drops. The editor gets an MCP menu with Reconnect and Status.
2. The server in Claude Code
As a plugin, in a Claude Code session:
/plugin install easyeda --marketplace zzvllvzz/easyeda-mcp
On Claude Code older than 2.1.275, add the marketplace first:
/plugin marketplace add zzvllvzz/easyeda-mcp
/plugin install easyeda@easyeda-mcp
Then run /reload-plugins or start a new session.
Or from npm, without the plugin:
# macOS, Linux
claude mcp add easyeda -s user -- npx -y easyeda-pro-mcp
# Windows
claude mcp add easyeda -s user -- cmd /c npx -y easyeda-pro-mcp
Or from source:
git clone https://github.com/zzvllvzz/easyeda-mcp
cd easyeda-mcp
npm install
claude mcp add easyeda -s user -- node /absolute/path/to/easyeda-mcp/server/index.mjs
Other MCP clients: run npx -y easyeda-pro-mcp as a stdio server.
3. Check
With EasyEDA open, ask Claude to check the EasyEDA connection. eda_status should answer connected with the editor and extension versions and the active project.
Tools
eda_status: is the editor connected, versions, active project and sheet, state of the bridge.eda_exec: run JS inside EasyEDA (eda, helpersh,args,console,store).eda_call: call one API method by its path.eda_api: search the API reference.sch_read: read a sheet: summary, parts with pins, wires, nets, check (check), overlaps (overlaps), free room (free).sch_draw: a batch of operations on the sheet as one guarded change (see below).sch_export: PDF, PNG, SVG, netlist, BOM to a file.lib_search: find parts in the library by words or LCSC numbers.pcb_read: the board: info, parts with pads, tracks, vias, pours and regions, nets, unrouted connections, DRC.pcb_draw: a batch of operations on the board as one change guarded by DRC.pcb_do: open a board, import changes from the schematic, refill pours, autoroute, remove routing.pcb_export: Gerber, pick and place, BOM, STEP/OBJ, DXF, DSN, IPC-356, IPC-2581, ODB++, PDF and more.
The helpers h live in server/helpers.js and are read again on every call, so the file can be edited while the server runs.
Guard, trial run and rollback
sch_draw and pcb_draw apply the list of operations as a whole or not at all.
On the schematic a netlist is taken before and after the change. If nets with different names given by a person merged into one, that is a short: the change is taken back and the report names the nets and the pins. A change in which an operation failed, or an expect ({NET: [pins]}) did not hold, is taken back the same way. After a rollback the netlist is compared with the original and the report says restored: true. allowShorts permits an intended merge. The report always shows what happened to the nets: what got connected, what dropped off, what split, what was renamed.
On the board DRC runs before and after the change. A new error other than a connection that is not routed yet (clearance, short, entering a keep-out) takes the change back. Pours are refilled before the check. allowErrors keeps a change with errors.
trial: true performs the change in the editor, shows the report and takes it back in any case. A rollback restores moved parts, properties, the no-connect mark, wire names and shapes, deleted wires, tracks and vias. Deleted parts, texts and shapes cannot be restored, so a trial run that deletes parts is refused up front.
The guard forbids nothing in advance by geometry: EasyEDA itself decides, and the netlist or DRC judges the result. It gives no false refusals.
Security
The extension runs whatever code the local server sends, with full access to the editor API and your EasyEDA account. Keep that in mind:
- The server listens on
127.0.0.1only. Browsers can open WebSockets to localhost from any site, so the server refuses connections that carry a browser Origin other than EasyEDA's own (https://*.easyeda.com,https://*.lceda.cn). More origins can be allowed withEASYEDA_MCP_ORIGINS, comma separated. Local programs (other sessions of this server,scripts/run.mjs) send no Origin and are accepted, as with any local developer tool. eda_execcan call any editor function, including the ordering ones (placePcbOrder,placeComponentsOrderand similar). The tool description tells the model never to call them.- EasyEDA saves changes to the cloud by itself a few seconds after an edit, and the API has no undo. Try risky edits with
trial: trueor on a scratch sheet or project.
How it works
extension/dist/index.js: the extension, written by hand without a bundler.server/link.mjs: the link to the editor. The first server started owns the port; servers of other Claude sessions go through it. If the first one exits, the next one takes the port.server/index.mjs: MCP over stdio and the tools. Large answers are saved to~/.easyeda-mcp/out/, the reply carries the beginning and the path.server/api-index.mjs: parses the API typings for search.
Environment variables: EASYEDA_MCP_PORT (the port in the extension has to change too), EASYEDA_MCP_OUT, EASYEDA_MCP_ORIGINS.
Development
npm testruns real server processes and the real extension code against a fakeeda(test/fake-eda.mjs). It does not check the behaviour of a live EasyEDA.npm run build:extpacksextension/intoeasyeda-mcp-bridge.eext(needs Node 20.15 or 22.2 and newer).node scripts/run.mjs draw <ops.json> [--trial] [--no-guard]andnode scripts/run.mjs exec <code.js> [args.json]runsch_drawoperations or code from a file through the hub of a running server. Useful for generators with hundreds of operations.
Updating the extension without the import dialog: if EasyEDA runs with a debugging port (easyeda-pro.exe --remote-debugging-port=9333 --remote-allow-origins=*), a new build can be put into its extension storage directly: npm run build:ext, then node scripts/push-ext.mjs, then restart EasyEDA. The very first install still goes through the import dialog.
Tested on a live EasyEDA Pro 3.2.209
Schematic: reading, every sch_draw operation, short protection, trial run and rollback (six scenarios, the sheet came back identical), check, overlaps, free room search, export pdf/png/svg/netlist/bom/view. Load: 260 operations in one call (120 parts, 130 wires, 10 ground symbols) with a check of 130 nets took 100 seconds with the window hidden.
Board (in a scratch project): import from the schematic, moving parts, tracks, vias, a pour with fill, a keep-out region, text, outline, DRC, protection against shorted tracks and entering a keep-out, autorouting, export gerber/pnp/bom/step/dxf/dsn/ipc356/odb/altium/pdf/netlist.
Link: works with the window minimized, recovers after a dropped socket and after the computer sleeps.
Not tested: multilayer boards and blind vias, net classes and differential pairs (available through the raw API), boards and sheets with hundreds of parts, the web editor, macOS and Linux.
Known limitations
- A modal dialog in the editor blocks the API call that opened it, and the bridge does not see it: the call waits until its timeout. Example: "this device has been updated, update in the project?" when placing a part whose symbol changed after its first use in the project. Press the button in the editor, or find the dialog in
top.documentfromeda_execand click it there. - No tools for creating sheets, changing the sheet format or editing library symbols. The raw API is available through
eda_exec. sch_drawtakes its operations inline only; for long lists usescripts/run.mjs.trialand thepartop do not return pin coordinates, and thesetop cannot mark a part as not placed (DNP).lib_searchcuts descriptions at about 120 characters.
Editor quirks the helpers work around
- The list of wires on a sheet (
getAll,getAllPrimitiveId) lags about a second behind wire creation,get(ids)sees them at once.h.drawwaits for the update; after the raw API callh.settle(ids). sch_PrimitiveComponent.createstores rotation 90 as 270 and the other way round;modifyis correct.sch_PrimitivePin.modifywithoutyflips the sign of the pin's y and the pin flies off the part. Pass the currenty.- Right after a netlist is generated the editor rejects edits:
modifythrowscmdKey, a wire create throwscreate failed!,deletesilently returnsfalse. A retry a moment later succeeds. - Connectivity lags about a second behind a wire deletion: a netlist taken at once still shows the old nets.
- A new wire merges with every wire whose end it touches;
createreturns the old wire's id. - A power symbol or a port cannot be modified, only deleted and created again. Rotation 90 is stored as 270 on creation for them too. A symbol right on a pin end hangs on a zero-length wire that cannot be created by hand: after moving the part away and back the symbol is attached anew.
- Every operation on a sheet gets slower as the sheet fills up; creating a part takes 0.5 to 0.7 s, so parts are placed in batches of eight.
sch_Drc.checkreturns only the number of findings per severity; the list exists only in the editor panel.- Board:
pcb_Primitive.getPrimitiveTypeByPrimitiveIdalways answersundefined; a pour is refilled with the object'srebuildCopperRegion();importChanges()only opens a confirmation dialog,h.pcb.importpresses its button;getPdfFilewithout content settings never answers;dmt_Project.deleteProjectreturnsfalseand does not delete the project. - Generating a netlist numbers the "R?" parts across the whole project. The API has no separate call for annotation.
getPdfFiledoes not exist in the editor,getPngFileandgetSvgFilenever resolve.getExportDocumentFiledoes all of it.- The extension script may run twice in a page, so there is one runtime per page (
globalThis.__easyedaMcpBridge__,info()shows its state). - In a minimized or hidden window page timers fire once a second, and after the fifth in a chain once a minute (measured: twelve pauses of 0.1 s took 3.7 minutes). So the connection watchdog and the helpers' pauses (
h.sleep,h.limit,h.settle) run on a timer in a worker: thirty such pauses take 3.3 s. The editor's own timers suffered the same way (netlist 53 s instead of 2 s, creating a part 24 s), so while the window is hidden the helpers move the page'ssetTimeoutandsetIntervalonto the same worker. With a visible window the timers are native. Turn it off withh.pageTimers(false).
License
MIT.
easyeda-pro-mcpnpm install easyeda-pro-mcp