deepseek-harness
deepseek-ai
DeepSeek Harness: Everything is a Plugin.
PROJECT TOPICS
PROJECT README
DeepSeek Harness (DSH) plugin that connects DSH to 嘉立创EDA专业版 / EasyEDA Pro and lets the agent draw schematics through MCP tools.
中文文档:README.zh.md · Tool reference: docs/tools.md · Changes: CHANGELOG.md
DSH agent
└─ mcp__jlceda__eda_* tools
└─ @deepseek-ai/dsh-mcp-client (stdio)
└─ lib/bridge.mjs (local MCP + WebSocket server, 127.0.0.1:39009)
└─ JLCEDA Pro extension dsh-eda-bridge-extension.zip
└─ official EasyEDA Pro extension API (eda.sch_*)
The DSH plugin starts a zero-dependency bridge child process. The bridge speaks MCP over stdio to DSH and WebSocket to a small JLCEDA Pro extension. The extension executes a strict allow-list of official EDA APIs, so the model cannot run arbitrary code inside JLCEDA.
Runtime requirement: DSH
0.1.1-rc.x,0.1.5-rc.xor0.2.0-rc.x(Web GUI and the official Desktop). The host settings seam and the browser bundle are adapted to every generation, so one build loads on any of them.
# directly from GitHub (pnpm runs the package's `prepare` build)
dsh plugin --profile web add "github:MCviseron/dsh-eda-mcp"
# or from a local clone, so every `pnpm build` is picked up by a profile restart
git clone https://github.com/MCviseron/dsh-eda-mcp.git
cd dsh-eda-mcp && pnpm install && dsh plugin --profile web add "link:$PWD"
dsh plugin forwards to pnpm and reconciles dsh.profile.bundles automatically. Restart the running DSH Web profile after installation.
The Desktop app hosts plugins in Electron, so there process.execPath is DeepSeek Harness.exe, not Node: spawning it with lib/bridge.mjs starts (or single-instance-aborts) a second app instead of a bridge, and port 39009 never listens — the settings card exists, /test always fails and the agent gets no mcp__jlceda__* tools.
The plugin now resolves a real Node executable (src/node-runtime.ts), in order: DSH_EDA_MCP_NODE override → DSH_NODE_EXECUTABLE / DSH_DESKTOP_NODE_EXECUTABLE (with ELECTRON_RUN_AS_NODE=1) → process.execPath on a Node host → the Desktop payload's own resources/runtime/primary-runtime/dependencies/node/bin/node.exe → node on PATH → Electron-as-Node.
POST /api/dsh-eda-mcp/test reports which one it picked:
{"ok":true,"health":{"status":"ok","version":"0.3.5","clients":1},
"launch":{"command":"…\\runtime\\primary-runtime\\dependencies\\node\\bin\\node.exe","source":"desktop runtime Node"}}
The Desktop loads the packaged
lib/index.js, and a plugin reload does not re-import a cached ESM module — after changingsrc/, runnode build.mjsand restart the Desktop app.
Build produces dsh-eda-bridge-extension.zip. In JLCEDA Pro:
dsh-eda-bridge-extension.zip.The extension connects to ws://127.0.0.1:39009/ws. Keep JLCEDA Pro running and a schematic page open.
In the DSH Web GUI settings page, the 嘉立创EDA MCP card has a 测试连接 button. It checks the local bridge health endpoint. The MCP tools appear as mcp__jlceda__eda_status, mcp__jlceda__eda_place_component, mcp__jlceda__eda_draw_wire, etc.
| Tool | Purpose |
|---|---|
eda_status |
Bridge status and connected JLCEDA clients |
eda_search_components |
Search JLCEDA library devices |
eda_place_component |
Place a component/symbol |
eda_place_net_flag |
Place VCC/GND/Power net flag |
eda_place_net_port |
Place IN/OUT/BI net port |
eda_draw_wire |
Draw a wire/polyline |
eda_draw_rectangle |
Draw a rectangle |
eda_draw_circle |
Draw a circle |
eda_draw_text |
Draw text |
eda_save_document |
Save the active schematic |
eda_zoom_to_fit / eda_zoom_to_region |
Zoom canvas |
eda_get_components / eda_get_wires |
Inspect primitives |
eda_delete_primitive |
Delete one primitive |
eda_api_call |
Allow-listed generic API call (can be disabled in settings) |
pcb_* / eda_pcb_* (65 tools total) |
PCB query, place/move/delete components, tracks, vias, regions, board outline, auto-place/auto-route, Gerber export |
Schematic/symbol coordinates are in 0.01 inch units; PCB coordinates are in mil. Rotation values are 0/90/180/270. Wire points are a flat array [x1, y1, x2, y2, ...].
Every PCB tool has an equivalent eda_pcb_* alias (eda_pcb_get_components = pcb_get_components). See README.zh.md for the full PCB table and the region-layer rules (pcb_PrimitiveRegion.create accepts copper layers and MULTI only, so the board outline stays a closed line loop on layer 11).
docs/tools.md is generated from the built bridge's MCP tools/list (81 tools) and is the authoritative list of names, parameters and required fields.
eda_get_page_info for the A4 frame, title-block keep-out and safe areas; then eda_search_components + eda_place_component (out-of-frame placement is rejected and rolled back).eda_draw_wire net parameter (same-name nets merge) - the most reliable electrical connection. eda_place_net_flag_at_pin places power/ground flags. eda_place_net_label_at_pin prefers a REAL net label and reports method: "netLabel"; when it reports method: "text" the EDA build has no createNetLabel and the text label does not create an electrical connection - fall back to the wire net parameter.eda_set_no_connect for unused pins, eda_draw_functional_box to group, then eda_run_drc + eda_save_document.eda_create_board links schematic and PCB (first time only).pcb_import_changes is asynchronous by default: pcb_Document.importChanges opens EDA's confirmation dialog and blocks until it is answered, so the tool returns immediately with componentsBefore and keeps the import running in the background.eda_pcb_wait_for_components: it polls every 5 s by default (minimum 3 s, deliberately low) for up to 45 s (pollIntervalMs / maxWaitMs). Confirmation is detected as "new PCB components appeared that did not exist before".confirmed: true run pcb_save_document; on confirmed: false ask the user and call again.pcb_draw_board_outline (one closed pcb_PrimitivePolyline on layer 11).eda_pcb_get_components (includePins: true for accurate pad nets) + eda_pcb_move_component; eda_pcb_auto_place (blocking by default, wait: false for a background job).eda_pcb_auto_route starts asynchronously (EDA shows its own progress bar); poll eda_pcb_job_status until running=false. Never await it and never raise timeouts - a whole board or a 35+ pin net such as GND always exceeds any sane timeout while EDA keeps working. Use eda_pcb_clear_routing to start over.eda_pcb_run_drc (strict includes warnings, includeVerboseError returns details) + eda_pcb_get_drc_rules.eda_pcb_set_net_track_width for power/GND, eda_pcb_create_pour for copper pours (45grid/90grid/solid, copper layers only), eda_pcb_export_gerber (base64 data URL, can be several MB).sch_Net.*, netlist export and the schematic get/getAll APIs only act on the active tab: with a PCB in front they return [] / null. eda_get_nets therefore degrades through getCurrentProjectAllNets -> getAllNets -> parsing sch_Netlist.getNetlist and reports source; when it is empty use eda_get_active_document and eda_open_document to bring the schematic page forward.
The Web GUI settings card exposes:
enabled — mount/unmount the MCP bridge.announceToAgent — inject plugin guidance into the system prompt.toolCallTimeoutMs — per-call EDA timeout.allowRawApi — expose the generic eda_api_call tool.The WebSocket port is fixed at 39009 in the first version. Do not run another service on that port.
Requirements: Node ^22.19.0 || >=24, pnpm (pinned by packageManager), and Windows for the extension zip (PowerShell Compress-Archive).
pnpm install
pnpm typecheck # tsc --noEmit
pnpm test # unit tests
pnpm build # bundles + extension zip
pnpm check # all three
Build outputs:
lib/index.js — DSH host plugin.lib/client.js — DSH Web GUI settings card.lib/bridge.mjs — standalone MCP/WebSocket bridge child.dsh-eda-bridge-extension.zip — JLCEDA Pro extension.lib/ and the zip are build outputs and are git-ignored; the host loads the packaged lib/index.js, so a change under src/ needs pnpm build plus a Host restart (a plugin reload does not re-import a cached ESM module).
See CONTRIBUTING.md for the repository layout, the release/tag flow, and the bridge/extension version rule.
127.0.0.1).eda_api_call is allow-list-only and can be disabled.pcb_PrimitivePolyline on layer 11 (polygon source + line width). It cannot be created with pcb_PrimitiveLine (a copper-track primitive; the core rejects layer 11) nor with pcb_PrimitiveRegion (TPCB_LayersOfRegion allows copper layers and MULTI(12) only). Verified against real .eprj2 project files, where an outline is stored as ["POLY", id, 0, "", 11, 10, [...], 1].pcb_Document.autoRouting returns success=false, duration=0 for every net when no net list is passed (empty routingRange in this EDA build), so eda_pcb_auto_route enumerates all net names first.eda_pcb_auto_route returns as soon as EDA starts routing (EDA shows its own progress bar) and eda_pcb_job_status is polled until running=false. Awaiting a whole-board or many-pin net (e.g. GND) always exceeds any sane timeout while EDA keeps working.sch_Net.*, netlist export) only act on the ACTIVE document; when they return empty/null, use eda_get_active_document and eda_open_document to bring the schematic page to the front.eda_pcb_export_gerber returns the Gerber zip as a base64 data URL, which can be several MB for a large board.sys_WebSocket, which has neither a close callback nor auto-reconnect; versions before 0.3.3 therefore had to be reconnected by hand after the DSH bridge child restarted. 0.3.3 adds a 10 s heartbeat that re-registers the socket when pong stops arriving.jlc-extension/api-bridge.js, then rebuilding/reimporting the extension zip.| Path | What it is |
|---|---|
src/index.ts, src/routes.ts, src/node-runtime.ts, src/config-values.ts, src/bridge-diagnostics.ts, src/guidance.ts |
DSH host half |
src/bridge/index.ts |
Standalone MCP/WebSocket bridge child |
src/client/ |
Web settings card |
jlc-extension/ |
JLCEDA Pro extension packaged into the zip |
test/ |
Unit tests |
docs/tools.md |
Generated tool reference (every MCP tool, its parameters, and required fields) |
build.mjs |
esbuild bundles + extension zip |
Apache-2.0 © dsh-eda-mcp contributors. See LICENSE.
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: 无有效分类标签。