@vcad/mcp 0.9.4-main.38 → 0.9.4-main.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/index.mjs +116 -8
- package/package.json +3 -3
- package/vcad_kernel_wasm_bg.wasm +0 -0
package/README.md
CHANGED
|
@@ -6,4 +6,4 @@ vcad's MCP server as a self-contained bundle (server + BRep kernel WASM).
|
|
|
6
6
|
{ "mcpServers": { "vcad": { "command": "npx", "args": ["-y", "@vcad/mcp"] } } }
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
Built from
|
|
9
|
+
Built from 08cd95d4487b522463d0a1a3b58b84935a1f7d08 at 2026-07-26T13:56:33.334Z. Source: https://github.com/ecto/vcad
|
package/index.mjs
CHANGED
|
@@ -177,6 +177,7 @@ __export(vcad_kernel_wasm_exports, {
|
|
|
177
177
|
exprEvaluate: () => exprEvaluate,
|
|
178
178
|
exprParse: () => exprParse,
|
|
179
179
|
feaAnalyzeMesh: () => feaAnalyzeMesh,
|
|
180
|
+
feaCheckBeam: () => feaCheckBeam,
|
|
180
181
|
generate3mf: () => generate3mf,
|
|
181
182
|
generate3mfWithGcode: () => generate3mfWithGcode,
|
|
182
183
|
generateGcode: () => generateGcode,
|
|
@@ -1925,6 +1926,15 @@ function feaAnalyzeMesh(spec_json, options_json, positions, indices) {
|
|
|
1925
1926
|
}
|
|
1926
1927
|
return takeFromExternrefTable0(ret[0]);
|
|
1927
1928
|
}
|
|
1929
|
+
function feaCheckBeam(case_json) {
|
|
1930
|
+
const ptr0 = passStringToWasm0(case_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
1931
|
+
const len0 = WASM_VECTOR_LEN;
|
|
1932
|
+
const ret = wasm.feaCheckBeam(ptr0, len0);
|
|
1933
|
+
if (ret[2]) {
|
|
1934
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
1935
|
+
}
|
|
1936
|
+
return takeFromExternrefTable0(ret[0]);
|
|
1937
|
+
}
|
|
1928
1938
|
function generate3mf(name, vertices, indices, settings_json) {
|
|
1929
1939
|
const ptr0 = passStringToWasm0(name, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
1930
1940
|
const len0 = WASM_VECTOR_LEN;
|
|
@@ -11526,6 +11536,7 @@ var init_dist = __esm({
|
|
|
11526
11536
|
evaluateDocument: wasmModule7.evaluateDocument,
|
|
11527
11537
|
evalVcadSource: wasmModule7.evalVcadSource,
|
|
11528
11538
|
evalVcadSourceWithModules: wasmModule7.evalVcadSourceWithModules,
|
|
11539
|
+
evalVcadSourceParametric: wasmModule7.evalVcadSourceParametric,
|
|
11529
11540
|
documentParameterGradient: wasmModule7.documentParameterGradient,
|
|
11530
11541
|
getPartsManifest: wasmModule7.getPartsManifest,
|
|
11531
11542
|
buildPart: wasmModule7.buildPart,
|
|
@@ -12230,6 +12241,22 @@ var init_dist = __esm({
|
|
|
12230
12241
|
const json = this.kernel.evalVcadSourceWithModules(source, JSON.stringify(modules));
|
|
12231
12242
|
return JSON.parse(json);
|
|
12232
12243
|
}
|
|
12244
|
+
/**
|
|
12245
|
+
* Evaluate loon source, returning the document alongside any parametric
|
|
12246
|
+
* warnings — intent the bridge could *not* preserve, such as a declared
|
|
12247
|
+
* parameter that ends up driving no geometry, or a field whose dependence
|
|
12248
|
+
* on a parameter is not affine and so keeps its literal.
|
|
12249
|
+
*
|
|
12250
|
+
* The document is identical to {@link evalVcadSourceWithModules}; only the
|
|
12251
|
+
* authoring feedback is extra. Returns null on kernels predating the
|
|
12252
|
+
* parametric loon forms, so callers can fall back.
|
|
12253
|
+
*/
|
|
12254
|
+
evalVcadSourceParametric(source, modules = {}) {
|
|
12255
|
+
if (!this.kernel.evalVcadSourceParametric)
|
|
12256
|
+
return null;
|
|
12257
|
+
const json = this.kernel.evalVcadSourceParametric(source, Object.keys(modules).length ? JSON.stringify(modules) : void 0);
|
|
12258
|
+
return JSON.parse(json);
|
|
12259
|
+
}
|
|
12233
12260
|
/** Evaluate a preview extrusion without adding to document */
|
|
12234
12261
|
evaluateExtrudePreview(origin, xDir, yDir, segments, direction) {
|
|
12235
12262
|
if (segments.length === 0)
|
|
@@ -40963,6 +40990,26 @@ var init_CHANGELOG = __esm({
|
|
|
40963
40990
|
"rendering"
|
|
40964
40991
|
]
|
|
40965
40992
|
},
|
|
40993
|
+
{
|
|
40994
|
+
id: "2026-07-26-parametric-loon-datums",
|
|
40995
|
+
version: "0.9.4",
|
|
40996
|
+
date: "2026-07-26",
|
|
40997
|
+
category: "feat",
|
|
40998
|
+
title: "Named parameters, datums and stacks in loon",
|
|
40999
|
+
summary: "Values named with [defparam] survive into the document and are settable with set_parameters; [datum-plane]/[stack] make shared planes and packing clearances named entities instead of repeated literals.",
|
|
41000
|
+
features: [
|
|
41001
|
+
"loon",
|
|
41002
|
+
"parameters",
|
|
41003
|
+
"datums",
|
|
41004
|
+
"assemblies"
|
|
41005
|
+
],
|
|
41006
|
+
mcpTools: [
|
|
41007
|
+
"create_cad_loon",
|
|
41008
|
+
"list_parameters",
|
|
41009
|
+
"set_parameters",
|
|
41010
|
+
"parameter_gradient"
|
|
41011
|
+
]
|
|
41012
|
+
},
|
|
40966
41013
|
{
|
|
40967
41014
|
id: "2026-07-26-loon-mirror-symmetry",
|
|
40968
41015
|
version: "0.9.4",
|
|
@@ -48729,9 +48776,45 @@ function createCadLoon(input, engine) {
|
|
|
48729
48776
|
return { content: [{ type: "text", text: text2 }] };
|
|
48730
48777
|
}
|
|
48731
48778
|
const text = format === "json" ? JSON.stringify(doc, null, 2) : toVCode2(doc);
|
|
48732
|
-
|
|
48733
|
-
|
|
48734
|
-
};
|
|
48779
|
+
const content = [{ type: "text", text }];
|
|
48780
|
+
const note = parametricNote(source, modules, engine, doc);
|
|
48781
|
+
if (note) content.push({ type: "text", text: note });
|
|
48782
|
+
return { content };
|
|
48783
|
+
}
|
|
48784
|
+
function parametricNote(source, modules, engine, doc) {
|
|
48785
|
+
const names = Object.keys(doc.parameters ?? {}).sort();
|
|
48786
|
+
if (!names.length) return null;
|
|
48787
|
+
const lines = [];
|
|
48788
|
+
const value = (n) => doc.parameters[n].value;
|
|
48789
|
+
const bound = new Set(
|
|
48790
|
+
Object.values(doc.bindings ?? {}).flatMap(
|
|
48791
|
+
(expr) => typeof expr === "string" ? expr.match(/[A-Za-z_]\w*/g) ?? [] : []
|
|
48792
|
+
)
|
|
48793
|
+
);
|
|
48794
|
+
const base = names.filter((n) => typeof value(n) === "number");
|
|
48795
|
+
const derived = names.filter((n) => typeof value(n) === "string");
|
|
48796
|
+
if (base.length) {
|
|
48797
|
+
lines.push(
|
|
48798
|
+
`Parameters (${base.length}, settable): ${base.map((n) => bound.has(n) ? n : `${n} (drives nothing)`).join(", ")}`
|
|
48799
|
+
);
|
|
48800
|
+
}
|
|
48801
|
+
if (derived.length) {
|
|
48802
|
+
lines.push(
|
|
48803
|
+
`Derived (${derived.length}, follow from the above): ${derived.map((n) => `${n} = "${value(n)}"`).join(", ")}`
|
|
48804
|
+
);
|
|
48805
|
+
}
|
|
48806
|
+
const datums = Object.keys(doc.datums ?? {}).sort();
|
|
48807
|
+
if (datums.length) lines.push(`Datums (${datums.length}): ${datums.join(", ")}`);
|
|
48808
|
+
if (base.length) {
|
|
48809
|
+
lines.push("Change any settable parameter with set_parameters \u2014 no re-authoring needed.");
|
|
48810
|
+
}
|
|
48811
|
+
let warnings = [];
|
|
48812
|
+
try {
|
|
48813
|
+
warnings = engine.evalVcadSourceParametric(source, modules)?.warnings ?? [];
|
|
48814
|
+
} catch {
|
|
48815
|
+
}
|
|
48816
|
+
for (const w of warnings) lines.push(`- ${w}`);
|
|
48817
|
+
return lines.join("\n");
|
|
48735
48818
|
}
|
|
48736
48819
|
var createCadLoonSchema, toolDefs2;
|
|
48737
48820
|
var init_loon = __esm({
|
|
@@ -48793,7 +48876,7 @@ var init_loon = __esm({
|
|
|
48793
48876
|
{
|
|
48794
48877
|
name: "create_cad_loon",
|
|
48795
48878
|
pack: null,
|
|
48796
|
-
description: 'The preferred authoring tool for whole parts and multi-feature models \u2014 one call, full vocabulary. Create a CAD document from loon source code. Loon is a Lisp-like language for parametric CAD \u2014 the FULL modeling vocabulary (patterns, sketches, extrude/revolve/sweep/loft, assemblies) is available here even where no dedicated MCP tool exists. For incremental single-node edits to an open session, use create/update/delete instead.\n\nPrimitives: [cube x y z], [cylinder r h], [sphere r], [cone r-bottom r-top h], [torus major-r minor-r], [wedge x y z], [prism sides radius height]\nBooleans (subject-last): [difference tool subject], [union other subject], [intersection other subject]\nTransforms (subject-last): [translate x y z s], [rotate rx ry rz s], [scale sx sy sz s], [mirror ox oy oz nx ny nz s] (plane through the origin point with that normal) \u2014 plus the axis sugar [mirror-x s] / [mirror-y s] / [mirror-z s], which mirror through the origin, negating that one coordinate. NEVER hand-mirror by negating coordinates; use these.\nFeatures: [fillet r s], [chamfer d s], [shell t s]\nPatterns (subject-last): [linear-pattern dx dy dz count spacing s], [circular-pattern ox oy oz ax ay az count angle s] \u2014 e.g. a bolt circle is [circular-pattern 0 0 0 0 0 1 6 360 bolt-hole]\nSymmetric patterns (subject-last): [mirror-pattern nx ny nz s] and its sugar [mirror-pattern-x s] / -y / -z union a solid with its mirror image (a left/right pair in one expression, so the halves can\'t drift apart); [quad-pattern s] is the 4-fold X-and-Y version \u2014 a quadruped\'s legs, a 4-post frame, a vehicle chassis\nSketches: [sketch ox oy oz xx xy xz yx yy yz #[segments]] with [line x1 y1 x2 y2] and [arc x1 y1 x2 y2 cx cy ccw]\nSketch ops (sketch-last): [extrude dx dy dz sk], [revolve aox aoy aoz adx ady adz angle sk], [sweep-line sx sy sz ex ey ez sk], [sweep-helix radius pitch height turns sk], [loft #[sk1 sk2 \u2026]], [loft-closed #[sk1 sk2 \u2026]]\nAssemblies: [assembly #[parts] #[instances] #[joints] ground-id] with [part name solid "material"], [instance name part-name x y z], [revolute-joint \u2026], [prismatic-joint \u2026], [fixed-joint \u2026], [ball-joint \u2026]\nAssembly symmetry: author ONE side as an assembly, then [mirror-group-x "-r" side] (or -y / -z) returns it plus a mirrored, suffixed copy \u2014 parts reflected, placements and joint anchors mirrored, and joint axes flipped by the correct rule (a hinge across its own mirror normal keeps its axis; the other two flip), so the same joint state drives both sides symmetrically. Splice it back with [assembly-join chassis mirrored]. NEVER hand-mirror an assembly.\nPipe: [pipe [cube 50 30 5] [difference [cylinder 3 10]] [fillet 1.0]]\nLet bindings: [let body [cube 50 30 5]]\nScene: [root solid "material-name"], with [material name r g b metallic roughness] to define one\nModules: [use bracket] then [bracket.plate] \u2014 multi-file projects work here, with sources passed in `modules` (or read from `base_dir`); [use bracket :as b] aliases, [use bracket [plate]] imports selectively, and `pub` in a module picks what it exports',
|
|
48879
|
+
description: 'The preferred authoring tool for whole parts and multi-feature models \u2014 one call, full vocabulary. Create a CAD document from loon source code. Loon is a Lisp-like language for parametric CAD \u2014 the FULL modeling vocabulary (patterns, sketches, extrude/revolve/sweep/loft, assemblies) is available here even where no dedicated MCP tool exists. For incremental single-node edits to an open session, use create/update/delete instead.\n\nPrimitives: [cube x y z], [cylinder r h], [sphere r], [cone r-bottom r-top h], [torus major-r minor-r], [wedge x y z], [prism sides radius height]\nBooleans (subject-last): [difference tool subject], [union other subject], [intersection other subject]\nTransforms (subject-last): [translate x y z s], [rotate rx ry rz s], [scale sx sy sz s], [mirror ox oy oz nx ny nz s] (plane through the origin point with that normal) \u2014 plus the axis sugar [mirror-x s] / [mirror-y s] / [mirror-z s], which mirror through the origin, negating that one coordinate. NEVER hand-mirror by negating coordinates; use these.\nFeatures: [fillet r s], [chamfer d s], [shell t s]\nPatterns (subject-last): [linear-pattern dx dy dz count spacing s], [circular-pattern ox oy oz ax ay az count angle s] \u2014 e.g. a bolt circle is [circular-pattern 0 0 0 0 0 1 6 360 bolt-hole]\nSymmetric patterns (subject-last): [mirror-pattern nx ny nz s] and its sugar [mirror-pattern-x s] / -y / -z union a solid with its mirror image (a left/right pair in one expression, so the halves can\'t drift apart); [quad-pattern s] is the 4-fold X-and-Y version \u2014 a quadruped\'s legs, a 4-post frame, a vehicle chassis\nSketches: [sketch ox oy oz xx xy xz yx yy yz #[segments]] with [line x1 y1 x2 y2] and [arc x1 y1 x2 y2 cx cy ccw]\nSketch ops (sketch-last): [extrude dx dy dz sk], [revolve aox aoy aoz adx ady adz angle sk], [sweep-line sx sy sz ex ey ez sk], [sweep-helix radius pitch height turns sk], [loft #[sk1 sk2 \u2026]], [loft-closed #[sk1 sk2 \u2026]]\nAssemblies: [assembly #[parts] #[instances] #[joints] ground-id] with [part name solid "material"], [instance name part-name x y z], [revolute-joint \u2026], [prismatic-joint \u2026], [fixed-joint \u2026], [ball-joint \u2026]\nAssembly symmetry: author ONE side as an assembly, then [mirror-group-x "-r" side] (or -y / -z) returns it plus a mirrored, suffixed copy \u2014 parts reflected, placements and joint anchors mirrored, and joint axes flipped by the correct rule (a hinge across its own mirror normal keeps its axis; the other two flip), so the same joint state drives both sides symmetrically. Splice it back with [assembly-join chassis mirrored]. NEVER hand-mirror an assembly.\nPipe: [pipe [cube 50 30 5] [difference [cylinder 3 10]] [fillet 1.0]]\nLet bindings: [let body [cube 50 30 5]] \u2014 note these are inlined and do NOT survive into the document; use [defparam ...] for a value you want to change later\nParameters (survive into the document and are settable afterwards with set_parameters, and differentiable with parameter_gradient): [defparam pitch_axis_x 310.0], [defparam wall "bore * 0.2"] for derived values, plus optional :unit/:min/:max/:description. Names must be identifier-safe (underscores, not dashes)\nDatums \u2014 named reference geometry, so two parts cannot each hold their own copy of a shared plane: [datum-plane "femur_inner" y 131.0], [datum-axis "pitch" x 0 0 310], [datum-point "hip" 0 0 310], read back with [datum "femur_inner"], [datum+ "femur_inner" 3.0] (3 mm outboard), [datum-x/-y/-z "pitch"]\nStacks \u2014 declarative packing, where each running clearance is a named value instead of an arbitrary number: [stack y "leg" 131.0 [lane "femur_inner" 5.0] [gap "idler_run" 1.0] [lane "idler_boss" 3.0]] declares datum planes leg_femur_inner_lo/_hi, leg_idler_boss_lo/_hi and leg_end; widening leg_idler_run slides everything outboard of it\nScene: [root solid "material-name"], with [material name r g b metallic roughness] to define one\nModules: [use bracket] then [bracket.plate] \u2014 multi-file projects work here, with sources passed in `modules` (or read from `base_dir`); [use bracket :as b] aliases, [use bracket [plate]] imports selectively, and `pub` in a module picks what it exports',
|
|
48797
48880
|
inputSchema: createCadLoonSchema,
|
|
48798
48881
|
handler: async (args, ctx) => {
|
|
48799
48882
|
const useLoons = Array.isArray(args.use_loons) ? args.use_loons : void 0;
|
|
@@ -58029,6 +58112,18 @@ function listParameters(input) {
|
|
|
58029
58112
|
);
|
|
58030
58113
|
return jsonResult({ count: parameters.length, parameters });
|
|
58031
58114
|
}
|
|
58115
|
+
function referencedNames(doc) {
|
|
58116
|
+
const out = /* @__PURE__ */ new Set();
|
|
58117
|
+
const harvest = (expr) => {
|
|
58118
|
+
if (typeof expr !== "string") return;
|
|
58119
|
+
for (const v of expr.match(/[A-Za-z_]\w*/g) ?? []) out.add(v);
|
|
58120
|
+
};
|
|
58121
|
+
for (const expr of Object.values(doc.bindings ?? {})) harvest(expr);
|
|
58122
|
+
for (const c of doc.constraints ?? []) {
|
|
58123
|
+
for (const v of Object.values(c)) harvest(v);
|
|
58124
|
+
}
|
|
58125
|
+
return out;
|
|
58126
|
+
}
|
|
58032
58127
|
async function setParameters(input, engine) {
|
|
58033
58128
|
const args = input ?? {};
|
|
58034
58129
|
const documentId = String(args.document_id ?? "");
|
|
@@ -58058,6 +58153,18 @@ async function setParameters(input, engine) {
|
|
|
58058
58153
|
`Unknown parameter(s): ${unknown2.join(", ")}. Use list_parameters to see declared names.`
|
|
58059
58154
|
);
|
|
58060
58155
|
}
|
|
58156
|
+
const referenced = referencedNames(doc);
|
|
58157
|
+
const noEffect = entries.map(([name]) => name).filter((name) => !referenced.has(name)).map((name) => {
|
|
58158
|
+
const value = doc.parameters[name].value;
|
|
58159
|
+
const inputs = typeof value === "string" ? [...new Set(value.match(/[A-Za-z_]\w*/g) ?? [])].filter(
|
|
58160
|
+
(v) => v in doc.parameters && referenced.has(v)
|
|
58161
|
+
) : [];
|
|
58162
|
+
return {
|
|
58163
|
+
name,
|
|
58164
|
+
reason: typeof value === "string" ? `derived (${JSON.stringify(value)}) \u2014 no field is bound to it` : "no field is bound to it",
|
|
58165
|
+
...inputs.length ? { set_instead: inputs } : {}
|
|
58166
|
+
};
|
|
58167
|
+
});
|
|
58061
58168
|
const changed = [];
|
|
58062
58169
|
for (const [name, value] of entries) {
|
|
58063
58170
|
const param = doc.parameters[name];
|
|
@@ -58079,6 +58186,7 @@ async function setParameters(input, engine) {
|
|
|
58079
58186
|
document_id: documentId,
|
|
58080
58187
|
updated: changed.length,
|
|
58081
58188
|
changed,
|
|
58189
|
+
...noEffect.length ? { no_effect: noEffect } : {},
|
|
58082
58190
|
...constraintSolve ? { constraint_solve: constraintSolve } : {}
|
|
58083
58191
|
});
|
|
58084
58192
|
result.structuredContent = { changed };
|
|
@@ -80215,8 +80323,8 @@ var init_server3 = __esm({
|
|
|
80215
80323
|
init_order_feed();
|
|
80216
80324
|
init_animate();
|
|
80217
80325
|
PKG_VERSION = (() => {
|
|
80218
|
-
if ("0.9.4-main.
|
|
80219
|
-
return "0.9.4-main.
|
|
80326
|
+
if ("0.9.4-main.39") {
|
|
80327
|
+
return "0.9.4-main.39";
|
|
80220
80328
|
}
|
|
80221
80329
|
try {
|
|
80222
80330
|
const req = createRequire2(import.meta.url);
|
|
@@ -80225,8 +80333,8 @@ var init_server3 = __esm({
|
|
|
80225
80333
|
return "0.0.0";
|
|
80226
80334
|
}
|
|
80227
80335
|
})();
|
|
80228
|
-
BUILD_SHA = "
|
|
80229
|
-
BUILD_TIME = "2026-07-26T13:
|
|
80336
|
+
BUILD_SHA = "08cd95d4487b522463d0a1a3b58b84935a1f7d08";
|
|
80337
|
+
BUILD_TIME = "2026-07-26T13:56:33.334Z";
|
|
80230
80338
|
SHORT_SHA = BUILD_SHA === "unknown" ? "unknown" : BUILD_SHA.slice(0, 7);
|
|
80231
80339
|
VERSION_WITH_BUILD = SHORT_SHA === "unknown" ? PKG_VERSION : `${PKG_VERSION}+${SHORT_SHA}`;
|
|
80232
80340
|
INSTANCE_ID = randomUUID6().slice(0, 8);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vcad/mcp",
|
|
3
|
-
"version": "0.9.4-main.
|
|
3
|
+
"version": "0.9.4-main.39",
|
|
4
4
|
"description": "vcad MCP server — parametric CAD + PCB design tools for AI agents (self-contained: bundled server + kernel WASM)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
},
|
|
20
20
|
"homepage": "https://vcad.io",
|
|
21
21
|
"vcadBuild": {
|
|
22
|
-
"sha": "
|
|
23
|
-
"builtAt": "2026-07-26T13:
|
|
22
|
+
"sha": "08cd95d4487b522463d0a1a3b58b84935a1f7d08",
|
|
23
|
+
"builtAt": "2026-07-26T13:56:33.334Z"
|
|
24
24
|
}
|
|
25
25
|
}
|
package/vcad_kernel_wasm_bg.wasm
CHANGED
|
Binary file
|