Skip to main content
Glama
h-d-engineer

OpenEMT MCP Server

by h-d-engineer

OpenEMT

CI Licence: AGPL v3 DOI

The electromagnetic transient simulator built for AI agents.

OpenEMT is an EMT (electromagnetic transient) simulator for power systems: an EMTP-style trapezoidal nodal solver with a positive-sequence power flow, a 36-block catalog spanning lines, transformers, machines, converters and protection, breaker switching events, and single-phase, 3-phase and DC studies.

What makes it different is that the solver core is pure and deterministic, and has three coequal frontends. Humans get a drag-and-drop canvas in a single self-contained HTML file, with no install and no server. Scripts and CI get a CLI. Agents get an MCP server whose tool schemas are generated from the block catalog itself, so an agent always sees the true parameter space rather than a hand-maintained summary of it. All three call the same simulate() and solvePowerFlow(). An agent can enumerate the physics catalog, build a circuit, solve it, and query results by stable block ID: the same loop an engineer runs in the canvas, not a wrapper bolted onto one.

Maturity: beta, v0.1.0. The block models are averaged and simplified by design (the concept-validation layer that runs before anyone opens PSCAD), every block is checked against an analytical or independent-solver reference, and every known limitation is written down. Read VALIDATION.md for what has been checked against what, and SPEC.md section 7 for what this tool does not do.

Provided AS IS, without warranty of any kind (see LICENSE sections 15 to 16). Results are not certified for engineering decisions. An external reference-tool cross-check is still open (SPEC.md section 5, item 9), so treat OpenEMT as a concept-validation and teaching tool, not as a system of record.

The OpenEMT canvas running examples/central_ups.json: a data-center UPS
schematic above three result plots

examples/central_ups.json mid-study. The utility breaker opens at 150 ms: the 480 V switchgear bus (orange) collapses while the UPS output (purple) keeps swinging, the DC link hands off from the rectifier's 380 V to the battery's 360 V, and the battery's state of charge starts draining. Everything on screen came from one Load and one Run.

Quick start

Humans. Try it right now at h-d-engineer.github.io/OpenEMT, or download index.html and double-click it: no install, no server, works offline, and it is the same file either way. Press Load and open anything in examples/.

Agents and scripts. Node 18+, then:

npm install                                          # the API layer's 2 deps
node api/cli.js catalog                              # every block and its parameters
node api/cli.js pf examples/ieee9bus.json            # steady-state power flow
node api/cli.js run examples/central_ups.json --pf   # EMT study from that operating point
node api/cli.js query examples/central_ups.json --block 15 --signal Vrms --pf --tail

That last line answers the question the central_ups example exists to ask: the utility trips at 150 ms and the 480 V switchgear bus (block 4) collapses to zero, while the UPS output (block 15) still reads 277 V at the end of the run.

Only the API layer has dependencies; the browser build has none. Run settings (duration, time step, phase mode) travel inside the circuit file, so a shipped example runs its intended study without being told how long to run. node api/cli.js --help lists every command, and docs/MCP.md has the per-client MCP setup: in Claude Code it is zero-config, because the repo ships a .mcp.json at the root.

Related MCP server: Universal Netlist MCP Server

Using the canvas

The rest of this section is the user manual for the browser frontend.

