Skip to main content
Glama
README.md
# ltspice-mcp

I wanted to learn about MCP, slash commands and claude.md files. Are DSLs a thing of the past? I created the following with Claude:

An MCP (Model Context Protocol) server that gives an LLM direct, tool-based access to LTspice circuit simulations — read schematics, set component values, run simulations, parse results, and generate plots, all from a Claude conversation.

---

## What it does

1. **Read & modify schematics** — parse `.asc` files, inspect components and parameters, patch values
2. **Run simulations** — invoke LTspice headlessly via Wine (`-b` batch mode), get back log and output files
3. **Analyze results** — parse `.raw` / `.op.raw` binary output: waveforms, node voltages, device currents
4. **Generate plots** — auto-generated matplotlib scripts saved next to the schematic as a reproducible record

---

## MCP Tools

| Tool | Description |
|------|-------------|
| `list_schematics` | Discover `.asc` files and associated outputs in a directory |
| `read_schematic` | Parse components, params, includes, directives from `.asc` |
| `read_parameters` | Read `.param` values from a `.inc` or `.asc` file |
| `write_parameters` | Write/overwrite `.param` values in a `.inc` file |
| `run_simulation` | Run LTspice via Wine (`-b` batch), return log + output file list |
| `read_waveforms` | Parse transient/AC `.raw` output — returns waveforms |
| `read_op_point` | Parse DC operating point `.op.raw` — returns node voltages/currents |
| `modify_component` | Patch `SYMATTR Value` of a named component directly in `.asc` |
| `write_schematic` | Generate a new `.asc` schematic from a component/netlist description |

---

## `/analyze-circuit` slash command

The flagship workflow. Run it from Claude Code on any `.asc` schematic:

```
/analyze-circuit examples/rc_filter/mystery_circuit.asc
/analyze-circuit /absolute/path/to/my_filter.asc
/analyze-circuit          ← lists available schematics and prompts
```

It will:
1. Run the simulation via `run_simulation`
2. Read the DC operating point — transistor bias, operating region
3. Discover all waveforms (names, ranges, simulation type)
4. Detect high-frequency signals and switch to full-resolution rendering automatically
5. Write and execute a `<stem>_analysis.py` plot script next to the schematic
6. Display the plot inline and provide a written circuit explanation

---

## Example Analysis Output: AM Modulator (`mystery_circuit.asc`)

A collector-modulated AM transmitter built around a single 2N3904 NPN BJT.

```spice
; Sources
V1  30 V DC                        ; supply
V2  SINE(0 30m 600k)               ; RF carrier — 30 mV, 600 kHz
V3  SINE(0 3.5 1k)                 ; audio modulating signal — 3.5 V, 1 kHz

; Bias network
R1  56k    ; base voltage divider (top)
R2  15k    ; base voltage divider (bottom)
R3  10k    ; collector load
R4  4.7k   ; emitter resistor — V3 (audio) connects at its bottom terminal

; Signal coupling
C1  100n   ; AC-couples carrier (V2) into base
C2  100n   ; emitter bypass (shorts R4 at RF frequencies)
C3  470p   ; output coupling cap — collector → V(n002) load output

Q1  2N3904 ; common-emitter RF amplifier
R5  1k     ; output load
```

**How it works:** V3 (audio, 3.5 V) sits in series with R4 between the emitter and ground. As the audio signal swings, it shifts the effective emitter voltage at 1 kHz, varying Vbe and hence gm. Since the RF carrier is simultaneously being amplified at the base, its gain varies at the audio rate — producing AM modulation. C3 AC-couples the collector output to the load.

**DC bias (Q1 in active region):**

| Parameter | Value |
|-----------|-------|
| Vcc | 30.0 V |
| Vc (collector) | 18.0 V |
| Vbe | 0.66 V |
| Vce | 12.4 V |
| Ic | 1.20 mA |
| β | 334 |

**`/analyze-circuit` output:**

![mystery_circuit analysis](examples/rc_filter/mystery_circuit_analysis.png)

The top panel uses LTspice-style min/max-per-pixel rendering to produce the AM "football" shape at full 2 ms resolution — the green filled band is the 600 kHz carrier, its amplitude envelope tracing the 1 kHz audio signal (red dashed). The bottom panel zooms to 10–30 µs to show individual carrier cycles.

---

## Setup

```bash
# Install in editable mode
pip install -e .

# LTspice runs via Wine — set path if different from default:
export LTSPICE_EXE="/home/user/.wine/drive_c/Program Files/LTC/LTspiceXVII/XVIIx64.exe"
```

### MCP config (`~/.config/claude/claude_desktop_config.json`)

```json
{
  "mcpServers": {
    "ltspice": {
      "command": "ltspice-mcp"
    }
  }
}
```

Or without installing the package:

```json
{
  "mcpServers": {
    "ltspice": {
      "command": "python",
      "args": ["-m", "ltspice_mcp.server"],
      "cwd": "/path/to/ltspice-mcp/src"
    }
  }
}
```

---

## Workflow example: RC filter optimization

```python
list_schematics(directory="examples/rc_filter/")
read_schematic(path="rc_filter.asc")           # inspect components
read_parameters(path="params.inc")             # current R=1k, C=100n → fc≈1.6kHz
write_parameters(path="params.inc", parameters={"R": 2200, "C": 47e-9})
run_simulation(schematic_path="rc_filter.asc")
read_waveforms(raw_path="rc_filter.raw", signals=["V(out)"])
# adjust values, repeat
```

---

## Project structure

```
src/ltspice_mcp/
  server.py           — MCP server, all tool definitions
  raw_parser.py       — .raw file parser (binary UTF-16-LE and ASCII)
  runner.py           — Wine subprocess runner (two-step: netlist → sim)
  schematic_writer.py — .asc generator (auto-layout + wire routing)
examples/
  rc_filter/
    rc_filter.asc                   — RC low-pass filter demo
    mystery_circuit.asc             — AM modulator (this example)
    mystery_circuit_analysis.py     — auto-generated plot script
    mystery_circuit_analysis.png    — analysis output
.claude/commands/
  analyze-circuit.md  — /analyze-circuit slash command definition
```

---

## Requirements

- Python 3.10+
- [Wine](https://www.winehq.org/) with LTspice XVII installed
- `matplotlib`, `numpy` (for generated plot scripts)
- MCP-compatible client (Claude Desktop or Claude Code)