Skip to main content
Glama
lildebil0

solidworks-mcp

by lildebil0
README.md
# solidworks-mcp

**English** · [Русский](README.ru.md) · [Кыргызча](README.ky.md)

> An MCP server that gives an LLM **57 tools**: a cross-platform **build123d code-CAD engine** (generate geometry in Python → STEP/STL/PNG) and a **SolidWorks COM automation** surface (drive a running SolidWorks — documents, dimensions, sketches, features, drawings, VBA).

[![Python](https://img.shields.io/badge/python-3.12%E2%80%933.14-blue.svg)](https://www.python.org/)
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
[![status](https://img.shields.io/badge/status-working%20skeleton%20%C2%B7%20live%20SolidWorks%20unverified-orange.svg)](#what-works--what-doesnt)

---

## Contents

- [What it is](#what-it-is)
- [What works / What doesn't](#what-works--what-doesnt)
- [Tool reference](#tool-reference)
- [Architecture](#architecture)
- [Two CAD paths](#two-cad-paths)
- [Install & run](#install--run)
- [Configure in an MCP client](#configure-in-an-mcp-client)
- [makepy (early binding)](#makepy-early-binding)
- [Safety](#safety)
- [Development & tests](#development--tests)
- [License & attribution](#license--attribution)

---

## What it is

`solidworks-mcp` is a [Model Context Protocol](https://modelcontextprotocol.io/) server built on [FastMCP](https://github.com/jlowin/fastmcp). It exposes two complementary CAD surfaces to any MCP client (Claude, or another LLM):

1. A **build123d code-CAD engine** — describe a part in Python, run it in a sandbox, get back a STEP/STL file and a PNG preview so the model can *see* the geometry. Pure Python + OpenCascade (OCCT); runs on any OS, no SolidWorks needed.
2. A **SolidWorks COM automation** surface — the `sw_*` tools drive a **running, licensed SolidWorks** over COM: open/save native documents, read/write driving dimensions, build sketches and features, create drawings, run VBA, and — through a reflective core — reach the **entire** SolidWorks API.

All 57 tools are registered by one FastMCP server that speaks MCP over stdio.

![Architecture](docs/img/architecture.png)

---

## What works / What doesn't

This is an **honest** status section. The repo is a working skeleton with a green, cross-platform core and a fully implemented — but **not yet live-verified** — SolidWorks surface.

| Status | Meaning |
|:------:|---------|
| ✅ | **Works & tested** — exercised by the automated test suite, cross-platform. |
| 🧪 | **Implemented, NOT yet verified on live SolidWorks** — logic covered by mock-COM tests only; needs Windows + a running, licensed SolidWorks to exercise for real. |
| ⚠️ | **Caveat** — read before relying on it. |

**✅ Works & tested**

- The **build123d engine** (all 6 tools): generate → render → DRC → export STEP/STL, behind an AST sandbox. Cross-platform.
- **MCP registration** of all **57 tools** by the FastMCP server.
- The **test suite**: **47 pytest passing** — 13 build123d/sandbox + 34 mock-COM. Runs on any OS, no SolidWorks required.

**🧪 Implemented, not yet verified on live SolidWorks**

- **Every `sw_*` tool** (51 of them: 11 base + 40 advanced). They are written, import cleanly, and their Python logic — the object-handle registry, argument marshaling, dispatch routing, enum resolution, screenshot→PNG, VBA temp-file handling — is covered by **mock-COM unit tests**.
- What has **not** happened: running them against **real geometry**. SolidWorks COM is STA and **not headless**, so this requires a Windows machine with a running, licensed SolidWorks. On a machine without one, a real `sw_*` call **fails loud** with `SolidWorks not available` — by design, not a silent fake.

**⚠️ Caveats**

- The **Tier-1 wrappers hardcode specific COM method signatures** (e.g. `FeatureExtrusion3`, `FeatureCut3`). Method shapes vary slightly across SolidWorks releases; if yours differs and a wrapper raises, **fall back to `sw_call`** with the exact method from the [API Help](https://help.solidworks.com/).
- Some calls that return data through **ByRef out-parameters** need **makepy** (early binding) to marshal correctly; late binding covers the vast majority. See [makepy](#makepy-early-binding).
- **`sw_run_vba` and `sw_call` execute arbitrary local code** in SolidWorks — the same trust level as a user running a macro by hand. Local, user-invoked use only; do not expose this server to untrusted callers. See [Safety](#safety).

For the deep dive on the SolidWorks surface — full architecture, makepy bootstrap, the safety model, and a worked end-to-end live-acceptance sequence — see **[`docs/SW_API.md`](docs/SW_API.md)**.

---

## Tool reference

Units: the build123d engine is unitless build123d (mm by convention); Tier-1 `sw_*` wrappers take **millimetres / degrees**; the raw `sw_call` core talks to the API in **metres / radians**.

### build123d engine — 6 — ✅ works & tested

| Tool | What it does |
|------|--------------|
| `generate_part(code)` | Run build123d code in the sandbox → PNG preview + metrics (bbox, size, volume, CoM) + `part_id` |
| `render_views(part_id)` | Isometric + front + top + right views as one PNG |
| `export_model(part_id, format, path)` | Write `step` or `stl` to disk |
| `run_drc(part_id, min_wall, max_bbox)` | Minimal DFM: volume > 0, max size, min-dimension proxy |
| `batch_generate(specs)` | Many parts in one call (list of code strings) |
| `list_catalog(query)` | bd_warehouse standard parts — **stub / TODO** |

### SolidWorks base — 11 — 🧪 implemented, not live-tested

| Tool | What it does |
|------|--------------|
| `sw_connect(launch_if_needed=False)` | Attach to (or optionally launch) SolidWorks; returns its revision |
| `sw_open(filepath)` | Open a native `.sldprt` / `.sldasm` / `.slddrw` |
| `sw_save(filepath=None)` | Save in place, or Save As to a path |
| `sw_close(save_first=False)` | Close the active document |
| `sw_export_step(output_path)` | Export the active model to STEP (clears selection first) |
| `sw_rebuild(force=False)` | `EditRebuild3` (changed only) / `ForceRebuild3` (whole tree) |
| `sw_get_dimension(name)` | Read a named driving dimension, in mm (e.g. `D1@Sketch1`) |
| `sw_set_dimension(name, value_mm, do_rebuild=True)` | Set a named dimension and rebuild |
| `sw_list_configurations()` | List configuration names of the active document |
| `sw_activate_configuration(name)` | Activate a configuration by name |
| `sw_run_macro(macro_path, module_name, procedure_name)` | Run a prebuilt VBA macro via `RunMacro2` |

### SolidWorks Tier-0 generic core — 7 — 🧪

This layer reaches the **entire** SolidWorks API by itself.

| Tool | What it does |
|------|--------------|
| `sw_call(handle, method, args=[])` | ★ Invoke **any** COM method on the object behind `handle`; returns a value or a new handle |
| `sw_get_prop(handle, prop)` | Read any COM property |
| `sw_set_prop(handle, prop, value)` | Write any COM property |
| `sw_enum(name)` | Resolve a `swconst` constant by name (e.g. `swEndCondBlind` → 0) |
| `sw_handles()` | List live object handles (`app`, `doc:1`, `obj:2`, …) |
| `sw_release(handle)` | Drop a handle |
| `sw_capture(width, height)` | Screenshot the active view/sheet → image |

### SolidWorks Tier-1 ergonomic wrappers — 32 — 🧪 (version-sensitive)

| Area | Tools |
|------|-------|
| New docs | `sw_new_part`, `sw_new_drawing` |
| Sketch | `sw_sketch_start`, `sw_sketch_line`, `sw_sketch_circle`, `sw_sketch_rect`, `sw_sketch_arc`, `sw_sketch_add_relation`, `sw_sketch_add_dimension`, `sw_sketch_exit` |
| Feature | `sw_extrude`, `sw_revolve`, `sw_loft`, `sw_sweep`, `sw_fillet`, `sw_chamfer`, `sw_hole`, `sw_linear_pattern`, `sw_circular_pattern` |
| Drawing | `sw_add_sheet`, `sw_add_view`, `sw_add_projected_view`, `sw_add_section_view`, `sw_add_detail_view`, `sw_insert_model_dimensions`, `sw_add_note`, `sw_add_balloon`, `sw_set_titleblock`, `sw_insert_bom`, `sw_export_drawing` |
| Select | `sw_select_by_id`, `sw_clear_selection` |

### SolidWorks Tier-2 — 1 — 🧪

| Tool | What it does |
|------|--------------|
| `sw_run_vba(code, module, proc)` | Run arbitrary VBA (write a temp `.swb`, run via `RunMacro2`) — full macro-recorder parity |

---

## Architecture

The 57 tools split into the cross-platform build123d engine (green) and the SolidWorks COM stack (amber, needs a running SolidWorks).

![Tool tiers](docs/img/tool-tiers.png)

### The core idea: object-handle registry + reflective `sw_call`

The SolidWorks API is thousands of methods across hundreds of interfaces, and almost every interesting one *returns another COM object* (`ISldWorks` → `IModelDoc2` → `IFeatureManager` → `IFeature` …). Rather than wrap each method, the **Tier-0 core**:

1. Keeps live COM objects in a process-global registry keyed by short string ids — the root `app` (= `ISldWorks`), then `doc:1`, `feat:2`, `sketch:3`, … The LLM never sees a raw COM pointer; it sees an id it threads back into the next call.
2. Exposes `sw_call(handle, method, args)`, which invokes **any** method by name (late-bound, no makepy needed). If the return is a COM object, it is auto-registered and its id handed back; otherwise a JSON value is returned.

**This pair alone reaches the entire API.** The 32 Tier-1 wrappers exist only so the common 80% reads naturally — each resolves the right COM object and makes one `sw_call`-style invocation underneath.

![sw_call flow](docs/img/sw-call-flow.png)

<details>
<summary>Code map (where things live)</summary>

| File | Role |
|------|------|
| `src/solidworks_mcp/server.py` | FastMCP server — registers `sw_*` + build123d tools, wraps PNG → image content |
| `src/solidworks_mcp/sw_tools.py` | Base 11 `sw_*` wrappers; then registers the advanced tools |
| `src/solidworks_mcp/sw_advanced_tools.py` | Tier-0/1/2 `@mcp.tool` adapters (generic core + sketch/feature/drawing wrappers + VBA) |
| `src/solidworks_mcp/sw_core.py` | Tier-0 COM core: handle registry, reflective `call`, `get_prop`/`set_prop`, enum, capture, run_vba |
| `src/solidworks_mcp/solidworks_bridge.py` | SolidWorks COM bridge (lazy pywin32, fail-loud, one connection per process) |
| `src/solidworks_mcp/tools.py` | build123d engine: tool logic + part registry + metrics + DRC |
| `src/solidworks_mcp/render.py` | HLR PNG previews (iso + 3 ortho), headless matplotlib |
| `src/solidworks_mcp/sandbox.py` | AST whitelist: blocks os/sys/subprocess/eval/open/dunder |

</details>

---

## Two CAD paths

There are two ways to produce geometry. **Path A** works anywhere and is tested; **Path B** needs a live SolidWorks and is not yet verified against real geometry.

![CAD paths](docs/img/cad-paths.png)

- **Path A (green, works anywhere, tested):** describe a part in code → build123d → STEP → optionally `sw_open` it in SolidWorks.
- **Path B (amber, Windows + live SolidWorks, not yet verified):** drive SolidWorks directly (sketch/feature/drawing tools or `sw_call`) → native `.sldprt` / `.slddrw`.

---

## Install & run

**Requirements:** Python **3.12–3.14**, [uv](https://docs.astral.sh/uv/). For the SolidWorks tools: **Windows + a licensed, running SolidWorks + pywin32**.

```bash
git clone https://github.com/lildebil0/solidworks-mcp
cd solidworks-mcp
uv venv --python 3.12
uv pip install -e ".[solidworks,dev]"     # SolidWorks (pywin32 on Windows) + build123d + test deps
# build123d-only / non-Windows:
# uv pip install -e ".[dev]"
```

Run the server (it speaks MCP over **stdio** — there is no port; the MCP client launches the process):

```bash
solidworks-mcp          # the installed console script
# or, without installing onto PATH:
uv run solidworks-mcp
```

**Enabling / disabling the SolidWorks tools:**

- The `sw_*` tools **register automatically** whenever `pywin32` is importable. Registration does **not** launch SolidWorks; the app is only touched on an actual `sw_*` call (call `sw_connect` first).
- On non-Windows / no pywin32, they **auto-skip** and the build123d tools stay available.
- Set `SOLIDWORKS_MCP_DISABLE=1` to force the build123d-only surface even where pywin32 exists.

---

## Configure in an MCP client

Add this to your MCP client config — Claude Code project `.mcp.json`, or a client's `mcpServers` block (e.g. `claude_desktop_config.json`). Replace `<repo>` with the absolute path to your clone.

```json
{
  "mcpServers": {
    "solidworks-mcp": {
      "command": "uv",
      "args": ["run", "--directory", "<repo>", "solidworks-mcp"]
    }
  }
}
```

Once the package is installed on your `PATH`, you can use the console script directly instead:

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

After adding it, restart the client and confirm the `solidworks-mcp` tools appear.

---

## makepy (early binding)

The reflective core runs **late-bound** by default, so it works on any machine with a running SolidWorks **without** makepy. Generate a typed wrapper only when you hit a method whose **ByRef out-array** parameters do not marshal under late binding (some selection / mass-property queries, certain `Get…` calls), or when you want the **full** `swconst` set resolved by `sw_enum`:

```bash
python -m win32com.client.makepy "SOLIDWORKS 2025 Type Library"
```

Sources for signatures (legal and sufficient): the **SolidWorks Type Library** (ships with SolidWorks) and the official **[API Help](https://help.solidworks.com/)**. Reverse-engineering the SolidWorks binaries is neither used nor needed. Details in [`docs/SW_API.md`](docs/SW_API.md).

---

## Safety

- **`sw_run_vba` is arbitrary local code execution** inside the running SolidWorks process — the same trust level as a user running a macro by hand. That is the intended capability for **local, user-invoked** desktop automation. Do **not** expose this MCP server to untrusted or remote callers; there is no sandbox here.
- **`sw_call` / `sw_set_prop`** can likewise invoke **any** SolidWorks operation, including destructive ones (delete bodies, overwrite files via `SaveAs`). Treat the server as you would the SolidWorks GUI itself.
- The build123d `generate_part` tool runs model-authored Python behind an **AST whitelist** (`sandbox.py`) that blocks `os`/`sys`/`subprocess`/`eval`/`open`/dunder escapes *before* execution. This is a deny-by-default static gate, not a full OS-level sandbox; for untrusted multi-user use, add process isolation + timeouts (see the TODOs in `docs/SW_API.md`).

---

## Development & tests

```bash
uv run python -m pytest
```

Note the `-m`: the current working directory must be on `sys.path`, because two tests do `from tests.test_sw_core import FakeCom`. A bare `pytest` invocation fails those two; `uv run python -m pytest` runs the full **47** green.

The suite is two parts: the build123d engine smoke + sandbox gate (13, which skip cleanly if OCCT is absent), and the mock-COM suites for the SolidWorks generic core and advanced-tool registration/wiring (34, no SolidWorks needed). They verify the registry, marshaling (including nested handles), dispatch routing, enum resolution, error mapping, screenshot→PNG, and VBA temp-file handling — they do **not** assert that a real part/drawing is produced. That is the live sequence in [`docs/SW_API.md`](docs/SW_API.md).

---

## License & attribution

Licensed under the **MIT License** — see [`LICENSE`](LICENSE).

The SolidWorks COM bridge and the full-API core are **original code**; no source was copied verbatim from third-party projects. COM signatures and integration patterns were informed by published documentation and prior open-source work, credited in full in [`NOTICE`](NOTICE):

- **[build123d](https://github.com/gumyr/build123d)** — the code-CAD engine (Apache-2.0).
- **[alisamsam/solidworks-mcp](https://github.com/alisamsam/solidworks-mcp)** (MIT) — studied for the COM connection pattern and ByRef out-parameter handling.
- **[vespo92/SolidworksMCP-TS](https://github.com/vespo92/SolidworksMCP-TS)** (MIT) — studied for COM call signatures (dimensions, export, rebuild, macros).
- The Tier-1 wrapper method signatures come from the official **SOLIDWORKS API Help** (Dassault Systèmes, help.solidworks.com); the object-handle registry and reflective-dispatch design are original.