Skip to main content
Glama

MultisimForge

Generate editable NI Multisim 14 circuits from plain text, verify connectivity offline, pull numbers out of Multisim's own simulation engine, and capture real instrument panels.

CLI + MCP server + agent skill in one package.

spec.json ──► MultisimForge build ──► .ms14 (editable) ──► MultisimForge check    offline connectivity check
                                      │
                                      ├──► MultisimForge preview   real schematic PNG from Multisim
                                      ├──► MultisimForge sim       real OP / AC / TRAN data
                                      └──► MultisimForge capture   real scope / bode panel screenshots

Why

Multisim exposes no public "place a part, draw a wire" API — only a COM automation interface that has to run inside a 32-bit process. Doing a batch of circuits, or producing reproducible simulation data, means clicking through the GUI by hand.

MultisimForge treats a .ms14 file as an XML container: it implements the container codec itself, reconstructs the pin-to-net relationships from the drawing geometry itself, and routes wires itself. So you can generate and validate a circuit without Multisim running at all. Multisim is only started when real-machine behaviour is needed (schematic image, simulation numbers, instrument screenshots) — and a background worker keeps one instance alive so repeated calls reuse it.

Related MCP server: root-ext-cad

Features

  • Generate circuits: SPICE-style netlist plus part coordinates/angles → .ms14. Automatic routing (obstacle-aware orthogonal A*, tree connection), multiple ground symbols, instrument panel presets, interactive simulation stop time.

  • Explicit wiring: parts accept mirror-x / mirror-y; wires lets you pin the exact polyline of any net (junctions are created automatically), and colors / wire_width control wire colour and thickness.

  • Offline self-check: reconstructs pin groups from wire and junction geometry and compares them against the electrical nets; also reports overlapping parts, wires crossing parts, crossings between different nets, and parts outside the sheet. No Multisim involved, so it cannot crash.

  • Any part: part templates are harvested whole from a .ms14 (electrical part + ports + model + symbol + panel state). Simulation uses the part's own model.

  • Real simulation data: injects voltage probes on the nets you ask for, then drives DC operating point, AC sweep and transient analysis through COM — resonance peak, −3 dB frequency, phase, peak-to-peak, period. Arbitrary SPICE text can also be handed to Multisim's command-line engine.

  • Real screenshots: opens Multisim, runs the simulation, waits for the waveform to settle, then grabs the circuit window, each instrument panel and the full screen. If the scope trace does not fill the screen, the simulation time is recalibrated and the run repeats.

  • Reused COM instance: preview / sim / parts fetch share one hidden Multisim inside a background 32-bit worker — roughly 0.3 s for the second call, with no repeated launch/kill cycle. multisimforge com status / com stop inspect and release it.

  • Read existing designs: inspect reports parts, nets and instrument settings.

  • .ms14 codec in pure Python: decoded XML matches the vendor decoder, and the XML layer round-trips byte for byte.

Requirements

  • Windows 10/11

  • NI Multisim 14.x (licensed)

  • Python 3.10+

  • pywin32, Pillow, numpy, scipy for screenshots

  • a 32-bit Python with pywin32 — Multisim's automation interface is an in-process 32-bit component

  • optional: Node.js + electronics-workbench-decoder (only parts dbindex needs it)

Local paths are detected at runtime (registry + install directories). Override them with a config.json in the repo root or with MULTISIMFORGE_<KEY> environment variables.

Install

git clone <this repo>
cd MultisimForge
python -m pip install -e .[capture]

MultisimForge parts init     # build the part library from the local Multisim samples (~30 s)

parts init harvests part templates from the samples shipped with your Multisim install and writes them to %LOCALAPPDATA%\multisimforge\parts. That directory is machine-local and is not distributed.

Quick start

examples/rc_lowpass.json:

{
  "netlist": "V1 vin 0 DC 0 AC 1 SIN(0 1 1k)\nR1 vin vout 1k\nC1 vout 0 0.1u\nXSC1 vin vout 0 nc1 0 nc2 OSCILLOSCOPE\n",
  "output": "out/rc.ms14",
  "layout": {"V1": [108, 216], "R1": [252, 180], "C1": [396, 252, 90], "XSC1": [540, 126],
             "GND": [[108, 306], [396, 342], [612, 198]]},
  "instruments": {"XSC1": {"timebase": "500us", "a_scale": "1V", "b_scale": "1V", "trigger": "none"}},
  "sim_time": "5ms"
}
MultisimForge build examples/rc_lowpass.json --preview out/rc.png   # generate + self-check + preview
MultisimForge sim out/rc.ms14 --ac 10,100k --out vout --in vin      # cutoff frequency, phase
MultisimForge capture out/rc.ms14 shots                             # real screenshots (do not touch mouse/keyboard)

