@vcad/mcp 0.9.4-main.36 → 0.9.4-main.38

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 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 3b9087f300b569c70aa24cebc52af06d15e59187 at 2026-07-26T13:20:01.737Z. Source: https://github.com/ecto/vcad
9
+ Built from 254d4e9d13825ac74a895590703959d77898e1f3 at 2026-07-26T13:42:07.736Z. Source: https://github.com/ecto/vcad
package/index.mjs CHANGED
@@ -11559,6 +11559,7 @@ var init_dist = __esm({
11559
11559
  circuitTransient: wasmModule7.circuitTransient,
11560
11560
  circuitTune: wasmModule7.circuitTune,
11561
11561
  feaAnalyzeMesh: wasmModule7.feaAnalyzeMesh,
11562
+ feaCheckBeam: wasmModule7.feaCheckBeam,
11562
11563
  emSimulate: wasmModule7.emSimulate,
11563
11564
  antennaAnalyze: wasmModule7.antennaAnalyze,
11564
11565
  photonicsSimulate: wasmModule7.photonicsSimulate,
@@ -11887,6 +11888,22 @@ var init_dist = __esm({
11887
11888
  }
11888
11889
  return fn(specJson, optionsJson, positions, indices);
11889
11890
  }
11891
+ /**
11892
+ * Closed-form check of a prismatic member: exact section properties,
11893
+ * beam bending with the Timoshenko shear term, Bredt thin-wall (or
11894
+ * Saint-Venant series) torsion, and Euler buckling — the route for
11895
+ * thin-walled sheet-metal and tube-frame members, which no affordable
11896
+ * lattice pitch can resolve. Same fail-closed contract and
11897
+ * `vcad.fea-claims/1` predicted claims as `feaAnalyzeMesh`; see
11898
+ * `vcad-kernel-fea::section`.
11899
+ */
11900
+ feaCheckBeam(caseJson) {
11901
+ const fn = this.kernel.feaCheckBeam;
11902
+ if (typeof fn !== "function") {
11903
+ throw new Error("feaCheckBeam is not exported by this kernel WASM build \u2014 rebuild packages/kernel-wasm");
11904
+ }
11905
+ return fn(caseJson);
11906
+ }
11890
11907
  /**
11891
11908
  * EM field simulation (2D/axisymmetric finite-volume magnetostatics or
11892
11909
  * electrostatics): inductance, force, torque, capacitance extraction and
@@ -40984,6 +41001,25 @@ var init_CHANGELOG = __esm({
40984
41001
  "export_cad"
40985
41002
  ]
40986
41003
  },
41004
+ {
41005
+ id: "2026-07-26-fastener-forms",
41006
+ version: "0.9.4",
41007
+ date: "2026-07-26",
41008
+ category: "feat",
41009
+ title: "Fasteners are a first-class form",
41010
+ summary: "bolt, bolt-circle, clearance-hole and tapped-hole: catalog-backed hardware oriented by its own axis, with real countersunk heads, length checks, and BOM lines counted off the geometry.",
41011
+ features: [
41012
+ "loon",
41013
+ "fasteners",
41014
+ "bom",
41015
+ "assembly"
41016
+ ],
41017
+ mcpTools: [
41018
+ "create_cad_loon",
41019
+ "bom_create",
41020
+ "search_mechanical_parts"
41021
+ ]
41022
+ },
40987
41023
  {
40988
41024
  id: "2026-07-26-document-source-provenance",
40989
41025
  version: "0.9.4",
@@ -41003,6 +41039,23 @@ var init_CHANGELOG = __esm({
41003
41039
  "load_document"
41004
41040
  ]
41005
41041
  },
41042
+ {
41043
+ id: "2026-07-26-beam-check-thin-walled-fea",
41044
+ version: "0.9.4",
41045
+ date: "2026-07-26",
41046
+ category: "feat",
41047
+ title: "beam_check: audited structural answer for thin walls",
41048
+ summary: "Sheet-metal and tube-frame members had no audited FEA answer at any resolution; beam_check prices them in closed form (Bredt torsion, beam bending, Euler buckling), and analyze_structure now measures the wall and refuses with the cell arithmetic instead of a bare Unverifiable.",
41049
+ features: [
41050
+ "fea",
41051
+ "sheet-metal",
41052
+ "receipts"
41053
+ ],
41054
+ mcpTools: [
41055
+ "beam_check",
41056
+ "analyze_structure"
41057
+ ]
41058
+ },
41006
41059
  {
41007
41060
  id: "2026-07-26-backwards-extrude-inverted-winding",
41008
41061
  version: "0.9.4",
@@ -53324,6 +53377,7 @@ var init_tool_metadata = __esm({
53324
53377
  solve_thermal: { title: "Solve Thermal", annotations: RO },
53325
53378
  simulate_flow: { title: "Simulate Flow", annotations: RO },
53326
53379
  analyze_structure: { title: "Analyze Structure", annotations: RO },
53380
+ beam_check: { title: "Check Beam / Section", annotations: RO },
53327
53381
  simulate_neutron_shield: {
53328
53382
  title: "Simulate Neutron Shield",
53329
53383
  annotations: RO
@@ -57148,6 +57202,14 @@ function totalsSummary(totals) {
57148
57202
  currency: totals.currency
57149
57203
  };
57150
57204
  }
57205
+ function documentHardware(documentId) {
57206
+ try {
57207
+ const doc = documents.get(documentId);
57208
+ return Array.isArray(doc?.hardware) ? doc.hardware : [];
57209
+ } catch {
57210
+ return [];
57211
+ }
57212
+ }
57151
57213
  async function bomCreate(input, store, user) {
57152
57214
  const args = input ?? {};
57153
57215
  const owner = ownerId(user);
@@ -57162,7 +57224,23 @@ async function bomCreate(input, store, user) {
57162
57224
  created_at: now,
57163
57225
  updated_at: now
57164
57226
  };
57165
- const lineInputs = Array.isArray(args.lines) ? args.lines : [];
57227
+ const fromGeometry = args.from_geometry !== false;
57228
+ const geometryLines = [];
57229
+ if (fromGeometry && bom.document_id) {
57230
+ for (const hw of documentHardware(bom.document_id)) {
57231
+ geometryLines.push({
57232
+ kind: "cots",
57233
+ name: hw.spec,
57234
+ catalog_id: hw.catalog_id ?? void 0,
57235
+ qty: hw.qty,
57236
+ notes: "counted from the model geometry"
57237
+ });
57238
+ }
57239
+ }
57240
+ const lineInputs = [
57241
+ ...geometryLines,
57242
+ ...Array.isArray(args.lines) ? args.lines : []
57243
+ ];
57166
57244
  for (let i = 0; i < lineInputs.length; i++) {
57167
57245
  const built = await buildLine(lineInputs[i] ?? {}, store, owner);
57168
57246
  if ("error" in built) return err4(`lines[${i}]: ${built.error}`);
@@ -57338,6 +57416,7 @@ var init_bom = __esm({
57338
57416
  init_pricing();
57339
57417
  init_types4();
57340
57418
  init_mech_parts();
57419
+ init_session_core();
57341
57420
  init_tool_def();
57342
57421
  PRICING_NOTE = "All prices are ESTIMATES (Phase-0 quote estimates, catalog price bands, or caller-supplied numbers) \u2014 not binding quotes.";
57343
57422
  memBoms = /* @__PURE__ */ new Map();
@@ -57403,6 +57482,10 @@ var init_bom = __esm({
57403
57482
  type: "array",
57404
57483
  items: { type: "object", properties: lineProperties, required: ["kind"] },
57405
57484
  description: "Optional full line list to build the BOM in ONE call (recommended on serverless \u2014 BOMs are in-memory per instance, so one-shot creation is the robust path)."
57485
+ },
57486
+ from_geometry: {
57487
+ type: "boolean",
57488
+ description: "Seed COTS lines from the hardware the document's geometry declares \u2014 every loon `bolt`/`bolt-circle` (plus its washers and nuts), with quantities already multiplied through patterns. Default true when document_id is given."
57406
57489
  }
57407
57490
  },
57408
57491
  required: []
@@ -57437,7 +57520,7 @@ var init_bom = __esm({
57437
57520
  {
57438
57521
  name: "bom_create",
57439
57522
  pack: "bom",
57440
- description: "Create a project bill of materials \u2014 the deliverable that collects every manufactured part (PCBs, sheet metal, 3D prints; link quote_manufacturing quotes by quote_id) and COTS part (bearings, shafts, screws, magnets; link search_mechanical_parts entries by catalog_id) in one place. Optionally attach a document_id and assembly notes. Pass the full `lines` array to build the whole BOM in ONE call \u2014 recommended, since BOMs are in-memory per server instance. All prices are estimates and flagged as such.",
57523
+ description: "Create a project bill of materials \u2014 the deliverable that collects every manufactured part (PCBs, sheet metal, 3D prints; link quote_manufacturing quotes by quote_id) and COTS part (bearings, shafts, screws, magnets; link search_mechanical_parts entries by catalog_id) in one place. Optionally attach a document_id and assembly notes. Pass the full `lines` array to build the whole BOM in ONE call \u2014 recommended, since BOMs are in-memory per server instance. When document_id names a resident session, fastener lines are seeded from the geometry itself (every loon `bolt`/`bolt-circle`, quantities multiplied through patterns) \u2014 pass from_geometry:false to opt out. All prices are estimates and flagged as such.",
57441
57524
  inputSchema: bomCreateSchema,
57442
57525
  handler: (a, c) => bomCreate(a, c.fabricateStore, c.user),
57443
57526
  behavior: behavior({})
@@ -72230,7 +72313,7 @@ var init_structure = __esm({
72230
72313
  {
72231
72314
  name: "analyze_structure",
72232
72315
  pack: null,
72233
- description: 'Static structural FEA on a part\'s real geometry with fail-closed mesh-convergence gating: linear-tet fill of the tessellated interior at 2+ refinement levels, linear-elastic solve (PCG), returning max von Mises stress, max displacement, discretization-error estimates, and (with yield_strength_mpa) a safety factor \u2014 plus `vcad.fea-claims/1` and unified-receipt claims. If QoIs disagree across levels the verdict is Unverifiable and NO stress/displacement claim is emitted (raise resolution, or fillet the singular corner it points at). Claims carry basis "predicted" and roll up Provisional until hardware is load-tested. Scope: small-displacement linear elasticity, one isotropic material; no plasticity, buckling, contact, or dynamic loads; boundary is staircase-approximated at the lattice pitch. Use predict_physics for the fast coarse steering loop; use this for the audited answer.',
72316
+ description: 'Static structural FEA on a part\'s real geometry with fail-closed mesh-convergence gating: linear-tet fill of the tessellated interior at 2+ refinement levels, linear-elastic solve (PCG), returning max von Mises stress, max displacement, discretization-error estimates, and (with yield_strength_mpa) a safety factor \u2014 plus `vcad.fea-claims/1` and unified-receipt claims. If QoIs disagree across levels the verdict is Unverifiable and NO stress/displacement claim is emitted (raise resolution, or fillet the singular corner it points at). Claims carry basis "predicted" and roll up Provisional until hardware is load-tested. Scope: small-displacement linear elasticity, one isotropic material; no plasticity, buckling, contact, or dynamic loads; boundary is staircase-approximated at the lattice pitch. THIN-WALLED PARTS (sheet metal, tube frame, plate) are outside this tool: it measures the thinnest load-bearing section and fails closed with the cell arithmetic and a pointer to beam_check, which is the more accurate answer for a prismatic member anyway. Use predict_physics for the fast coarse steering loop; use this for the audited answer on chunky geometry.',
72234
72317
  inputSchema: {
72235
72318
  type: "object",
72236
72319
  required: ["document_id", "part", "loads", "supports"],
@@ -72295,7 +72378,7 @@ var init_structure = __esm({
72295
72378
  },
72296
72379
  resolution: {
72297
72380
  type: "number",
72298
- description: "Coarse-level lattice cells along the longest bbox axis (default 24). The finest level is resolution * 2^(levels-1), capped at 160 for this tier. Keep >= ~6 cells through the thinnest load-bearing section."
72381
+ description: "Coarse-level lattice cells along the longest bbox axis (default 24). The finest level is resolution * 2^(levels-1), capped at 160 for this tier. Keep >= ~6 cells through the thinnest load-bearing section \u2014 the tool measures the part and refuses below ~4, with the cell arithmetic attached. Raising this is NOT the lever for a thin wall (a 2 mm wall on a 300 mm member needs ~950 cells): use beam_check."
72299
72382
  },
72300
72383
  levels: {
72301
72384
  type: "number",
@@ -72346,6 +72429,89 @@ var init_structure = __esm({
72346
72429
  });
72347
72430
  },
72348
72431
  behavior: behavior({})
72432
+ },
72433
+ {
72434
+ name: "beam_check",
72435
+ pack: null,
72436
+ description: 'Closed-form structural check of a PRISMATIC member \u2014 the audited answer for thin-walled geometry, where the lattice in analyze_structure cannot put enough cells through the wall at any affordable resolution. Give it a profile (rect, rect_tube, round, round_tube, i_beam), a span, an end condition, and a load case; get section properties (A, I_y, I_z, J, section moduli, torsional stiffness), stresses (bending, axial, torsional and transverse shear, von Mises), deflection with the Timoshenko shear term, twist, the Euler buckling load under compression, and a safety factor \u2014 plus `vcad.fea-claims/1` and unified-receipt claims under `structure.beam.*`. Exact integrals where they exist (round, round tube, rectangle bending), the convergent Saint-Venant series for solid-rectangle torsion, Bredt closed thin-wall theory for tube torsion \u2014 every approximation is stated in the returned notes. For a constant cross-section this is not a fallback: it beats a staircased lattice on accuracy and costs microseconds. Fail-closed: too stubby for beam theory (L/depth < 5), too thick-walled for Bredt, deflecting past a tenth of the span, torque on an open section, or buckling before it yields \u2014 any of those makes the verdict Unverifiable and NO QoI is claimed, with the reason naming the route forward. Claims carry basis "predicted" and roll up Provisional until hardware is load-tested. Scope: one uniform section over the whole span, idealized ends, no stress concentrations (holes, welds, corner radii), no local wall buckling, no fatigue. Needs no document \u2014 it is geometry-by-description, so it works before the part exists.',
72437
+ inputSchema: {
72438
+ type: "object",
72439
+ required: ["profile", "length_mm", "end_condition"],
72440
+ properties: {
72441
+ profile: {
72442
+ type: "object",
72443
+ required: ["type"],
72444
+ description: 'Cross-section. The member runs along X and the section lives in (Y, Z): width_mm is the Y extent, height_mm the Z extent. One of: {"type":"rect",width_mm,height_mm}, {"type":"rect_tube",width_mm,height_mm,wall_mm}, {"type":"round",diameter_mm}, {"type":"round_tube",diameter_mm,wall_mm}, {"type":"i_beam",width_mm,height_mm,flange_mm,web_mm}. Tube dimensions are OUTSIDE dimensions.',
72445
+ properties: {
72446
+ type: {
72447
+ type: "string",
72448
+ enum: ["rect", "rect_tube", "round", "round_tube", "i_beam"]
72449
+ },
72450
+ width_mm: { type: "number", description: "Y extent, mm." },
72451
+ height_mm: { type: "number", description: "Z extent, mm." },
72452
+ wall_mm: { type: "number", description: "Wall thickness, mm." },
72453
+ diameter_mm: { type: "number", description: "Outside diameter, mm." },
72454
+ flange_mm: { type: "number", description: "Flange thickness, mm." },
72455
+ web_mm: { type: "number", description: "Web thickness, mm." }
72456
+ }
72457
+ },
72458
+ length_mm: {
72459
+ type: "number",
72460
+ description: "Free span between supports, mm."
72461
+ },
72462
+ end_condition: {
72463
+ type: "string",
72464
+ enum: [
72465
+ "cantilever_tip",
72466
+ "cantilever_uniform",
72467
+ "simple_center",
72468
+ "simple_uniform",
72469
+ "fixed_fixed_center",
72470
+ "fixed_fixed_uniform"
72471
+ ],
72472
+ description: "Support and load arrangement. `*_uniform` spreads the transverse force over the span; `*_center`/`*_tip` concentrates it. Also sets the Euler effective-length factor (cantilever K=2, simple K=1, fixed-fixed K=0.5)."
72473
+ },
72474
+ transverse_force_n: {
72475
+ type: "number",
72476
+ description: "Total transverse force, N (magnitude). Default 0."
72477
+ },
72478
+ bend_axis: {
72479
+ type: "string",
72480
+ enum: ["y", "z"],
72481
+ description: "Which principal axis to bend about: `y` uses I_y and deflects along Z (default), `z` uses I_z and deflects along Y. Matters for any non-square section."
72482
+ },
72483
+ torque_nmm: {
72484
+ type: "number",
72485
+ description: "Torque about the member axis, N\xB7mm (1 N\xB7m = 1000 N\xB7mm). Default 0. This is the case closed-form theory answers best and the lattice answers worst."
72486
+ },
72487
+ axial_force_n: {
72488
+ type: "number",
72489
+ description: "Axial force, N \u2014 positive tension, negative compression. Compression is also checked against Euler buckling, and a member that buckles is reported Unverifiable rather than 'safe'. Default 0."
72490
+ },
72491
+ youngs_modulus_mpa: {
72492
+ type: "number",
72493
+ description: "Young's modulus, MPa. Default 69000 (6061 aluminum); steel ~200000, PLA ~2300."
72494
+ },
72495
+ poisson: {
72496
+ type: "number",
72497
+ description: "Poisson's ratio in [0, 0.5). Default 0.33; sets G = E/(2(1+nu))."
72498
+ },
72499
+ yield_strength_mpa: {
72500
+ type: "number",
72501
+ description: "Yield strength, MPa. When given, safety_factor = yield / von Mises is computed and claimed (applicable checks only)."
72502
+ }
72503
+ }
72504
+ },
72505
+ handler: (args, ctx) => {
72506
+ const a = args;
72507
+ const started = performance.now();
72508
+ const out = ctx.engine.feaCheckBeam(JSON.stringify(a));
72509
+ return textResult7({
72510
+ solve_ms: Math.round(performance.now() - started),
72511
+ ...out
72512
+ });
72513
+ },
72514
+ behavior: behavior({})
72349
72515
  }
72350
72516
  ];
72351
72517
  }
@@ -80049,8 +80215,8 @@ var init_server3 = __esm({
80049
80215
  init_order_feed();
80050
80216
  init_animate();
80051
80217
  PKG_VERSION = (() => {
80052
- if ("0.9.4-main.36") {
80053
- return "0.9.4-main.36";
80218
+ if ("0.9.4-main.38") {
80219
+ return "0.9.4-main.38";
80054
80220
  }
80055
80221
  try {
80056
80222
  const req = createRequire2(import.meta.url);
@@ -80059,8 +80225,8 @@ var init_server3 = __esm({
80059
80225
  return "0.0.0";
80060
80226
  }
80061
80227
  })();
80062
- BUILD_SHA = "3b9087f300b569c70aa24cebc52af06d15e59187";
80063
- BUILD_TIME = "2026-07-26T13:20:01.737Z";
80228
+ BUILD_SHA = "254d4e9d13825ac74a895590703959d77898e1f3";
80229
+ BUILD_TIME = "2026-07-26T13:42:07.736Z";
80064
80230
  SHORT_SHA = BUILD_SHA === "unknown" ? "unknown" : BUILD_SHA.slice(0, 7);
80065
80231
  VERSION_WITH_BUILD = SHORT_SHA === "unknown" ? PKG_VERSION : `${PKG_VERSION}+${SHORT_SHA}`;
80066
80232
  INSTANCE_ID = randomUUID6().slice(0, 8);
@@ -80208,6 +80374,7 @@ var init_server3 = __esm({
80208
80374
  "solve_thermal",
80209
80375
  "simulate_flow",
80210
80376
  "analyze_structure",
80377
+ "beam_check",
80211
80378
  "simulate_neutron_shield",
80212
80379
  "simulate_lattice_gauge",
80213
80380
  "analyze_tolerance_stackup",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vcad/mcp",
3
- "version": "0.9.4-main.36",
3
+ "version": "0.9.4-main.38",
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": "3b9087f300b569c70aa24cebc52af06d15e59187",
23
- "builtAt": "2026-07-26T13:20:01.737Z"
22
+ "sha": "254d4e9d13825ac74a895590703959d77898e1f3",
23
+ "builtAt": "2026-07-26T13:42:07.736Z"
24
24
  }
25
25
  }
Binary file