# ParCAD: open source CAD MCP server for Claude, ChatGPT and Cursor

> Open source CAD your AI drives over MCP. Add mcp.parcad.dev/mcp to Claude, ChatGPT or Cursor, or run it on your own machine. Parts are JavaScript on an OpenCASCADE kernel, measured and checked, and exported as STEP, 3MF or STL for 3D printing.

Experimental, made by Maging Studio. Units are millimetres. AGPL-3.0 or later; the parts you make are yours. Source: https://github.com/ierehon1905/parcad

## Get it

- Your AI · nothing to install: `https://mcp.parcad.dev/mcp`
- macOS · Linux: `brew tap ierehon1905/parcad && brew install parcad`
- Desktop app · Windows, macOS, Linux: [Download from Releases](https://github.com/ierehon1905/parcad/releases)
- Browser · nothing to install: [Open ParCAD web](https://parcad.dev/app/)

## Connect your AI

The hosted MCP server is https://mcp.parcad.dev/mcp. Sign in with GitHub or Google when your client asks.

- Claude (web and desktop): Customize, then Connectors, then Add custom connector. Paste the URL and sign in with GitHub or Google.
- Claude Code: One line, then sign in when /mcp asks.

  ```bash
  claude mcp add --transport http parcad https://mcp.parcad.dev/mcp
  ```
- Codex: Add it, then sign in.

  ```bash
  codex mcp add parcad --url https://mcp.parcad.dev/mcp && codex mcp login parcad
  ```
- ChatGPT, Cursor and other clients: Add a remote MCP server with the URL. The client opens the sign-in page itself.

## The case for it

### Select edges by description

Write what you mean: the circular rims that open onto the top face, the seam where the arm meets the hub. The description keeps matching after you move a hole or add three more.

### A drifted selector stops the build

Add .expect({ count: 4 }) to a selector. If an edit changes what it matches, the build stops and lists every edge it found, with its length and position, so you know what to change.

```text
expected 3 edge(s), but matched 4. The model's topology
changed; inspect the current edges and update the selector
or expectation. The edges matched, shortest first:
  18.84 mm arc at (-18.00, -20.00, 4.00), convex 90°
  18.84 mm arc at (-18.00, 20.00, 4.00), convex 90°
  18.84 mm arc at (18.00, -20.00, 4.00), convex 90°
  18.84 mm arc at (18.00, 20.00, 4.00), convex 90°
```

### One OpenCASCADE model

Your script builds a small graph, and OpenCASCADE turns it into faces and edges. The viewport, the measurements and the STEP file all come from that one solid.

### Every number is measured

Reports read volume, wall thickness, whether two bores meet and the gap between a lid and its base off the built solid. The jar and cap in the picture sit 0.25 mm apart on the thread.

### See inside the part

Cut any part on a plane to check that bores meet and walls keep their thickness. An agent gets the same section views over MCP.

## In code

### Selectors

`bracket.js`:

```js
const plate = box(80, 60, 8).tag("plate");
const wall = box(8, 60, 40).at(-36, 0, 20).tag("wall");

const body = union(plate, wall, { blend: 6 });   // the blend is the fillet
const drilled = body.cut(
  ...grid(2, 2, 36, 40).map(([x, y]) => cylinder(3, 32).at(x, y)),
);

return drilled
  .edges({
    curve: "circle",
    role: "hole",
    adjacentTo: { faceNormal: "+z" },
  })
  .expect({ count: 4 })   // four rims, or the build stops
  .fillet(0.8);
```

- Size: 80 × 60 × 44 mm
- Volume: 55 231.168 mm³
- Bodies: 1
- Watertight: yes

The selector matches the four hole rims on the top face. Move a hole and it matches them again; lose one and the build stops at .expect().

### Two bodies

`spur-gears.js`:

```js
const m = 2;
const pinionTeeth = 20;
const wheelTeeth = 30;
const width = 8;
const backlash = 0.1;
const centres = (m * (pinionTeeth + wheelTeeth)) / 2;

const pinion = extrude(
  spurGearOutline({ module: m, teeth: pinionTeeth, backlash }),
  width,
)
  .cut(cylinder(5 / 2, width * 2))
  .tag("pinion");

const wheel = extrude(
  spurGearOutline({ module: m, teeth: wheelTeeth, backlash }),
  width,
)
  .cut(cylinder(8 / 2, width * 2))
  .rotate("z", 180 / wheelTeeth)
  .at(centres, 0, 0)
  .tag("wheel");

return { pinion, wheel };
```

- Pinion ↔ wheel: clear
- Clearance: 0.094 mm
- Bodies: 2
- Volume: 31 375.868 mm³

0.1 mm of backlash predicts 0.1 · cos 20° = 0.094 mm between the flanks. The kernel measures 0.094 mm.

### Sections

`tools/call · evaluate_part`:

```json
{
  "name": "evaluate_part",
  "arguments": {
    "script": "…examples/manifold-block.js…",
    "views": ["iso"],
    "section": { "axis": "y" }
  }
}
```

- Size: 80 × 50 × 40 mm
- Volume: 145 263.889 mm³
- Cut: y, through the middle
- Watertight: yes

Cut the block on a plane to check that the drilled galleries meet. The cut applies to the picture only.

### Tags

`bracket.js`:

```js
const plate = box(w, d, t).tag("plate");

const wall = box(t, d, wallH)
  .at(-(w - t) / 2, 0, (wallH + t) / 2 - t / 2)
  .tag("wall");

const drilled = body
  .cut(...grid(2, 2, 36, 40).map(([x, y]) => hole.at(x, y)))
  .tag("mount_holes");

return chamferedBase
  .vertices(">X and >Y and <Z")
  .expect({ count: 1 })
  .fillet(2)
  .tag("outer_corner_round");
```

- Tags: 7 in the model
- View: regions: true
- Survives: booleans, fillets, rotations
- Volume: 55 074.791 mm³

A tag names the faces a node made and follows them through booleans, fillets and rotations. Colour by tag to see which feature owns each surface.

### Export

`tools/call · export_part`:

```json
{ "name": "export_part",
  "arguments": { "script": "…examples/flange.js…", "format": "stl" } }

{
  "format": "stl",
  "measured": {
    "bodies": 1,
    "deflection_mm": 0.01,
    "kind": "solid",
    "size": [152.395, 152.398, 25.4],
    "voids": 0,
    "volume_mm3": 296023.409,
    "watertight": true
  }
}
```

- Formats: STEP · 3MF · STL
- Deflection: 0.01 mm
- Volume: 296 023.409 mm³
- Watertight: yes

An ASME B16.5 slip-on flange. The reply measures the file the kernel just wrote.

## For agents

### One URL, nothing to install

Add mcp.parcad.dev/mcp to Claude, ChatGPT, Cursor or Codex and sign in with GitHub or Google. In Claude the part shows up in 3D right in the chat.

```bash
claude mcp add --transport http parcad https://mcp.parcad.dev/mcp
```

[How to connect](https://github.com/ierehon1905/parcad#use-it-from-an-agent)

### Pictures made for reading

Four views at one scale, sections through the inside, and faces coloured by the tag that built them, drawn for a model that reads images.

[What an agent sees](https://github.com/ierehon1905/parcad/blob/main/docs/PERCEPTION.md)

### Or on your own machine

Install with Homebrew and add one line to Claude Code or Codex, or one click in Cursor and VS Code. ParCAD web can also hand your client a link to its tab.

```bash
claude mcp add parcad -- parcad mcp
```

[Setup guide](https://github.com/ierehon1905/parcad#use-it-from-an-agent)

### Tested on small models

Each tool reply goes to a small model over MCP, in both thinking modes. A trial counts as SOUND only when the model reached the right answer by the route the case requires.

[Read the method](https://github.com/ierehon1905/parcad/blob/main/docs/WRITING_FOR_MODELS.md)

## Ways to run it

### Hosted — Free

Add one URL to your AI client and it can build parts. Nothing to install. Sign in with GitHub or Google.

- Claude, ChatGPT, Cursor, Codex or any MCP client
- In Claude, the part in 3D right in the chat
- Your parts in your own account
- Limits on builds and storage per account
- A part unused for 30 days is deleted, so download what you keep

```bash
https://mcp.parcad.dev/mcp
```

### Desktop app — Free

The editor, the viewport and the MCP server in one window. Releases · macOS, Linux, Windows.

- macOS Apple silicon, Linux .deb and .AppImage, Windows .msi
- Every build measures the whole eval corpus before upload
- UI and MCP on 127.0.0.1:4242, shared live with your agent
- Parts are plain .js files you can edit in any editor

[Download](https://github.com/ierehon1905/parcad/releases)

### Headless — Free

The same host without a window, for your browser or your agent. Homebrew, macOS and Linux.

- parcad serve — the whole app at 127.0.0.1:4242
- parcad mcp — stdio for clients that launch servers
- parcad tools and parcad call — every tool from a shell
- brew services start parcad keeps one up from login

```bash
brew tap ierehon1905/parcad && brew install parcad
```

### ParCAD web — Free

The desktop editor and kernel, compiled to WebAssembly, in a browser tab. Nothing to install.

- Every seed part, the op palette, sections and inspection
- Export STEP, 3MF and STL as downloads
- Connect an AI client with a link
- Parts live in that browser's storage
- Heavy parts get 60 s, or up to 600 when an agent asks

[Open in browser](https://parcad.dev/app/)

## Examples

- [ASME B16.5 slip-on flange](https://raw.githubusercontent.com/ierehon1905/parcad/main/examples/flange.js): A bolt circle, and one cut whose provenance reaches five rims. 296 023.409 mm³
- [Spur gear pair, module 2](https://raw.githubusercontent.com/ierehon1905/parcad/main/examples/spur-gears.js): Involute flanks checked against the formula, meshed at their centre distance. 0.094 mm flank gap
- [Twisted star planter](https://raw.githubusercontent.com/ierehon1905/parcad/main/examples/twisted-planter.js): A ruled loft through nine star sections, hollowed along the same twist. 2 bodies, touching
- [Hydraulic manifold](https://raw.githubusercontent.com/ierehon1905/parcad/main/examples/manifold-block.js): Cross-drilled galleries that have to actually intersect. 145 263.889 mm³
- [Screw-top jar, M40 × 3](https://raw.githubusercontent.com/ierehon1905/parcad/main/examples/screw-top-jar.js): A modelled thread on the neck and in the cap. 0.25 mm thread clearance
- [Socket-weld pipe tee](https://raw.githubusercontent.com/ierehon1905/parcad/main/examples/pipe-tee.js): A saddle intersection curve, blended inside and out. 134 874.458 mm³
- [Pleated lampshade](https://raw.githubusercontent.com/ierehon1905/parcad/main/examples/pleated-shade.js): A loft surface through fitted sections, thickened into a wall. 192 × 181 × 199 mm
- [Wash bottle](https://raw.githubusercontent.com/ierehon1905/parcad/main/examples/wash-bottle.js): A spline shoulder, and a spout bored along its own spline. 52 922.598 mm³
- [Knurled knob, D-bore](https://raw.githubusercontent.com/ierehon1905/parcad/main/examples/knurled-knob.js): A D-bore by intersection and 24 flutes. 9 285.196 mm³
- [Rod-end clevis](https://raw.githubusercontent.com/ierehon1905/parcad/main/examples/clevis.js): One fork arm authored, the other mirrored. 27 615.040 mm³
- [Bent hydraulic line](https://raw.githubusercontent.com/ierehon1905/parcad/main/examples/hydraulic-line.js): Straight runs and real bend radii, bored along the same route. 19 057.366 mm³
- [Extruded heat sink](https://raw.githubusercontent.com/ierehon1905/parcad/main/examples/heat-sink.js): One fin shape placed nine times from a single graph node. 44 907.727 mm³

## FAQ

### How do I connect ParCAD to Claude or ChatGPT?

Add https://mcp.parcad.dev/mcp as a connector and sign in with GitHub or Google. In Claude that's Customize, then Connectors, then Add custom connector. Claude Code and Codex take it in one line, shown under Agents above.

Nothing to install. Your parts live in your own account.

### Can an AI design 3D-printable parts with it?

Yes, that's what it's for. The agent writes the part as JavaScript, and ParCAD builds it on an exact kernel and checks it: the sizes you asked for, wall thickness, what it stands on, whether it fits the thing it holds, and whether a hinge or drawer moves without hitting anything.

Export 3MF for Bambu Studio, OrcaSlicer, PrusaSlicer or Cura.

### Is ParCAD the same as PartCAD?

No. PartCAD is a package manager for CAD models. ParCAD is a CAD app and an MCP server, at parcad.dev.

### Is it ready for real parts?

It's experimental: one author, and the DSL still changes. Every operation is checked against measured geometry in the eval corpus, but none of it has had years of use yet.

Measure a part before you machine it.

### How does it compare to CadQuery, build123d and OpenSCAD?

Those projects are older and more mature. ParCAD differs in three ways: selectors describe geometry and check how many edges they match; the viewport, measurements and STEP export come from one B‑rep; and every report carries measured numbers an agent can read.

### What is it for?

Small mechanical parts: brackets, flanges, manifolds, heat sinks, enclosures — things you print or machine one of. Units are millimetres.

### Which agents can use it?

Any MCP client. The hosted server works with Claude, ChatGPT, Cursor, Codex or anything that connects to a URL. On your own machine, parcad mcp works with Claude Code, Codex, Cursor, VS Code and Claude Desktop. Start the agent on read_docs, which returns the whole language in one call.

### What can I export?

STEP for exact surfaces, 3MF for a slicer with each body as its own named object, and STL for a bare mesh. Each export reports the file's size, volume, watertightness and the deflection of every triangle.

### Is it free, and how is it licensed?

Free. The app, the CLI, ParCAD web and the hosted server cost nothing. The hosted server has limits on builds and storage per account.

GNU AGPL-3.0 or later. The parts you make are yours: part scripts and everything ParCAD exports from them can be licensed however you like, and the seed parts are MIT. Releases through v0.0.9 stay MIT or Apache-2.0.

OpenCASCADE and its bindings are LGPL-2.1, so redistributing a binary carries obligations; NOTICE.md spells them out.
