# AnkusDrive

> CLI + MCP server that turns FreeCAD into a mechanical-design workbench for LLM agents — parametric CAD, drawings, FEM/CFD simulation, and manufacturing checks

- **Type:** MCP server
- **Install:** `agentstack add mcp-gchen19-ankusdrive`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [gchen19](https://agentstack.voostack.com/s/gchen19)
- **Installs:** 0
- **Category:** [AI & ML](https://agentstack.voostack.com/c/ai-and-ml)
- **Latest version:** 0.1.0
- **License:** Apache-2.0
- **Upstream author:** [gchen19](https://github.com/gchen19)
- **Source:** https://github.com/gchen19/AnkusDrive
- **Website:** https://pypi.org/project/ankusdrive/

## Install

```sh
agentstack add mcp-gchen19-ankusdrive
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# AnkusDrive

  
    
    
  

A CLI + MCP server that drives [FreeCAD](https://www.freecad.org/) through its Python API so LLMs (and humans at a terminal) can design mechanical parts and run FEM simulations without clicking through the GUI.

## Why

FreeCAD exposes almost everything it does through a Python API — create documents, build sketches, extrude solids, mesh them, run CalculiX/Elmer FEM solves, read back stress/displacement fields. But that API lives inside FreeCAD's embedded Python (`freecadcmd`), which is awkward to call from anywhere else. AnkusDrive wraps it behind two surfaces:

- **CLI** — one-shot commands (`ankusdrive run script.py`, `ankusdrive box --w 10 --d 20 --h 5 -o part.FCStd`) for scripts, CI, and quick iteration.
- **MCP server** — 280+ structured tools (`new_document`, `add_primitive`, `boolean_op`, `pad`, `add_gear`, `fem_new_analysis`, `fem_run`, `fem_results`) so an LLM agent can model, inspect, and simulate iteratively. Beyond core CAD/FEM this now spans a broad **simulation surface** (thermal, CFD/CHT, EM, acoustics, FSI, injection molding, granular/DEM, optics, multibody) and a **design-control layer** (item/part numbers, recipes, variant families, lifecycle/revision, ECO change orders, versioned interfaces).
- **Multi-agent orchestration** — a host-side reference layer that lets a *team* of agents partition one product into components, build them in parallel, and merge the pieces back together with the joints actually fitting (see [Multi-agent design](#multi-agent-design)).

## Target environment

- FreeCAD 1.1.x. The `freecadcmd` binary is auto-discovered per-OS (macOS `.app` bundle, Linux `/usr/bin` etc., **Windows** `C:\Program Files\FreeCAD 1.1\bin\freecadcmd.exe` — version-globbed); override via `$ANKUSDRIVE_FREECADCMD` or rely on PATH. Run `ankusdrive doctor` to see exactly what resolved.
- Bundled Python, `ccx` (CalculiX), and `gmsh` already ship **inside every FreeCAD install** — the macOS `.app`, the Linux package, and the Windows `bin\` — so core CAD + structural FEM work on all three with no extra install.
- Host-side rendering needs `Pillow` and `numpy`; both are installed by AnkusDrive as regular pip deps.
- **One optional exception:** drawing **PDF/SVG** export (`export_drawing`) renders inside FreeCAD's *bundled* Python, so it needs `reportlab` + `svglib` installed **there** — see [Drawing export (PDF/SVG)](#drawing-export-pdfsvg). DXF export and everything else leave FreeCAD's Python untouched.

## Setup

AnkusDrive is a `pip`-installable package; FreeCAD itself is the only thing you
install separately. The host-side dependencies (`mcp`, `Pillow`, `numpy`) come
along with the install. `freecadcmd` is launched as a subprocess and uses its
own bundled Python — AnkusDrive doesn't touch it.

```bash
# 1. Install FreeCAD 1.1.x from https://www.freecad.org/
#    (macOS: drag to /Applications; Linux: distro package or AppImage;
#     Windows: run the installer — default C:\Program Files\FreeCAD 1.1)

# 2. Install AnkusDrive. Pick one:
pipx install ankusdrive                                       # from PyPI — isolated app, `ankusdrive` on PATH
pip install ankusdrive                                        # or into an env you manage yourself
# unreleased main, or for development from a clone:
pipx install git+https://github.com/gchen19/AnkusDrive.git
git clone https://github.com/gchen19/AnkusDrive.git && cd AnkusDrive
python3 -m venv .venv && .venv/bin/pip install -e .         # `.venv/bin/ankusdrive`

# 3. Smoke-test that the worker can reach FreeCAD, and see the full setup report
ankusdrive ping        # → ping=pong freecad=1.1.1
ankusdrive doctor      # per-item FreeCAD + solver checklist with the exact fix each
```

> **On Windows, don't follow the block above by hand** — there is one scripted path
> that does all of it including the MCP registration:
> [Windows quickstart (PowerShell)](#windows-quickstart-powershell).

AnkusDrive is published on PyPI at
[pypi.org/project/ankusdrive](https://pypi.org/project/ankusdrive/); the
distribution roadmap beyond it (marketplace listings, hosted transport) is
tracked in [epic #303](https://github.com/gchen19/AnkusDrive/issues/303); the
original phase plan is kept as a design record at
[`docs/archive/PUBLISHING_PLAN.md`](https://github.com/gchen19/AnkusDrive/blob/main/docs/archive/PUBLISHING_PLAN.md).

### Windows quickstart (PowerShell)

Windows is a first-class target (core CAD + CalculiX FEM run natively against a stock
FreeCAD 1.1 install), and the whole core install is one script — venv, pinned
dependencies, `doctor`, and the MCP registration line with **resolved absolute paths**:

```powershell
# 1. Install FreeCAD 1.1.x from https://www.freecad.org/ (default C:\Program Files\FreeCAD 1.1).
#    Nothing needs to go on PATH — AnkusDrive globs the versioned install dir itself.

# 2. Clone and run the core installer. Windows PowerShell 5.1 is enough; no admin needed.
git clone https://github.com/gchen19/AnkusDrive.git
cd AnkusDrive
powershell -ExecutionPolicy Bypass -File scripts\install-core.ps1
```

That creates `.venv`, installs AnkusDrive with the pins that matter (notably `mcp /tmp/_fcprefix.py
FREECAD_PREFIX="$(freecadcmd /tmp/_fcprefix.py 2>/dev/null | sed -n 's/^DPREFIX=//p')"
FREECAD_PY="$FREECAD_PREFIX/bin/python"      # some builds: $FREECAD_PREFIX/bin/python3

# Pin svglib pycairo, a native build we
# don't use (our drawings are line art, no gradients).
"$FREECAD_PY" -m pip install reportlab "svglib/.local/bin/ankusdrive` (pipx default) or
`/absolute/path/to/AnkusDrive/.venv/bin/ankusdrive` (clone+venv).

**Claude Desktop, one click** — download `ankusdrive-.mcpb` from the
[latest release](https://github.com/gchen19/AnkusDrive/releases/latest) and open it.
Claude Desktop sets up its Python environment with `uv`, so no `pipx` step is needed
— FreeCAD 1.1 still is. The install dialog has one optional field, the FreeCAD
command path, for a FreeCAD that auto-discovery cannot find.

**Claude Code** — register once:

```bash
claude mcp add ankusdrive -- ankusdrive mcp
```

**Other hosts (Cursor, Continue, custom MCP clients)** — same shape: stdio
transport, command = `ankusdrive`, args = `["mcp"]`.

After restarting the host, you should see 280+ `ankusdrive__*` tools become
available. If startup hangs or the host reports a closed connection, run
`ankusdrive ping` directly — that exercises the same worker boot path with
cleaner error messages.

**Tool families (toolsets).** Every tool definition takes up the client's context, and
all 283 come to roughly 114k tokens. Tools are grouped into families you can switch on
and off: `core` (always on), `drawings`, `fem`, `components`, `sheet_metal`, `assembly`,
`intent`, `manufacturing`, `hand_calcs`, `simulation`, `plm`, `rendering`.
- **pip / pipx / uvx / clone:** every family is on unless you set
  `ANKUSDRIVE_TOOLSETS`, e.g. `ANKUSDRIVE_TOOLSETS=drawings,fem,simulation`, or
  `toolsets = "..."` in `config.toml`.
- **Claude Desktop extension:** `core`, `drawings` and `fem` are on by default
  (~31k tokens); turn others on in the extension's settings.

`setup_status` lists the families that are off and exactly how to enable each one.

**`run_script`** executes Python the agent writes, with full access to your files and
processes. It's controlled by `ANKUSDRIVE_ALLOW_RUN_SCRIPT` (env, or `allow_run_script`
in `config.toml`):
- **pip / pipx / uvx / clone:** allowed unless set to `false`.
- **Claude Desktop extension:** **off by default**; turn it on in the extension's
  settings.

When it's off, the tool isn't offered at all, and `setup_status` says how to enable it.

## Simulation solvers & review-video demos

The base install (FreeCAD + `pip install ankusdrive`) covers geometry, the analytic
oracles, and the MCP surface. The heavy simulation families each shell out to an
**external solver**, discovered at runtime by [`ankusdrive/solvers.py`](https://github.com/gchen19/AnkusDrive/blob/main/ankusdrive/solvers.py)
(`$ANKUSDRIVE__PATH` → `PATH` → standard install dirs). A family whose solver is
absent degrades to a clean `{ok: false, reason, install}` dict instead of crashing — check
what currently resolves with **`ankusdrive doctor`** (cross-platform, no server boot needed),
the `solve_capabilities` MCP tool, or the install script's `list`. The install script
installs the pip-wheel solvers and provisions the native ones —
`scripts/install-solvers.sh` on Linux/macOS (apt/conda + source builds), and
[`scripts/install-solvers.ps1`](https://github.com/gchen19/AnkusDrive/blob/main/scripts/install-solvers.ps1) on Windows (pip extras +
portable SU2/Elmer/PrusaSlicer downloads; CalculiX auto-detected from FreeCAD's bundle).

**Persistent config:** every `ANKUSDRIVE_*` path can instead live in
`~/.config/ankusdrive/config.toml` (`%APPDATA%\ankusdrive\config.toml` on Windows;
`ANKUSDRIVE_CONFIG` overrides): `freecadcmd = "..."` at top level, one lowercased key per
solver var under `[solvers]` (`su2_path`, `elmer_path`, `openfoam_bashrc`, ...). Env vars
still win when set; the file is the layer that survives an MCP host's minimal launch
environment. `ankusdrive doctor` reports the file and which layer resolved each value.

**Platform note:** the solver *discovery* layer is fully cross-platform (per-OS install
dirs, Windows `PATHEXT`/`.exe`, env overrides), so `ankusdrive doctor` gives an honest report
on macOS/Linux/Windows. The **pip-wheel** families (MBD, topology, optics, fluids) install
identically everywhere. The **native-binary** families differ by OS — CalculiX ships inside
every FreeCAD install; SU2 and PrusaSlicer have good Windows/macOS binaries; Elmer has a
portable Windows zip but no macOS binaries; the
**OpenFOAM-backed** families (CFD, FSI, injection molding) still rely on a Linux shell +
linker glue and are Linux/WSL/Docker for now. See
[`docs/WINDOWS.md`](https://github.com/gchen19/AnkusDrive/blob/main/docs/WINDOWS.md) and [`docs/MACOS.md`](https://github.com/gchen19/AnkusDrive/blob/main/docs/MACOS.md) for the full
per-solver reality and setup on each OS.

The review-video demos under [`scratch/`](https://github.com/gchen19/AnkusDrive/tree/main/scratch) turn a solver result into a GIF a human
can watch — the **real exported geometry** in motion with the matching oracle overlaid on
the frame (written to `artifacts/`). Each needs its family's solver plus `matplotlib`, and
the CFD one needs `meshio` (on top of the base `numpy`/`Pillow`):

```bash
pip install matplotlib meshio        # frame rendering + reading OpenFOAM's VTK output
```

| Review-video demo (`scratch/…`) | Solver it drives | Install |
|---|---|---|
| `dog_clutch_cad_sim.py` — rigid-body contact via `p.vhacd` | **PyBullet** (pip wheel) | `pip install 'ankusdrive[mbd]'` |
| `meshing_gears_video.py` — MBD gear train | **PyBullet** (pip wheel) | `pip install 'ankusdrive[mbd]'` |
| `modal_shape_video.py` — FEM modal shapes | **CalculiX** `ccx` (FreeCAD FEM) | `apt install calculix-ccx` (Linux); FreeCAD finds `ccx` on `PATH` |
| `thermal_field_video.py` — transient thermal field | **Elmer** | `apt install elmerfem-csc`; ensure `ElmerSolver` on `PATH` (or set `ANKUSDRIVE_ELMER_PATH`) |
| `cfd_field_video.py` — CFD field (lid-driven cavity) | **OpenFOAM** + `meshio` | OpenFOAM via apt/conda, then `source /etc/bashrc` (or set `ANKUSDRIVE_OPENFOAM_BASHRC`); `pip install meshio` |

All of them also use FreeCAD for the geometry/meshing, so run each with the same
interpreter that launches the worker — e.g. `.venv/bin/python3 scratch/cfd_field_video.py`.

### Optics

Two optics engines sit behind the MCP surface, in two licensing/runtime lanes:

| Lane | Tools | Engine | Install |
|---|---|---|---|
| Sequential — lens design + optimization | `optics_lens_design`, `optics_lens_optimize`, `optics_raytrace` | **optiland** / rayoptics (MIT/BSD, in-process) | `pip install 'ankusdrive[optics]'` — or `scripts/install-solvers.sh optics` |
| Non-sequential — tracing through STL solids | `optics_solid_trace` | **KrakenOS** (GPL-3.0, **out-of-process only**) | `pip install 'ankusdrive[optics_gpl]'` — or `scripts/install-solvers.sh optics_gpl` |

The sequential engines import in-process, so install the `optics` extra into the **same
interpreter that launches the worker** (like the other wheels). The non-sequential engine
is GPL-3.0 and is therefore **never imported by AnkusDrive** — it runs in a separate
subprocess ([`ankusdrive/optics_gpl_runner.py`](https://github.com/gchen19/AnkusDrive/blob/main/ankusdrive/optics_gpl_runner.py)), the same
arm's-length boundary used for the GPL Elmer/OpenFOAM binaries. The worker locates a
Python that can import KrakenOS automatically (from where the wheel is installed); override
with `ANKUSDRIVE_OPTICS_GPL_PYTHON=/path/to/python`. Because of that isolation the GPL extra
is **opt-in**: the no-argument `install-solvers.sh` run installs only the permissive
extras and prints how to add `optics_gpl`. Rendered examples for both lanes (lens layout,
spot diagram, optimization, prism TIR, and a ball-lens spherical-aberration study) live in
[`examples/optics_gallery/`](https://github.com/gchen19/AnkusDrive/tree/main/examples/optics_gallery) — regenerate with
`.venv/bin/python examples/optics_gallery.py` (and `…_3d.py`, `optics_ball_lens.py`), or
bootstrap everything in one shot (installs both lanes, then renders every figure):

```bash
scripts/install-solvers.sh --optics-gallery
```

## Architecture sketch

```
 ┌────────────┐      ┌────────────┐      ┌──────────────────────┐
 │  MCP host  │ ───► │ AnkusDrive   │ ───► │  freecadcmd worker   │
 │  (Claude)  │      │ (Python)   │ IPC  │  (long-lived Python) │
 └────────────┘      └────────────┘      └──────────────────────┘
       ▲                    ▲                        │
       │                    │                        ▼
       └── CLI user ────────┘               .FCStd / .inp / .vtk
```

Key decision: **long-lived worker with JSON-over-stdin/stdout**, not subprocess-per-call. FreeCAD startup is ~1–2s; re-paying that per tool call is unacceptable for an interactive agent. The worker is a small Python loop launched under `freecadcmd`, reading commands, dispatching to handlers, returning structured results (including object IDs so follow-up calls can reference created geometry).

## FreeCAD API surface we care about

Notes gathered from the scripting docs and the FEM Python tutorial:

**Core (App):**
- `App.newDocument(name)` / `App.ActiveDocument` / `doc.recompute()` / `doc.save(path)`
- `doc.addObject("Part::Box", "name")` — typed object creation; properties set after (`box.Height = 5`)
- `doc.supportedTypes()` for introspection; `obj.TypeId`, `obj.isDerivedFrom("Part::Feature")`

**Modeling:**
- `Part` — `makeBox`, `makeCylinder`, `makeSphere`, boolean `cut/common/fuse`, fillets, lofts (OpenCASCADE under the hood)
- `Draft` — 2D primitives, `move`, arrays
- `Sketcher` + `PartDesign` — parametric sketch-driven solids (most "real" mechanical design happens here)
- `FreeCAD.Vector`, `Placement` for positioning

**FEM (`ObjectsFem` + `femtools`):**
- `ObjectsFem.makeAnalysis(doc, "Analysis")` — container
- `makeSolverCalculixCcxTools` / `makeSolverElmer` — solver objects with tunables (`GeometricalNonlinearity`, `ThermoMechSteadyState`, …)
- `makeMaterialSolid` — assign `YoungsModulus`, `PoissonRatio`, `Density`
- Constraints: `makeConstraintFixed`, `makeConstraintForce`, `makeConstraintPressure`, `makeConstraintDisplacement`, contact/tie/spring, thermal
- Mesh: `makeMeshGmsh` + `femmesh.gmshtools.GmshTools(...).create_mesh()` (or Netgen)
- Run: `femtools.ccxtools.FemToolsCcx().run()`
- Results: iterate `analysis.Group` for `Fem::FemResultObject`; read `.DisplacementVectors`, stress fields

**Headless invocation:**
- `freecadcmd script.py` — runs script then exits
- `freecadcmd` with no args — interactive Python REPL (what the worker will drive)
- `--console`, `-M `, `-P `, `--pass `, `FreeCAD.ConfigGet(...)` for env info
- `FreeCADG

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [gchen19](https://github.com/gchen19)
- **Source:** [gchen19/AnkusDrive](https://github.com/gchen19/AnkusDrive)
- **License:** Apache-2.0
- **Homepage:** https://pypi.org/project/ankusdrive/

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** yes
- **Shell / process execution:** yes
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-gchen19-ankusdrive
- Seller: https://agentstack.voostack.com/s/gchen19
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