capture works on a copy under work/capture/<run_id>/ and opens its own window, so the input .ms14 is byte-identical before and after. A window title carries only the file stem, so close any other window showing the same file name first: capture refuses to guess which file such a window holds.

Every command prints one JSON envelope with a status and the matching exit_code:

{"problems": [], "warnings": [], "crossings": 0, "nets": {"vin": ["R1.1", "V1.1", "XSC1.1"]},
 "status": "PASS", "exit_code": 0}

status

exit code

meaning

PASS

0

every mandatory check passed

WARN

0

usable, with a declared caveat (layout advice, degraded routing you allowed)

FAIL

2

the design is wrong: problems says what

ERROR

1

the tool or the environment failed

CANCELLED

130

interrupted

A non-empty problems means the drawing disagrees with the netlist and must be fixed; warnings are layout advice (too many crossings, detours).

Routing

The router looks for a clean path before it reports a problem. It retries the pin escape at growing clearances, falls back to a denser A* grid, and routes the design up to three times with the failing nets moved first (rip-up and retry).

If a net still has no obstacle-free path, build tries to repair the layout: it moves one part or one ground symbol by half a grid step (up to 48 tries, 3 s) and keeps the cleanest result. The move is reported, so the run is WARN:

{"status": "WARN", "moved_parts": {"GND[1]": [0, 24]},
 "warnings": ["layout auto-repaired: moved GND[1] by (+0,+24) so the router could pass"]}

If no arrangement routes cleanly, build fails with RouteError and writes nothing — it will not quietly draw a wire through a component. Two escape hatches:

MultisimForge build design.json --no-auto-repair      # fail on the spec exactly as written
MultisimForge build design.json --allow-fallback      # status WARN, degraded: true

Explicit wiring

The third element of a layout entry may be "mirror-x" / "mirror-y"; mirroring reverses pin order while labels stay horizontal:

"layout": {"XFG3": [45, 90, "mirror-x"], "XSC3": [183, 108], "GND": [[147, 171]]},
"wires": {
  "out": [[[63, 90], [63, 144], [135, 144], [135, 126]]],
  "0": [[[27, 90], [27, 171], [144, 171]], [[144, 126], [144, 171]]]
},
"colors": {"out": "red", "0": "red"},
"wire_width": 2

Every segment must be horizontal or vertical, and polyline endpoints must land on a pin centre or coincide with another polyline (a junction is created at shared points). A net with wires follows those polylines exactly; other nets keep using the router. See examples/explicit_wiring.json.

Commands

Command

Purpose

parts list [keyword]

search the part library (name, family, pin order)

parts show <model>

pin order, hidden power pins, pin offsets and directions at 0°

parts fetch <model>

pull a model out of the Multisim database when it is not in the library

parts harvest <file-or-dir>

harvest parts from existing .ms14 files

parts init

rebuild the whole part library

build spec.json [--preview x.png]

generate + self-check (optionally export a preview)

preview x.ms14 x.png

export the schematic through Multisim

check x.ms14

offline self-check

inspect x.ms14

report parts, nets, instrument settings

sim x.ms14 --nets a,b --op / --ac ... / --tran ...

real simulation data

spice x.cir --cmd "tran 1u 10m"

hand SPICE text to Multisim's engine

capture x.ms14 outdir

real screenshots: circuit, each instrument panel, full screen (needs no other window open for that file name)

set-sim-time x.ms14 20ms

change the interactive simulation stop time

com status / stop

inspect or release the background COM worker

decode / encode

.ms14 ↔ XML (debugging)

Flags

Command

Flag

Meaning

build

--preview <png>

export a preview image after building

--allow-fallback

accept degraded wiring: status WARN, degraded: true

--no-auto-repair

fail on the spec exactly as written; do not move parts

check

—

reads a .ms14 or a decoded .xml; no flags

sim

--nets a,b

nets to probe (required for meaningful data)

--op / --ac start,stop,points / --tran step,stop

analyses to run (any combination)

--out / --in

AC output node / AC input source

--at t1,t2,...

time points to sample from a transient run

--csv <dir>

also write each analysis to CSV

spice

--cmd "tran 1u 10m"

SPICE command handed to Multisim's engine

capture

--wait <s>

how long the display must be still to call it finished (default 1.5)

--timeout <s>

maximum wait (default 90)

