ParCAD
MCPB · PARCAD-MCP-X86_64-UNKNOWN-LINUX-GNU.MCPB · 3 COMPONENTS · SCANNED OCT 3
Parametric CAD as code: model 3D-printable parts on an exact B-rep kernel, measured.
How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. How we score → Why this is hard to score →
Supply Chain Security0
- No malware scan is available for this kind of package: the supply-chain vendors we use do not cover it. This is a permanent gap in our coverage, not a finding about the package.Unverified
- Known CVEs could not be checked: we found no dependency list to check in this bundle: either it runs a compiled binary, whose bundled manifests we do not read, or none of the package.json, requirements.txt, pyproject.toml or uv.lock files it ships for its runtime declares a dependency we can read (a requirements.txt that only points at a setup.py project, a local path, or a nested requirements file we cannot follow counts as none).Unverified
- Install-script risk not yet assessed.Unverified
- Dependency health could not be checked: we found no dependency list to check in this bundle: either it runs a compiled binary, whose bundled manifests we do not read, or none of the package.json, requirements.txt, pyproject.toml or uv.lock files it ships for its runtime declares a dependency we can read (a requirements.txt that only points at a setup.py project, a local path, or a nested requirements file we cannot follow counts as none).Unverified
Provenance & Transparency45
- Source repository is publicly reachable at the declared URL. View diagnostics → Pass
- Provenance check failed: no build-provenance attestation is published. See how to fix → View diagnostics → Fail
- Clear OSI-approved license (AGPL-3.0-or-later).Pass
- Actively maintained (last published 6 days ago).Pass
- Disclosure check failed: no security disclosure policy was found in the source repository. See how to fix → Fail
Schema Quality & AI Usability74
- 100% of prompts and resources have a non-trivial description (not blank, and not just the item's name).Pass
- AI-judged instruction clarity (excellent).Pass
- Context-footprint check failed: tool/resource definitions use about 11720 tokens (~558/item across 21 items; 20 tools + 1 resources), over budget; trim descriptions and params. See how to fix → Fail
- Usage-examples check failed: none of the tools include examples. See how to fix → Fail
Stability & Change Management0
- Stability not yet verified: not enough scan history yet (needs a 30-day window).Unverified
Tool Coverage100
- 100% of tools have a non-trivial description (not blank, and not just the tool's name).Pass
- 100% of tool parameters carry a description.Pass
- Structured output schemas are declared (75% of tools); any adoption earns full credit.Pass
Tool Safety50
- Injection-marker check failed: the description of tool "set_script" contains an instruction to conceal the call from the user, the text "Do not tell the user", at byte 1402 of that field. See how to fix → Fail
- We read all 20 captured tool definition(s), and no name or description among them implies an irreversible operation.Pass
- An AI judge read all 22 captured unit(s) of tool text and found none that tries to manipulate the model reading it.Pass
Capabilities100
- Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.Pass
- Supports UI / widget rendering.Pass
Unverified: 2 categories
Categories scored 0 because we could not verify them: a data source with nothing on this package, evidence we could not reach, or a check we could not run. We only credit what we can confirm.
How do I install the ParCAD MCP server?
ParCAD ships as an MCPB bundle, a single file you download and open in an MCP host that supports MCPB bundles, such as Claude Desktop. The host reads the launch command from the bundle's own manifest, so there is no command to copy. The MCP registry declares no SHA-256 for this bundle, so there is no published digest to check the download against.
mcpb · parcad-mcp-x86_64-unknown-linux-gnu.mcpb
Download bundleThe MCP registry declares no SHA-256 for this bundle, so there is no published digest to check it against. Open it with an MCPB-capable host such as Claude Desktop.
Every change we have recorded for this component, newest first. Security-relevant changes are always shown. ▲ marks a change for the better, ▼ a change for the worse; unmarked changes are neutral.
- 28 Sept 26 0
- We updated how we score, so this day's move reflects our rubric, not a change to the server See what changed → functional
- 27 Sept 26 37
First indexed and scored.
Diagnostic detail from the automated scan of this channel: what the scanner observed at each step, so you can see exactly where a check passed or failed. It is informational only and never changes the trust score.
Captured 3 Oct 2026 · Analysed mcpb/https://github.com/ierehon1905/parcad/releases/download/v0.0.11/parcad-mcp-x86_64-unknown-linux-gnu.mcpb
Provenance No attestation
The registry publishes no build provenance for this version, so there is nothing to verify.
| Result | No attestation |
|---|---|
| Ecosystem | mcpb |
| Reason | No attestation published |
Background: How many MCP packages publish verified provenance →
The tools this component advertises to a client, with an estimated token cost for each. Expand a tool to see its parameters and schema. The per-tool counts are indicative and are not scored directly; the schema's total context footprint is one signal in Schema Quality & AI Usability. A tool's description is untrusted text the model reads on every call, which is what makes this list a security surface and not just an inventory: how tool poisoning works →
check_fit Check the fit ~503
Lay a reference object against a part and measure how they sit, on the two exact solids: `verdict` is clear, touching or interfering; `interference_mm3` is the material the two share, which is what would have to be cut away for the object to fit, and `depth_mm` at `deepest_mm` is how far one reaches into the other — the number to read, since a volume is not a depth; `clearance_mm` and `closest_mm` say how much room there is and where, when they do not overlap, and `contact_mm2` over `contact_patches` patches says how much of a face they share when they touch, which is what tells a seat from a corner. This is the question 'does the laptop fit in its holder' or 'does the lid clear the boss', and neither a render nor arithmetic on the script can answer it — the script says what was asked for and this measures what was built. Both arguments are scripts. The reference is usually one line placing a body from the DEVICES table, e.g. `return device("macbook-pro-16").at(0, 0, 18.4)`, or any shape drawn where the object sits. A holder is right when the reference is `clear` by about the clearance it was drawn with, and wrong when it `interfering` — the depth and where it is deepest say by how much. When both objects are bodies of one part — `return { holder, laptop }` — evaluate_part already measures the pair in `between_bodies`, with the same verdict and numbers, and no second call is needed.
| Name | Type | Req | Description |
|---|---|---|---|
| edits | array | – | Changes to make to the part before building, in order, each { old, new } replacing text that appears exactly once; nothing is written back. |
| project | string|null | – | The part as saved, instead of sending it: a path as list_projects spells it, or "@session" for the script on the user's screen. |
| reference | string | yes | The object laid against it, as a parcad script placed where it sits — usually one line, e.g. `return device("macbook-pro-16").at(0, 0, 18.4)`. |
| script | string|null | – | The part, as a parcad script. Give this or `project`, not both. |
No output schema declared.
No examples provided.
check_selector Check a selector ~99
Parse a directional selector such as '>Z and >Y and |X' and report the exact error and character span if it is wrong. Cheap: it runs the kernel's own parser and touches no geometry.
| Name | Type | Req | Description |
|---|---|---|---|
| kind | string|null | – | `edge` (default) or `vertex`. Vertex selectors accept directional extrema only. |
| selector | string | yes | A selector to check, such as `>Z and >Y and |X`. |
| Name | Type | Req | Description |
|---|---|---|---|
| error | string|null | – | – |
| ok | boolean | yes | – |
| span | array|null | – | Byte range of the offending term, for pointing at it. |
No examples provided.
edit_part Edit a part in place ~795
Change part of a script without sending the whole thing: each edit replaces `old` with `new`, once, and the part is rebuilt and measured exactly as evaluate_part does — same reply, same views — then saved. `project` names the part to edit, or "@session" for the script on the user's screen. An `old` that appears twice, or not at all, is refused naming how many times it was found and where, and nothing is written: give more surrounding lines. The edited text is built before anything is written, so a change that does not build is refused and the part is left as it was. The previous text is kept as a snapshot (list_snapshots, restore_snapshot), so an edit is undoable, and an edit to the open part lands in the window's own undo history: the reply then carries `on_screen` with the revision and `viewers`, as set_script's does. A saved part that is also open on screen is put on screen too. Use it for every change after the first: a fillet radius, a dimension, one function — sending 10 KB of unchanged script to change two lines is the most common way a session runs out of room. To try a change without saving it, call evaluate_part with the same `project` and `edits`. The reply adds `edits_applied`, the new `script_sha256`, and for a saved part the `path` written and the `snapshot` kept; pass a reply's `script_sha256` back as `expect_sha256` to be refused if the text changed under you. An edit that writes part.js is refused when the edited text fails its `print_check` (material under 0.3 mm) or one of the part's own `checks`, naming the finding or the check and its measurement, unless `allow_failing` gives the user's reason; an edit to "@session" changes only the screen and is never refused for a verdict — the window shows it red.
| Name | Type | Req | Description |
|---|---|---|---|
| allow_failing | string|null | – | Write the part although one of its own `checks` fails, for this reason — the user's decision, in their words. Without it a failing check refuses an edit that writes part.js, naming the check and what… |
| edits | array | yes | Each { old, new }, applied in order to the text as the previous edit left it. `old` must appear exactly once. |
| expect_sha256 | string|null | – | Refuse unless the part's current text still hashes to this — the `script_sha256` a previous reply reported — so an edit written against text the user has since changed is refused rather than applied.… |
| image_size | integer|null | – | Pixels per side, 128 to 1024, as evaluate_part's. Defaults to 512. |
| materials | boolean|null | – | Draw each face in its `.material()`, as evaluate_part's. |
| project | string | yes | The part to edit, as list_projects spells it — 'Mounts/bracket' — or "@session" for the script on the user's screen. |
| regions | boolean|null | – | Colour each view by the tag that owns the surface, as evaluate_part's. |
| section | – | – | Cut the part open on a plane for the views, as evaluate_part's. |
| timeout_s | number|null | – | Seconds the kernel may take, 1 to 600, as evaluate_part's. |
| views | array|null | – | Also draw the edited part, as evaluate_part's `views`: `iso`, `front`, `back`, `left`, `right`, `top`, `bottom`. Omit to measure only. |
No output schema declared.
No examples provided.
evaluate_part Build and measure a part ~3,259
Build a part from a parcad DSL script and report its measured geometry, opening with `print_check` — the thinnest wall between its two features, every cut into a feature it was not for (`grille` cuts `boss`), each body's overhang as it prints (up its `.printedUp()` axis, or +z as drawn), `failed` where nothing prints (under 0.3 mm), `flagged` for what prints but should be read — then size, volume, area, face and edge counts, mesh quality, `bodies` (free-standing pieces: one for a part; more is pieces drawn together, which watertightness does not catch) and `voids` (closed surfaces inside it, a shell's cavity), tags, and `stands_on` — the surface in the part's lowest plane and how many separate patches it is in. A part that is meant to be several solids — a base and its lid, a clamp in two halves — returns an object of named shapes, `return { base, lid }`, and the reply then carries `named_bodies`: each body measured alone (size, bounds, volume, faces, `watertight`, `pieces` — 1 when that body is intact, more when its own booleans left it split, the defect the part-level `bodies` cannot tell from a second body that was meant) and `between_bodies`: every pair measured on the exact solids, `clear` with a `clearance_mm` and the two `closest_mm` points, `touching` with the `contact_mm2` they share over `contact_patches` patches, or `interfering` with the mm³ they share and the `depth_mm` one reaches into the other at `deepest_mm`. Read the depth and the contact, not the verdict: `interfering` by 0.002 mm³ along a rim is a graze two microns deep, not a catch, and `touching` is the same word for a face seated over 2800 mm² and for two corners that meet at 0 mm². Read `between_bodies` for whether a lid clears its base or a clip is drawn through what it clips onto; for such a part `bodies` should equal the number of named bodies. Bodies are never fused, and selectors, tags and treatments work inside one body only. A part may carry its own rules — `checks: [{ clear: ["lid",…
| Name | Type | Req | Description |
|---|---|---|---|
| edits | array | – | Changes to make before building, in order, each { old, new } replacing text that appears exactly once. Nothing is written back — this is "what if the wall were 1.2 mm" in one call; edit_part is the t… |
| image_size | integer|null | – | Pixels per side, 128 to 1024. Defaults to 512. |
| materials | boolean|null | – | Draw each face in the material the script gave it with `.material()` instead of neutral grey. Off by default: grey keeps shape and shading easiest to read, and the snapshot's `materials` says whether… |
| project | string|null | – | The part to build instead of sending it, as list_projects spells it — 'Mounts/bracket' — or "@session" for the script on the user's screen. Costs no script to send, and reuses the build a save or an… |
| regions | boolean|null | – | Colour each view by the tag that owns the surface, instead of shading it. The reply then names every tag's colour and its share of the visible surface — every tag in the model, with the ones hidden f… |
| script | string|null | – | A parcad DSL script. It must end by returning a shape, e.g. `return body.cut(hole)`, or an object of named shapes for a part that stays in several bodies, e.g. `return { base, lid }`. Units are milli… |
| section | – | – | Cut the part open on a plane before drawing it, so the views show the inside. Nothing about the part changes — this is how it is drawn, not an operation on it. |
| timeout_s | number|null | – | Seconds the kernel may take, 1 to 600. Defaults to 20, or PARCAD_OCCT_TIMEOUT. A part that timed out can be asked again with more; a build that finishes is kept, so the next call on the same script —… |
| views | array|null | – | Also draw the part, from these viewpoints: `iso`, `front`, `back`, `left`, `right`, `top`, `bottom`. Omit to measure without rendering, which is much faster. Every view shares one framing, so a featu… |
No output schema declared.
No examples provided.
export_part Export a part to a file ~951
Export a part and return the absolute path written. `format` is `3mf` for printing — what Bambu Studio, OrcaSlicer, PrusaSlicer and Cura open, with every body its own named object in millimetres — `stl` for a bare mesh any tool reads, or `step` for exact surfaces, for another CAD program or a machine shop. Files are written to the parcad export directory; the filename must have no directory part. The reply's `measured` describes the part in the file, off the same build that wrote it: size, volume, `watertight`, `bodies`, `voids`, and for 3MF and STL the `deflection_mm` every triangle is within. Reuses the build of an earlier evaluate_part on the same script; `timeout_s` gives a heavy part longer. A part that returns several bodies (`return { base, lid }`) is written whole by default — one object per body in 3MF, one solid per body in STEP, every body's triangles merged into one STL, where a slicer can no longer tell them apart — and `measured.named_bodies` then measures each body in the file. Pass `body: "lid"` to write that one body alone. A `.reference()` body is never in the file and cannot be asked for by name. `open: true` also hands the file to the application this machine opens that extension with, so a 3MF lands in the user's slicer with no path to find: use it when the user wants to print or look at the part now, not for every export. `opened` says whether the system took the file; `open_error` says why not and what to tell the user. The path is written either way. STL and 3MF describe closed solids and refuse a part with a surface body, naming `.thicken(t)`; STEP carries surfaces exactly. A part whose `print_check` fails — material under 0.3 mm, where nothing prints — or that carries its own `checks` and fails one is refused, with the finding or the check and its measurement named, and nothing is written: fix the part, or, when the user has decided the failure is acceptable, pass `allow_failing` with their reason, which the reply keeps. The reply opens…
| Name | Type | Req | Description |
|---|---|---|---|
| allow_failing | string|null | – | Write the file although one of the part's own `checks` fails, for this reason — the user's decision, in their words. Without it a failing check refuses the export, naming the check and what was measu… |
| body | string|null | – | For a part that returns several bodies (`return { base, lid }`): the name of the one body to write on its own, e.g. `lid`. Omit to write every body into one file — an object per body in 3MF, a solid… |
| edits | array | – | Changes to make before building, in order, each { old, new } replacing text that appears exactly once; nothing is written back to the part. |
| filename | string|null | – | File name to write, without any directory part. Defaults to `part.3mf` / `part.stl` / `part.step`. |
| format | string | yes | `3mf` for a slicer, `stl` for a bare mesh, or `step` for exact surfaces. |
| open | boolean | – | Open the written file in the application this machine opens its extension with — a 3MF lands in the user's slicer. Only when the user asked to see or print the part now. |
| project | string|null | – | The part to export instead of sending it, as list_projects spells it, or "@session" for the script on the user's screen. |
| script | string|null | – | A parcad DSL script ending in a returned shape. Give this or `project`, not both. |
| timeout_s | number|null | – | Seconds the kernel may take, 1 to 600. Defaults to 20, or PARCAD_OCCT_TIMEOUT. Reuses the build of an earlier evaluate_part on the same script when there is one. |
| Name | Type | Req | Description |
|---|---|---|---|
| allow_failing | string|null | – | The reason the file was written over a failing verdict, as given. |
| brief | – | – | What the part is for, judged on this build — or, with no `brief()` in the script, the one line saying its size is measured against nothing. Absent only for a surface, which has neither size nor volum… |
| bytes | integer | yes | – |
| checks | – | – | The part's own checks, judged on this build; absent when the script carries none. |
| downloaded | boolean|null | – | In ParCAD web: true when the user's browser was given the file to download, which is the only copy they can reach. |
| format | string | yes | – |
| measured | – | yes | The part in the file, measured off the build that wrote it: size, volume, `watertight`, `bodies`, `voids`, and for STL the mesh `deflection_mm`. A file with watertight false, or with more bodies than… |
| open_error | string|null | – | Why the file could not be handed to an application, and what to do. |
| opened | boolean|null | – | Present when `open` was asked: true when the system accepted the file for the application it opens this extension with. The file is written either way. |
| path | string | yes | – |
| print_check | – | – | Whether the part prints; absent for a surface. |
| script_sha256 | string | yes | – |
No examples provided.
get_session Read the open editor ~242
Read the live session: which project is open in the parcad window and the script as it currently stands in the editor, including anything the user has typed since you last looked. Call this before editing — the on-screen script may differ from the file on disk, and editing from a stale copy silently reverts the user's work. `name` is null until something is opened; `revision` increases with every change. The editor pushes its document a moment after typing stops, so the very last keystrokes can lag by about half a second. `viewers` is what each open window is actually drawing, as the window reported it: the `revision` it last evaluated, whether that `built`, the `error` if not, and the `volume_mm3` it measured. A window below the session's revision has not caught up; one with built: false is still drawing an older part beside that error. An empty list means no window is open, so nobody is looking. A viewer over 30 seconds old is marked `stale` and is not evidence the user is looking at anything; one silent for 300 seconds is left out.
Input schema present but exposes no named parameters.
| Name | Type | Req | Description |
|---|---|---|---|
| name | string|null | yes | The open project's path, as `list_projects` spells it. `null` until something is opened. |
| origin | string | yes | The viewer that made this change: a window's own random id, or [`AGENT_ORIGIN`] for an edit that arrived over MCP. A viewer ignores events carrying its own id. |
| revision | integer | yes | Bumped on every real change. Two viewers holding the same revision are showing the same text. |
| script | string | yes | The script as the originating viewer last showed it. This is the document being typed, not the file on disk — saving is separate. |
| viewers | array | yes | One entry per open window that has evaluated something. A window whose `revision` is below the session's has not caught up; one with `built` false is drawing an older part beside an error; one marked… |
No examples provided.
inspect_treatment_target Show what a fillet will act on ~192
Show exactly which edges a fillet or chamfer will act on, resolved against the shape before that treatment runs. Takes a node index from evaluate_part's treatments list. Also reports tags whose edge set is exactly this target, which are stable selectors you can use in the script.
| Name | Type | Req | Description |
|---|---|---|---|
| edits | array | – | Changes to make before building, in order, each { old, new } replacing text that appears exactly once; nothing is written back. |
| node | integer | yes | The intent-graph node of the treatment to resolve, as reported in `treatments` by `evaluate_part`. |
| project | string|null | – | The part to build instead of sending it, as list_projects spells it, or "@session" for the script on the user's screen. |
| script | string|null | – | A parcad DSL script ending in a returned shape. Give this or `project`, not both. |
| Name | Type | Req | Description |
|---|---|---|---|
| edge_count | integer | yes | How many edges this treatment applies to. `expect({ count })` in the script asserts this, and a changed count then fails loudly. |
| edges | array | yes | – |
| equivalent_tags | array | yes | Tags whose live edge set is *exactly* this target. These are authored references: `{ generatedBy: tag }` selects the same edges and keeps selecting them as the model changes. |
| node | integer | yes | – |
| script_sha256 | string | yes | – |
| vertex_count | integer | yes | – |
No examples provided.
list_entities List a part's edges and faces ~338
List what a part is made of, as text rather than a picture: its visible edges with their centres, directions and lengths, and its faces with what each one is (plane, cylinder, cone, sphere, torus), its exact area, a point on it, its outward normal or axis, and the faces it touches. For a part in several named bodies each edge and face also says which `body` it is on. Use the edges to work out which directional or topological selector picks the edges you mean. Use the faces to work out the *shape* of the part without looking at it — `adjacent` is the half that carries it, because a plane at z=44 could be the top of a plate or the floor of a pocket and what it borders is what tells them apart. A cylindrical face bordering two planes is a through hole; bordering one is a blind one. The returned edge@N and face@N ids describe one evaluation and must never appear in a script — there is no face selector in the DSL, so a face is something to read, and the way to act on one is the edges around it.
| Name | Type | Req | Description |
|---|---|---|---|
| edits | array | – | Changes to make before building, in order, each { old, new } replacing text that appears exactly once; nothing is written back. |
| project | string|null | – | The part to build instead of sending it, as list_projects spells it, or "@session" for the script on the user's screen. |
| script | string|null | – | A parcad DSL script ending in a returned shape. Give this or `project`, not both. |
| Name | Type | Req | Description |
|---|---|---|---|
| edges | array | yes | Visible edge curves of the evaluated part. `id` is valid for this evaluation only and is never accepted as an authored reference — use it to work out a directional or topological selector, not to sto… |
| faces | array | yes | The part's faces, with what each one is and what it touches. |
| script_sha256 | string | yes | – |
| total_edges | integer | yes | How many edges the part has, when `edges` was truncated. |
| total_faces | integer | yes | How many faces the part has, when `faces` was truncated. |
No examples provided.
list_projects List projects ~99
List the parts in parcad's project folder. This is the same folder the desktop app and the user see, so anything listed here can be opened in the app, and anything saved here shows up in it. Paths are slash-separated: a part inside a folder is listed as 'Mounts/bracket', and that whole string is the name every other project tool takes. Parts that ship with parcad are seeded into this folder and are ordinary projects.
Input schema present but exposes no named parameters.
| Name | Type | Req | Description |
|---|---|---|---|
| directory | string | yes | The folder itself, so a person can be pointed at it. |
| projects | array | yes | Every project in the shared folder, as slash-separated paths — a part in a folder reads `Mounts/bracket`. Includes the parts parcad seeded on first run, which have no special status. |
No examples provided.
list_snapshots List a project's earlier versions ~140
List the earlier versions of a project's script that parcad kept, newest first: one is kept automatically before save_project overwrites part.js, and one before set_script replaces the script on screen — including text the user typed and never saved. Each has an `id`, the `path` of a plain .js file, its size and its first line. Use restore_snapshot to put one back on screen; the 50 newest are kept per project.
| Name | Type | Req | Description |
|---|---|---|---|
| name | string | yes | A project path exactly as `list_projects` gives it: slash-separated folder names and no extension, such as `bracket` or `Mounts/bracket`. |
| Name | Type | Req | Description |
|---|---|---|---|
| name | string | yes | – |
| snapshots | array | yes | Newest first. Each is a plain `.js` file at `path`. |
No examples provided.
measure_wall_thickness Find the thinnest wall ~1,063
Find the thinnest material anywhere in the part, and where it is. Use this before saying a part is ready to print, cast or mill, and any time you cut a pocket, a bore or a shell into something — it is the check that catches a wall you thinned without meaning to. Unlike probe_part it needs no guess about where to look: it reads every edge, searches every pair of faces for thin material between them, and measures from thousands of points over the whole surface, and reports the worst. The thickness at a point is the diameter of the largest ball that fits inside the material touching the surface there — the wall thickness a moulder or a print check means. Through a slanted wall it is the distance across the wall, not along any line: a 2 mm slab tilted 30° reads 2.0 here and 2.31 straight down with probe_part. Use this for how thick a wall is, probe_part for how much material a particular line crosses. Reports `thinnest` — the thickness in mm, the point, and `surface_of` and `opposite_surface_of`, the tags of the two faces the material lies between, which is what tells you *which* wall is thin. Pass `threshold_mm` (the process minimum, e.g. 1.2 for a print) and it also reports `below_threshold`, how many samples failed it, plus `thin_spots`: every thin sample grouped into the place it belongs to, with its `kind`, `samples` and `extent_mm`, so a pocket floor thin all over and one thin corner are different entries. Read `kind` first. `feather` is a sliver: real material that thins to a knife edge where two faces meet at a shallow angle, what a cut leaves when it grazes another feature. Its `thickness_mm` is 0 because the material really does run out to nothing along that edge — it is the thinnest material in the part, not a measuring artefact and not an `edge` reading — with `wedge_deg` the angle and `extent_mm` the stretch that sharp. It will not print or cast cleanly and is almost never intended, so fix it or say why it stays. `wall` is two faces that do not meet — a…
| Name | Type | Req | Description |
|---|---|---|---|
| edits | array | – | Changes to make before building, in order, each { old, new } replacing text that appears exactly once; nothing is written back. |
| max_samples | integer|null | – | How many surface points the sweep measures from, 200 to 100000; the default, 6000, puts one at most about every hundredth of the part's diagonal, and the reply's `sample_spacing_mm` says how far apar… |
| project | string|null | – | The part to build instead of sending it, as list_projects spells it, or "@session" for the script on the user's screen. |
| script | string|null | – | A parcad DSL script ending in a returned shape. Give this or `project`, not both. |
| threshold_mm | number|null | – | What counts as too thin, in mm — the process minimum, such as 1.2 for a typical print or 2.5 for a casting. Without it only the thinnest place is reported and nothing is counted. |
| timeout_s | number|null | – | Seconds the kernel may take to build and sweep the part, 1 to 600. Defaults to 20, or PARCAD_OCCT_TIMEOUT. |
| Name | Type | Req | Description |
|---|---|---|---|
| below_threshold | integer | yes | How many samples were at or below `threshold_mm`, edges not counted — the number that separates one bad spot from a wall that is thin everywhere. |
| below_threshold_at_edges | integer | yes | Samples at or below `threshold_mm` that only read thin beside a sharp edge. |
| discarded | integer | yes | – |
| note | string | yes | What the number is, and what is certain about it: which thin places are always found, and which only as finely as `sample_spacing_mm`. |
| sample_spacing_mm | number | yes | Every point of every face is within this of a sample on the same face: how wide a thin place the sweep alone can miss, where the searches in `note` do not reach. |
| samples | integer | yes | Surface points measured, and points skipped as unusable. A sweep that discarded most of what it sampled is a weaker answer, and says so. |
| script_sha256 | string | yes | – |
| surfaces_skipped | array | – | Named bodies left out because they are surfaces, which have no material to be thick. |
| thin_spots | array | – | With a threshold: every thin sample grouped into the place it belongs to, feathers and walls thinnest first, then up to three edges. Without one: the thinnest samples, spread across the part. |
| thinnest | – | – | The thinnest place found that is not an edge reading — an edge only when the part has nothing else. Absent only when nothing was measurable, which for a real part means something is wrong with the sw… |
| threshold_mm | number|null | – | Echoed back, because "0 below threshold" is meaningless without it. |
| units | string | yes | – |
No examples provided.
open_project Show a part on the user's screen ~360
Show the user a part: open a project on the screen they are watching — the parcad app, or the ParCAD web page in their browser — loaded from disk, exactly as if they had picked it, in every open window. To show a part you have built, save it with save_project under a name of its own and open that; the part that was open is left as it was. Takes a path from list_projects. Returns the session without the loaded script: `script_chars` and `script_sha256` identify the text every window took, `script: true` asks for it, and read_project has it anyway. Use this before set_script when the part you want to change is not the one on screen — get_session tells you which that is. Like set_script, the reply waits for a window to report evaluating it and carries `viewers`: tell the user the part is on screen only when one reports it built. A viewer over 30 seconds old is marked `stale` and is not evidence the user is looking at anything; one silent for 300 seconds is left out, and is not waited for.
| Name | Type | Req | Description |
|---|---|---|---|
| name | string | yes | A project path exactly as `list_projects` gives it: slash-separated folder names and no extension, such as `bracket` or `Mounts/bracket`. |
| script | boolean | – | Also return the loaded script. Off by default: the reply identifies it by `script_chars` and `script_sha256`, and read_project has the text. |
| wait_s | number|null | – | How long to wait, in seconds, for a window to report that it evaluated the opened part. 0 to 60; defaults to 20. |
| Name | Type | Req | Description |
|---|---|---|---|
| name | string|null | yes | The open project's path, as `list_projects` spells it. |
| origin | string | yes | – |
| revision | integer | yes | The session revision this change made; a viewer at or past it shows it. |
| script | string|null | – | The script itself, only when `script: true` asked for it. |
| script_chars | integer | yes | Characters in the script now on screen. |
| script_sha256 | string | yes | The first 12 hex digits of the SHA-256 of the script now on screen, which is how a caller checks the text every window took is the one it meant without reading it back. |
| viewers | array | yes | What each open window is drawing, as in get_session. |
No examples provided.
probe_part Probe a part along rays and points ~499
Measure a part along rays and at points instead of looking at it. This is the tool for every question of the form 'is there material here', 'how thick is that', 'does this hole break through', 'do these two bores meet' — a render cannot settle any of them, and neither can arithmetic on the script: the script says what was asked for, and this says what was built. Reach for it before you reason from a dimension in the source. Each point reports `medium`, either "material" or "void", plus the distance to the nearest surface (negative in material). Each ray reports every crossing in order, each with the `medium` it passed `into` and `surface_of`, the tag of the node whose surface that face belongs to — read those names down the list and they name the features the line went through, which is how you tell two voids that meet from two that do not. Also `solid_mm`, and `first_solid_mm`, which is a wall thickness, measured. A ray that reports no crossings at all crossed nothing but void: that is a positive result, not a failed measurement. Everything is measured on the exact solid — every fillet and chamfer is in it, and a distance near a corner is the true distance — so there is nothing left out to allow for. For a part in several bodies each crossing and point also says which `body`. On a surface, which has no inside, a point is never `material`: its `distance_mm` is to the surface, and a ray lists every place it passes through the surface as a crossing into `void`.
| Name | Type | Req | Description |
|---|---|---|---|
| edits | array | – | Changes to make before building, in order, each { old, new } replacing text that appears exactly once; nothing is written back. |
| points | array | – | Points to test for material, in mm. |
| project | string|null | – | The part to build instead of sending it, as list_projects spells it, or "@session" for the script on the user's screen. |
| rays | array | – | Lines to measure along. |
| script | string|null | – | A parcad DSL script ending in a returned shape. Give this or `project`, not both. |
| timeout_s | number|null | – | Seconds the kernel may take to build the part, 1 to 600. Defaults to 20, or PARCAD_OCCT_TIMEOUT. |
| Name | Type | Req | Description |
|---|---|---|---|
| points | array | yes | – |
| rays | array | yes | – |
| script_sha256 | string | yes | – |
| units | string | yes | – |
No examples provided.
probe_step_export Measure a STEP file ~704
Measure a STEP file exported from another CAD system — Fusion 360, SolidWorks, FreeCAD — so the part in it can be recreated as a parcad script against numbers instead of an impression. Takes the file's absolute path on this machine. Every value in the reply is measured off the file's own B-rep by the exact kernel; nothing is inferred from the file name, and nothing is echoed from a request. The reply lists `solids`, each with exact `volume_mm3` and `area_mm2`, `bbox_min`/`bbox_max`, and `face_types` — a tally such as {"plane": 18, "nurbs": 12} that says at a glance what kind of geometry the body is made of. A file can hold several solids; recreating one of them is not recreating the document, so check the count and say which body a script reproduces. `free_faces` counts faces that belong to no solid — a file that is all free faces holds surface bodies, and there is no solid to recreate. By default each solid also carries `faces`: the surface of each (`plane` with origin and outward `normal`; `cylinder`, `cone`, `sphere`, `torus` with axis and radii; `nurbs` with degrees, knots and the full `poles` grid) and its boundary `wires`, edges in traversal order so each edge's `b` is the next edge's `a`. A wire whose edges are all straight lines also carries `polygon` — its vertices in order, which is a section outline an `extrude` or `loft` can take almost verbatim. Pass detail: "summary" for the solids without faces, the right first look at an unfamiliar file. Reading a loft target: a `nurbs` wall whose `poles` grid is 2 by 2 is ruled — four corner points fully determine it, and a parcad `loft` through matching sections rebuilds the identical surface (vertex pairing is by outline index, so a section listed a quarter turn on authors a twisted wall). Bigger pole grids are fitted surfaces; hold a recreation to volume, area and bounding box rather than pole-for-pole equality. Reading a curved profile: a revolved or extruded wall's profile is one row of its `poles` grid. W…
| Name | Type | Req | Description |
|---|---|---|---|
| detail | string|null | – | `faces` (the default) includes every face's surface geometry and boundary loops; `summary` stops at per-solid volume, area, bounding box and face-type counts. |
| path | string | yes | Absolute path of the .step / .stp file to measure, on the machine parcad runs on. |
No output schema declared.
No examples provided.
read_docs Read parcad's own documentation ~671
Read parcad's own documentation. Call this before writing your first script: `dsl` is the complete language reference — every function, method and constant, with signatures and what each one means — generated from the DSL source, so nothing it has can be missing from it. The alternative is learning the language from example parts, and that has been measured: a session that read two of them built its part out of boxes and cylinders, recorded `mirror` and lofts as impossible when both ship, and never found revolve, cone, ngon, polar, repeat, countersink, counterbore, tapDrill or clearance. The parts it wrote were a function of which files it happened to open. The other topics are prose, and each is cited by name inside the seeded parts' own comments: `gaps` is what the language cannot express and what to write instead; `gotchas` is the list of shapes that make the kernel return a plausible wrong answer or die — a blended union of two solids that only touch on a face, an offset that silently drops a body, a fillet that grows the part; `operations` is which operations exist, which are deliberately absent, and why. Read `gaps` and `gotchas` before a part with blends, offsets or shells in it: most failed calls are in there already, described from the other side. A topic too long for one reply — `dsl` is one, and so is `gotchas` — answers first with its contents, not the document: every section by name, and the name of every entry in it. `section` in that reply says `contents`, and `sections` lists the section names. Call read_docs again with the same `topic` and `section` set to one of those names to read that section whole, or to one entry's name — `holeFor`, `Shape.mirror`, `SectionEntry`; a bare method name like `mirror` also works — to read just that entry. Reading every section in `sections` is reading the whole document; nothing is left out of them. A topic that fits in one reply comes back whole, with no `section`. Entries give the rules and an example; `detail…
| Name | Type | Req | Description |
|---|---|---|---|
| detail | boolean | – | Add the reasons and history behind each rule. Leave it out: the default is the rules themselves, and is what writing a part needs. |
| section | string|null | – | One part of a topic too long for a single reply. Leave it out first: a long topic then answers with its contents, which names every section and every entry. Pass a section name from there to read tha… |
| topic | string|null | – | Which document: `dsl` (the default) is the language reference; `gaps` is what the language cannot express; `gotchas` is what silently returns a wrong answer; `operations` is what exists and what is d… |
| Name | Type | Req | Description |
|---|---|---|---|
| section | string|null | – | Which part of the topic `text` is: `contents` for the index of a topic too long for one reply, a section or entry name when one was asked for, absent when `text` is the whole document. |
| sections | array | yes | Every section of this topic, in order, when it is too long for one reply; reading each of them is reading the whole document. Empty when the topic arrives whole. Always sent: the output schema requir… |
| source | string | yes | The file in the parcad repository this text comes from. |
| text | string | yes | – |
| topic | string | yes | – |
| topics | array | yes | Everything else that can be read, so one call is enough to find the rest. Only on a topic's first reply; a section leaves it empty. |
No examples provided.
read_project Read a project ~145
Return the DSL source of one project. The seeded parts are worth reading before writing your own: they are the same files the eval corpus measures, so they always run. On disk a project is usually a '<name>.parcad' folder whose 'part.js' is the source this returns; a README.md beside it describes the part in prose. A loose '<name>.js' file is also a project. Either way, use the path from list_projects rather than a filename.
| Name | Type | Req | Description |
|---|---|---|---|
| name | string | yes | A project path exactly as `list_projects` gives it: slash-separated folder names and no extension, such as `bracket` or `Mounts/bracket`. |
| Name | Type | Req | Description |
|---|---|---|---|
| name | string | yes | – |
| script | string | yes | – |
No examples provided.
restore_snapshot Restore an earlier version ~136
Put a kept version of a project back in the editor, as an ordinary edit the user can undo. Opens the project first if another one is on screen. Like set_script it changes the screen only — call save_project to write it — keeps the current text as a snapshot first, and waits for a window to report showing it.
| Name | Type | Req | Description |
|---|---|---|---|
| id | string | yes | The snapshot's `id`, from `list_snapshots`. |
| name | string | yes | The project path, as `list_projects` gives it. |
| wait_s | number|null | – | How long to wait for a window to show it, as in `set_script`. |
| Name | Type | Req | Description |
|---|---|---|---|
| name | string|null | yes | The open project's path, as `list_projects` spells it. `null` until something is opened. |
| origin | string | yes | The viewer that made this change: a window's own random id, or [`AGENT_ORIGIN`] for an edit that arrived over MCP. A viewer ignores events carrying its own id. |
| revision | integer | yes | Bumped on every real change. Two viewers holding the same revision are showing the same text. |
| script | string | yes | The script as the originating viewer last showed it. This is the document being typed, not the file on disk — saving is separate. |
| viewers | array | yes | One entry per open window that has evaluated something. A window whose `revision` is below the session's has not caught up; one with `built` false is drawing an older part beside an error; one marked… |
No examples provided.
save_project Save project ~387
Write a new part to parcad's project folder so the user can open it; open_project it afterwards to put it on their screen. For a part that is already saved, call edit_part instead: it changes the lines you name, rebuilds, and saves in one call, without the whole script being sent again. Evaluate a script first: saving one that does not build leaves the user a broken file. Replaces an existing project at the same path; a new one is created as a '<name>.parcad' folder, and naming a path like 'Mounts/bracket' files it under a folder, creating the folder if needed. The reply says whether the script `built` (the `error` if not — the file is saved regardless) and the `snapshot` of the version it replaced, which list_snapshots and restore_snapshot can bring back. A part that builds and fails its `print_check` (material under 0.3 mm, where nothing prints) or one of its own `checks` is not saved: the refusal names the finding or the check and its measurement; fix the part, or pass `allow_failing` with the user's reason, which the reply keeps beside the verdicts it opens with.
| Name | Type | Req | Description |
|---|---|---|---|
| allow_failing | string|null | – | Save although one of the part's own `checks` fails, for this reason — the user's decision, in their words. Without it a failing check refuses the save, naming the check and what was measured; with it… |
| name | string | yes | The project path to write: slash-separated folder names and no extension, such as `bracket` or `Mounts/bracket`. Folders are created as needed. An existing project at that path is replaced. |
| script | string | yes | The DSL source to save. |
| Name | Type | Req | Description |
|---|---|---|---|
| allow_failing | string|null | – | The reason the part was saved over a failing verdict, as given. |
| brief | – | – | What the part is for, judged on this build — or, with no `brief()` in the script, the one line saying its size is measured against nothing. Absent only for a surface, which has neither size nor volum… |
| built | boolean | yes | Whether the saved script builds in the exact kernel. |
| checks | – | – | The part's own checks, judged on this build; absent when the script carries none. |
| error | string|null | – | Why it does not, when it does not. The file is saved either way. |
| name | string | yes | – |
| path | string | yes | – |
| print_check | – | – | Whether the part prints; absent for a surface. |
| snapshot | string|null | – | The previous `part.js`, kept before it was replaced; see `list_snapshots`. |
No examples provided.
set_script Replace the script on screen ~459
Replace the whole script of the project open on the user's screen. For a change to that part — a dimension, a radius, one function — call edit_part with project "@session" instead: it sends only the lines that change, builds them first, and lands on screen the same way; set_script is for a script that is new from the first line. To show them a different part, save it with save_project and open it with open_project, or its text lands in the open project and a save writes it there. The change appears in every window immediately and lands in the editor's normal undo history, so the user can Cmd-Z it back like their own typing — there is no lock, and you must not wait for one. It edits the screen only: nothing is written to disk until the user saves or you call save_project. Evaluate the script first with evaluate_part; putting a script that does not build in front of the user replaces their working part with an error. Read get_session first and base your edit on the script it returns, or you will silently revert what the user typed since you last looked. The reply waits (up to `wait_s`, default 20 s) until a window reports evaluating this revision, and its `viewers` says what each window showed: built with which `volume_mm3`, or the `error` it hit. It does not echo the script you sent: `script_chars` and `script_sha256` identify what landed, and get_session returns it whole. Do not tell the user the part is on screen unless a viewer reports this `revision` with built: true. Setting the same script again makes every window evaluate it again — the way to recover a window that is showing something stale.
| Name | Type | Req | Description |
|---|---|---|---|
| script | string | yes | The DSL source to put on screen, whole — this replaces the open document, it does not append to it. |
| wait_s | number|null | – | How long to wait, in seconds, for a window to report that it evaluated this revision. 0 to 60; defaults to 20. The reply comes as soon as one does, or when the time is up with `viewers` saying where… |
| Name | Type | Req | Description |
|---|---|---|---|
| name | string|null | yes | The open project's path, as `list_projects` spells it. |
| origin | string | yes | – |
| revision | integer | yes | The session revision this change made; a viewer at or past it shows it. |
| script | string|null | – | The script itself, only when `script: true` asked for it. |
| script_chars | integer | yes | Characters in the script now on screen. |
| script_sha256 | string | yes | The first 12 hex digits of the SHA-256 of the script now on screen, which is how a caller checks the text every window took is the one it meant without reading it back. |
| viewers | array | yes | What each open window is drawing, as in get_session. |
No examples provided.
view_part Draw a part in the chat ~141
Only for parcad's in-chat 3D viewer, which calls it itself with the project an open_project call opened: it returns that build's mesh as binary arrays, which are no use to read. To build, measure or look at a part, call evaluate_part.
| Name | Type | Req | Description |
|---|---|---|---|
| project | string|null | – | The project to draw, as an open_project reply's `name` spells it, or "@session" for the script on the user's screen. |
| script | string|null | – | The script to draw, whole. Give this or `project`. |
| timeout_s | number|null | – | Seconds the kernel may take, as evaluate_part's. |
No output schema declared.
No examples provided.
What is the ParCAD MCP server?
ParCAD is an MCP server listed in the public MCP registry as io.github.ierehon1905/parcad. Parametric CAD as code: model 3D-printable parts on an exact B-rep kernel, measured. This page covers its MCPB bundle (https://github.com/ierehon1905/parcad/releases/download/v0.0.11/parcad-mcp-x86_64-unknown-linux-gnu.mcpb).
Is the ParCAD MCP server safe to use?
ParCAD scores 37 out of 100 on VerifyMCP. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.
What tools does the ParCAD MCP server expose?
ParCAD exposes 20 tools: check_fit, check_selector, edit_part, evaluate_part, export_part, and 15 more. Their descriptions and schemas cost roughly 11,183 tokens of context every time the server is loaded.
What licence is the ParCAD MCP server under?
ParCAD declares the AGPL-3.0-or-later licence, which is OSI-approved. That covers the source only, and says nothing about the cost of any service it calls.