The solver runs in a Web Worker (built from an inline Blob, so it's still one file) and streams plot data back as it computes — long Duration (ms) runs animate progressively instead of freezing the tab, and can be cancelled with Stop.

The run toolbar has three time controls, PSCAD-style: Duration (total simulated time, ms), Time step (the solver's internal trapezoidal step, µs — smaller is more accurate but slower; defaults to 50 µs), and Plot step (how finely output is kept for plotting, µs — leave blank for automatic decimation that keeps every solver sample on normal runs and only thins very long runs to cap storage, or set it explicitly for a fixed sample spacing). Zoomed-out plots downsample per pixel by min/max bucketing so narrow spikes still show at their true amplitude.

The block palette is grouped into four category dropdowns — Sources/Loads, Passive, Power Electronics, Protection/Meas — instead of one long row of buttons; click a category to flip open a flyout of its blocks, click a block to drop it on the canvas (the flyout stays open so you can drop several of the same kind in a row), and click elsewhere to close it. Each block also gets a small colored corner tick on the canvas matching its palette category, so a dense schematic is scannable by category at a glance.

After a run, small animated markers march along each wire showing which way power is actually flowing — into a load, out of a source, or reversing direction on a battery as it switches between charging and discharging. AC wires show both components independently, since a real AC branch carries them simultaneously and they can even point opposite ways: a blue half-arrow on the top of the wire for active power, a yellow half-arrow on the bottom for reactive power — the two ride the same wire as one line with two independent halves rather than separate marker trains. A Flow arrows checkbox in the toolbar turns the whole thing on or off (it was called "Power flow" before that name was given to the steady-state solve below). Only wires with an unambiguous reading get a marker: a pure measurement probe never shows one, and neither does a wire on a node shared by several devices with no explicit Bus block (splitting that current per-wire isn't attempted).

Blocks draw as standard IEC-style schematic symbols (AC-source circle, inductor coil, capacitor plates, two-circle transformer, breaker blade, converter squares…), so the canvas reads like a real single-line diagram.

Canvas editing: scroll or use the +/− buttons to zoom, drag empty canvas to pan, select a block and press R (or click the ↻ button) to rotate it 90°, or hit the ⛶ button to take the canvas fullscreen (Esc exits). Select several blocks at once by shift/ctrl-clicking each one, or shift/ctrl-dragging a rectangle over them — then drag any of them to move the whole group, press R to rotate all of them, or Delete/Backspace (or the Delete button) to remove them together. Escape clears the selection. Undo/Redo buttons (or Ctrl+Z / Ctrl+Shift+Z / Ctrl+Y) cover every schematic edit — adding, deleting, dragging, rotating, rewiring, editing a parameter, clearing the canvas, running auto-layout, or loading a file over your current work. A project-name badge above the canvas (next to the status line) always names the circuit you're looking at — Demo on startup, the file name after a Load, Untitled after Clear — and grows a the moment you edit anything, clearing again when you Save (which also downloads under that name instead of a generic circuit.json). For nodes with more than two connections, drop a Bus block — a thick, nameable junction bar with one or more taps — instead of routing many wires to one point. Every bus is also a measurement point: its node voltage shows up automatically in the plot Signals picker under the bus's name (AC or DC detected from the circuit), so you rarely need a separate probe on a bus.

As your circuit grows, use the Layout button to auto-arrange blocks in a left-to-right or top-to-bottom hierarchy (power source at top/left, branches flowing outward with even spacing) — a quick way to declutter before manual fine-tuning. In top-to-bottom mode, components rotate to run vertically with the flow (a bus stays a horizontal bar; ground/probe/fault keep their natural orientation), so wires between them run as clean straight lines instead of sideways elbows.

Plots are fully customizable: add/rename/remove plot cards, and use each plot's Signals button to pick which probe voltages and branch currents (per phase, A/B/C — a DC node shows one "DC" signal instead of three duplicates) appear from a grouped, filterable tree. Each signal can go on the plot's left or right y-axis, so signals with very different scales (a 12 kV bus and a 480 V bus, or a voltage and a current) stay legible together.

Every probe voltage and branch current also offers an RMS trace (one fundamental cycle, sliding window), and every branch element offers active (P) and reactive (Q) power, right alongside its current in the picker — true power needs a voltage and current pair, which only a branch has (a bare probe doesn't have an associated current). Unlike voltage/current, P and Q on a genuine 3-phase branch are a single total 3-phase value, not three A/B/C entries — that's how 3-phase power is normally quoted, and per-phase current is still there if you need to check for imbalance. A branch that only exists on one phase (a single-phase fault, say) still reports its one real reading labeled by that phase.

Each branch offers two distinct power quantities, because they answer different questions: plain P/Q (W/VAR) is what the element itself absorbs — a closed breaker reads ~0 and a line only its own I²R loss, which is correct but surprising if you expected to see the feeder's power there. P/Q in / out (W in/W out) is the power actually flowing through the branch, measured at terminal 0 (in) and terminal 1 (out): along a series chain, one element's "out" equals the next one's "in", and in − out = absorbed exactly. A terminal wired to ground reads 0 through power (no power flows through a node at 0 V), so read a source's delivered power from its "out" side. Through power isn't offered on the PFC and DC/DC converter blocks — their two sides carry different currents, so the series in/out identity doesn't apply to them. Sign convention is the same for every block, no exceptions: positive = absorbing power, negative = delivering it — a discharging battery or a generating PV panel read negative, same as any other source, and a charging battery reads positive, same as any other load.

All plots share one zoomable time window, so zooming in on one lines up the same window on every other plot — useful for correlating a voltage dip with a current spike at the same instant. Drag on any plot to zoom into a time range; Shift+drag to pan; scroll to zoom at the cursor; or use the +/−/Reset controls above the plots. The y-axis auto-rescales to whatever's currently visible.

Power flow

Alongside the time-domain solver there is a positive-sequence steady-state power flow. It answers a different question: instead of integrating the network forward in time, it solves the algebraic operating point directly.

Press Power flow in the toolbar and every bus is annotated on the canvas with its solved voltage magnitude (pu) and angle, colored green inside the 0.95 to 1.05 pu band and red outside it. The status line reports convergence, total generation, the bus-voltage range, and how many buses fall outside the band, which makes the canvas a quick voltage-screening view.

The more valuable use is initialization. Time-domain runs otherwise start cold, with every machine at rotor angle 0, so a generator that needs a real load angle to export its power has to swing into position; at a weak point of interconnection it can swing past its pull-out and never synchronize at all. With Init from PF checked (the default), Run solves the power flow first and starts every machine at the operating point: correct rotor angle, internal EMF, and filtered P/Q, with the governor and AVR centered so mechanical equals electrical power at t = 0. The run then begins flat instead of swinging in. On the IEEE 39-bus case the residual frequency movement over an undisturbed run drops from about 110 mHz (cold) to about 3 mHz (initialized).

Generators and inverters carry two power-flow parameters in the inspector: pfType (slack, PV, or PQ) and Vset (the scheduled terminal voltage in volts; 0 means "use E0"). Exactly one machine should be the slack; if none is marked, the largest machine is promoted automatically. Constant-impedance elements (lines, transformers, caps, RLC loads) fold into the admittance matrix, and AC PQ (and ZIP) load blocks are treated as P+Q injections.

Honest limits of the current MVP: it initializes machine states only, not passive-element histories (line currents and cap voltages still start at zero), so a brief electrical inrush over the first cycles remains even from a power-flow start. The solve is Gauss-Seidel rather than Newton-Raphson, and there is no reactive-limit enforcement, tap changing, or N-1 contingency screening yet. See SPEC.md section 5.

Driving it from an agent (MCP)

The solver core is exposed as an MCP server (api/mcp-server.js) with 14 tools, so an agent (Claude Code, Claude Desktop, Cursor, others) can enumerate the block catalog, build a circuit, import a PSS/E case, run power flow and time-domain simulations, and query results by block ID over the Model Context Protocol. Two design rules make it usable rather than decorative: the tool schemas are generated from DEFS, so the parameter space an agent sees is the one the solver actually implements, and every result is addressed by stable block ID, never by positional index, so an agent can edit a circuit without invalidating the query it wrote earlier. The solver is deterministic, so a run is reproducible from the circuit file alone.

In Claude Code it is zero-config: the repo ships a .mcp.json at the root and you approve the one-time prompt on first use. For Claude Desktop and other clients you add a small absolute-path entry to that client's MCP config. Prerequisites, exact snippets per client, and troubleshooting are in docs/MCP.md.

Development

src/blocks.js       block catalog + companion models       <- add new blocks here
src/solver.js       union-find, LU, time loop, events,
                    power flow + machine init              <- numerics
src/import.js       PSS/E RAW importer (DOM-free)
src/ui.js           canvas, wiring, plots, demo            <- browser frontend
src/shell.html      page shell + styles
build.py            assembles index.html from src/         (python3 build.py)

api/core.js         the OpenEMT class: the headless contract <- extend this
api/cli.js          thin CLI front over core.js
api/mcp-server.js   thin MCP front over core.js
api/test_api.js     regression guard for all three

src/ is the single source of truth. It is plain global-scope script that build.py concatenates into the one-file browser build, and that api/core.js loads as text into a Node vm sandbox: same code, two hosts, no second copy of the physics and no duplicated block list (the MCP tool schemas are generated from DEFS at startup). There is deliberately only one headless loader; extend api/core.js rather than adding another.

Read SPEC.md before changing anything: it contains the companion-model derivations, solver invariants, and the roadmap. The intended workflow with a local model (Claude Code + qwen or similar):

  1. Point Claude Code at this folder.

  2. Give it SPEC.md as context and a single roadmap item as the task (e.g. "implement the capacitor block per SPEC section 2").

  3. After each change: python3 build.py && node smoke_test.js && node api/test_api.js must pass, and the build must leave index.html byte-identical if src/ was not touched.

  4. Physics that is not already derived in SPEC section 2 should be derived in a frontier-model session first, added to SPEC, then implemented locally.

Examples

examples/README.md is the index: one table row per shipped example, with the run mode, what it demonstrates, and where its data came from. Eleven curated cases ship in examples/:

showcase

every AC block in one circuit, plus a self-clearing phase-A fault

central_ups, central_ups_sag

a data-center UPS riding through a utility trip and, separately, a grid fault

ieee9bus, ieee39bus

the WSCC 9-bus and IEEE 39-bus New England benchmarks, from primary sources

iec60909_hv_network, ieee_harmonics_14bus

PSS/E RAW imports checked against the source cases' own bus voltages (load-flow only, deliberately)

radial_feeder

the gentlest starting point: a feeder, three transformers, one breaker trip

single_phase_lateral, single_phase_gfm_lateral

genuine single-phase unbalance on a tapped lateral

syncgen_droop

two synchronous machines sharing a load step by governor droop

Run settings travel inside each file, so Load then Run gives the intended study. Every case also loads headlessly: node api/cli.js run examples/showcase.json.

The rest of this section is a tour of the block library, using the smaller regression circuits in tests/fixtures/ as illustrations. Those are loadable with the Load button too; they are the circuits smoke_test.js asserts against, which is why each one exercises exactly one idea.

tests/fixtures/hybrid.json — hybrid AC/DC study (3-ph mode): 277 V grid → breaker → line feeds an AC load and, through the PFC bridge, a 380 V DC bus with a 10 kW constant-power load. The breaker trips at 60 ms (per-pole current-zero clearing), the PFC shuts down on undervoltage, and the battery catches the DC bus at 360 V — one simulation across both domains.

tests/fixtures/dcbus.json — DC rack backup study (run in 1-ph mode): PFC rectifier holds a 380 V bus feeding a 10 kW constant-power load; grid is lost at 60 ms and the battery DC/DC catches the bus at its 360 V setpoint.

The battery is a full bidirectional store with state of charge: it discharges to hold its V ref when the bus sags (and dies at SOC 0), and charges at up to I charge whenever the bus sits above V ref (stopping at SOC 100) — plot the SOC from the Signals picker. Capacity defaults to a deliberately tiny 0.02 Ah so charge/discharge is visible on millisecond EMT timescales. The PFC gains a reverse flag: set rev=1 and its V ref below the battery's, and it exports battery power back into the AC grid at unity power factor — enough for simple BESS charge/export studies from either a DC or an AC link.

tests/fixtures/bess_soc.json (run in 1-ph mode) — battery SOC demo on a DC link: the PFC holds the bus and charges the battery (soc0 = 40%) for the first 50 ms, then the grid is lost and the battery discharges into the CPL — watch SOC ramp up, then down, in the Signals picker.

tests/fixtures/grid_export.json (3-ph mode) — battery-to-grid export: a battery (Vref 380 V) holds a named Bus on the DC link above the PFC's setpoint (Vref 360 V, reverse = 1), so the PFC continuously exports the battery's power to the AC grid at unity pf. The bus is auto-monitored (no probe needed) and SOC drains as it discharges into the grid.

The GFM inverter is now a real AC/DC device, not just an idealized AC source: its optional bottom DC+ terminal draws or delivers exactly the power its AC side is measured to exchange, so wiring a battery there shows genuine charge/discharge flow instead of free energy. It also has a mode switch — mode 0 (default) is the original grid-forming droop (sets its own V/f, can island); mode 1 is grid-following: it locks onto an existing grid and PI-dispatches a fixed P0/Q0 setpoint instead of drooping away from it. GFL mode's tracking speed and damping depend on the tie being reasonably inductive (a well-filtered inverter, larger Lf, tracks faster and tighter — see SPEC.md for the derivation); defaults are tuned conservative so it won't misbehave out of the box.

tests/fixtures/gfm_bess.json (3-ph mode) — a battery wired to a GFM inverter's DC port, with the inverter in grid-following mode dispatching 5 kW / 1 kvar into a stiff grid: watch the GFM's DC current and the battery's SOC move together as the setpoint is delivered.

The Sync gen block is a real rotating-machine model — a classical synchronous generator (round rotor, constant transient EMF behind Ra + Xd'), not another inverter-based source. Unlike the GFM inverter, whose frequency is an algebraic function of filtered measured power (droop or PI), a sync gen's frequency is a genuine dynamic state: its rotor is a spinning mass with inertia (H), so after a disturbance it actually swings — a real oscillation that decays over a few cycles, not an instant jump to a new setpoint. A governor (Kgov, kW/Hz droop; 0 = fixed mechanical power, no governor) adjusts mechanical power as frequency sags or rises, and multiple machines on the same system automatically share a load in proportion to their droop, exactly like real turbine governors — no coordination logic needed, it falls straight out of the physics. An AVR (mq/Q0, same Q-droop form as the GFM's) holds terminal voltage. Frequency (f) is plotted automatically from the Signals picker — watching it dip and recover after a load step is the actual point of this block. Classical model only: no subtransient reactances, saturation, or exciter dynamics (see SPEC.md for the full derivation and the numerical-stability checks behind the defaults).

examples/syncgen_droop.json (3-ph mode; the file carries its own 5 s run, because the natural swing period here is around half a second) — two sync gens (15 kW / 10 kW mechanical, different ratings and governor droop) share a base load through a common Bus; a breaker adds a second, larger load at 2000 ms. Watch both machines' f signals dip together and settle to a new, slightly lower shared frequency as their governors pick up the extra demand in proportion to droop — a textbook primary-frequency- response demo, and the first example in this tool with more than one generation source.

The DC/DC block is a dedicated bidirectional converter, separate from a battery's own built-in regulation — the way industry actually controls charge/discharge, letting a battery sit at its own native voltage while a converter steps it to a bus at a different level. mode 0 (CV) PI-holds its OUT terminal at a V ref; mode 1 (CC) dispatches a fixed current directly (the classic constant-current charge/discharge pattern) — its IN current is always the lossless power-balance consequence of whatever OUT is doing. Either side needs a capacitor (or another regulating element) to hold its voltage — a bare current source can't stabilize a node by itself.

tests/fixtures/dcdc_charger.json (3-ph mode) — a DC/DC converter in CC mode discharges a battery at its own native 48 V onto a 380 V DC bus (held by a reversible PFC/grid tie) at a fixed, controlled current: watch the battery's higher current on its own 48 V side against the converter's smaller, set-point current on the 380 V side, and its SOC drain accordingly.

The PV array block is a panel with its DC/DC converter and MPPT controller embedded as one block, the way real solar installations are built. It runs a genuine Perturb & Observe search — its internal operating voltage (Vop, plot it from the Signals picker) hunts around the panel's max-power point, completely decoupled from whatever the DC bus is actually at. G (irradiance, W/m², 1000 = full sun) is a static "current weather" knob scaling delivered power; Voc/Isc/Vmpp/Impp are the datasheet numbers every panel ships with. Generation-only — it never absorbs — so pair it with something that actively regulates its bus (a battery, or another converter).

tests/fixtures/pv_mppt.json — a PV panel under partial cloud (G=800) charges a battery on a small DC bus: watch Vop hunt near Vmpp while the battery's SOC climbs from the panel's MPP power.

The Line RL block can now model a full nominal π-equivalent (RLC) line: give it a C (total, µF) and it splits that evenly as a shunt capacitor to ground at each end — the standard way medium-length transmission lines are modeled, adding charging-current effects a plain series R+L can't. Not combinable with mutual coupling (Rm/Lm) in this version. The PQ load block is the standard power-flow load model — constant real+reactive power regardless of bus voltage (unlike Load R's fixed impedance), with Q>0 lagging/inductive and Q<0 leading/capacitive.

tests/fixtures/pq_piline.json — a source feeds a PI (RLC) line into a PQ load (8 kW / 3 kvar): watch the load bus sag realistically under the line impedance while the load still draws its full setpoint power.

examples/showcase.json (open with the Load button) exercises every AC block: source → breaker (closes 10 ms) → coupled 3-ph line → 2:1 transformer → load + filter cap, with a GFM droop inverter dispatching 5 kW into the secondary bus and a phase-A-to-ground fault at 55 ms that self-clears at the first current zero after 85 ms. Probes on primary and secondary buses.

examples/radial_feeder.json — a plain linear distribution study (no converters): a 2.4 kV feeder fans out through a Bus to three step-down (10:1) transformers and their loads, and one feeder's breaker opens at 50 ms — watch that one probe's voltage drop to zero at 50 ms while the other two ride through unaffected. A good one for seeing Bus fan-out, transformers, and the power-flow arrows together at a slightly larger scale than the other examples.

examples/central_ups.json (3-ph mode; the file carries its own 300 ms run settings) — a centralized-UPS data center whose topology follows PNNL's DML_DC2_Central_UPS PSCAD example system (Data Center Model Library, report PNNL-38817). It was rebuilt on this block set, not converted, so treat it as illustrative of that architecture rather than as a validated replica of the PNNL model. A 2.4 kV utility feeds an 8.66:1 service transformer onto a named 480 V switchgear Bus carrying chiller-pump, fan, and site-support loads plus a double-conversion UPS — PFC rectifier holding a 380 V DC link, battery on the link, GFM inverter re-forming a tightly regulated 277 V island for a ~10 kW IT load. The utility breaker trips at 150 ms and the rectifier drops with it (its grid-lost protection — the same trip PNNL describes for a grid-side sag); the switchgear bus and all the cooling load black out, the battery catches the DC link at its 360 V setpoint, and the IT load rides through the entire event without a dent. The saved plots show the whole story: bus vs UPS-output voltage, DC-link handoff 380 → 360 V, and battery SOC ramping down once it carries the load.

Validation

node smoke_test.js runs every block in canned circuits headless and checks the results against analytical or independent-solver references (133 checks, per-block PASS/FAIL summary). VALIDATION.md is the manifest: per-block checks, reference types, tolerances, and the rationale for each tolerance band. Every new block ships with its checks appended to the smoke test and a row in that manifest.

node api/test_api.js is the second suite: it guards the headless contract (api/core.js, the CLI, and the MCP server) and ties its results to the same analytical values, so the agent path is proven to reproduce the solver path rather than merely to run. Both suites must pass before any solver, example, or API change, and python build.py must reproduce the committed index.html byte for byte.

The power flow is guarded by a flat-start test, which is its real acceptance criterion: solve, initialize, then run with no disturbance at all and confirm nothing moves. It checks convergence, that the machine actually starts at a nonzero load angle, that the undisturbed run stays flat (under 30 mHz, against roughly 519 mHz for the same circuit cold-started), and that the final frequency lands on nominal.

Status

Version 0.1.0. Roadmap (SPEC.md section 5) complete through item 37, with one exception: item 9 (the per-block validation suite) stays open until an external reference-tool cross-check exists. The analytical and independent-solver checks are in place (see VALIDATION.md), but that last class is non-negotiable before any client-facing use, which is why the AS-IS notice at the top of this page is not boilerplate.

Studies can be single-phase or 3-phase (balanced, or unbalanced via coupled lines, per-phase faults, or single-phase laterals tapped off one phase with the Phase Tap block, including single-phase loads, transformers, and grid-forming/following inverters on a lateral), plus DC bus studies and hybrid AC/DC circuits bridged through the PFC and GFM blocks. The 36-block catalog (full table in SPEC.md section 4): source, ground, probe, bus, phase tap; lines (RL/π, Bergeron traveling-wave, frequency-dependent JMarti); passives (C, series RLC, parallel RLC); transformers (two-winding with opt-in saturation, 3-phase vector-group, three-winding), all entered as nameplate winding voltages; loads (AC PQ, ZIP composite, DC constant-power, induction motor); machines and converters (synchronous generator with governor/AVR, GFM inverter with droop/grid-following modes + DC port + current limiter, transmission-grade GFL solar with an explicit PLL, Type 4 wind, VSC-HVDC link, SVC/STATCOM, PFC rectifier, battery DC/DC, dedicated DC/DC, PV with MPPT); protection and switching (breaker with multi-op reclose, fault, overcurrent relay, distance relay with out-of-step blinders, latching generation-trip relay, switched-shunt controller, surge arrester); and the aggregation current-scaling coupler for N-replica studies.

A positive-sequence power flow (Newton-Raphson with a Gauss-Seidel fallback, generator reactive limits, PSS/E RAW import) solves the steady-state operating point, annotates bus voltages on the canvas, and initializes time-domain runs so they start flat instead of swinging in from a cold start. The browser build runs the solver in a Web Worker with streaming plots, so run duration is not limited by UI freezing.

See SPEC.md section 7 for the honest limitations register.

Licence

OpenEMT is free software under the GNU Affero General Public License v3 (AGPL-3.0-only). See LICENSE.

A commercial licence is available from PEN LLC for uses the AGPL does not suit, including proprietary redistribution and hosted services built on a modified version. See LICENSING.md, or enquire at licensing@openemt.pro.

Contributions are welcome and require a signed CLA; see CONTRIBUTING.md. The licences cover the code, not the name: see TRADEMARK.md.

To cite OpenEMT, use the concept DOI 10.5281/zenodo.21857083, which always resolves to the newest archived release; each release also has its own version DOI if you need to pin one. GitHub's "Cite this repository" button reads CITATION.cff and will format it for you.

Copyright (C) 2026 Hiva Nasiri.

A
license - permissive license
-
quality - not tested
A
maintenance

Maintenance

Maintainers
Response time
Release cycle
1Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

View all related MCP servers

Related MCP Connectors

  • MCP server exposing the Backtest360 engine API as tools for AI agents.

  • MCP server for AI dialogue using various LLM models via AceDataCloud

  • MCP server connecting AI agents to non-custodial staking data across 130+ networks.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/h-d-engineer/OpenEMT'

If you have feedback or need assistance with the MCP directory API, please join our Discord server