--keep-open

leave the window open after capture

--on-netlist-error continue

continue past the netlist-error dialog (default: abort)

any

--debug

show the traceback instead of a JSON envelope on an unexpected error

Durations must be greater than 0 and at most 3600 seconds.

MCP server

mcp_adapter/server.py is a stdio MCP server exposing the CLI as tools (check_design, inspect_design, build_schematic, capture_instruments, simulate, preview_design, set_sim_time, convert_design, parts, run_cli).

It is deliberately a thin, process-isolated shell: every tool shells out to python -m multisimforge <cmd> and returns the JSON the CLI prints. No Multisim COM object ever lives in the server process, so a COM crash or a failed screenshot run cannot take the server down.

python -m pip install -e .[mcp]
python mcp_adapter/server.py          # stdio; let your MCP client launch it

mcp_adapter/harness.py is an offline debug client: hand it a JSON call list, it launches the server, runs the calls and writes the results to JSON.

Layout

MultisimForge/
  codec.py        .ms14 container codec (PKWare DCL implode/explode, pure Python)
  xmlio.py        XML read/write (attribute newlines preserved, &ASC encoding, ID remapping)
  parts.py        part template library: harvest, index, lookup
  structural.py   extract structural templates from a blank design (shell, wire, junction, probe, sim state)
  netlist.py      netlist parser
  builder.py      spec → .ms14 (placement, rotation/mirror, labels, routing, instrument state, sheet size)
  router.py       pin escape + obstacle-aware orthogonal A* + tree connection
  check.py        offline self-check: geometry → electrical nets, plus layout checks
  sim.py          real simulation (probe injection, OP/AC/TRAN, result statistics)
  capture.py      real screenshots (PrintWindow, F5/F7 key posting, waveform coverage)
  com.py          COM worker (one reused Multisim instance)
  config.py       local path detection
mcp_adapter/      stdio MCP server + debug client
tools/dbindex.js  read the Multisim master component database index (optional)

Tests

python -m pip install -e .[dev]
python -m pytest -q

The offline suite covers the container codec, XML round-trips, the netlist parser, generation and connectivity of the three examples, and argument validation for mirroring and explicit wiring. CI runs on Windows and Linux (Linux runs only the parts that do not need Multisim).

Known limitations

  • Scope and bode cursors cannot be preset. The design file does carry the cursor positions (NI_EWB_CURRENTDISPLAYDATA_CURSORPOS_0/1), and they survive a save, but Multisim 14.3 ignores the stored value when it opens the design: a file written with T1 = 1.5 ms, T2 = 3 ms opens with both cursors at 0 s, and requesting a restore through NI_EWB_HASSERIALIZERESTOREDATA changes nothing. Take readings from sim, which asks the simulator instead of the screen.

  • Multi-section parts (LM324, 74LS00, ...) use only section A per instance, and digital parts keep VCC/GND on hidden pins. The generator writes one symbol per instance.

  • Routing is automatic A,* so dense circuits can still detour — move coordinates or switch to wires; the crossings count is the metric to optimise. When a layout has no legal route at all, the build fails and names the nets rather than shipping a drawing with wires through parts. Overlapping parts are the usual cause, and the only fix is to move a part, so auto-repair reports every move it makes.

  • parts fetch can crash Multisim. ReplaceComponent occasionally corrupts the process heap (0xC0000374) and Multisim exits. It depends on the state of the running instance rather than on the carrier circuit — the same fetch failed twice and then succeeded three times in a row after the instance was restarted. A crash now restarts the COM instance and retries once before reporting.

  • capture takes the foreground for the desktop screenshot. The circuit and panel images come from PrintWindow and work with Multisim covered, but the full-screen image composites the real desktop, so it needs Multisim on top: leave the mouse and keyboard alone for about a minute. If the foreground cannot be taken, that one image is skipped with a warning and the others are still written.

License

MIT, see LICENSE. Third-party components and notices are listed in THIRD_PARTY_NOTICES.md.

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    D
    maintenance
    Production-ready TypeScript MCP server exposing utility, GitHub, and Microsoft Teams tools over stdio.
    14
    1
    MIT
  • F
    license
    A
    quality
    B
    maintenance
    CAD-engineering MCP tool server for parametric modeling, DFM validation, mechanical calculations, and more. Enables code-CAD builds (build123d/CadQuery), model inspection, meshing, and mechanical calculators via MCP stdio.
    11
    -
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables turning any command-line tool into an MCP server with auto-generated JSON schema, supporting stdio, timeouts, and stderr capture.
    MIT