@vcad/mcp 0.9.4-main.18 → 0.9.4-main.19

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 48276771946e67b08cb31a66d123bdc2d7af926d at 2026-07-24T22:30:13.865Z. Source: https://github.com/ecto/vcad
9
+ Built from 7f18700be295061f294b748d3d7aa957f34ddd1c at 2026-07-25T13:19:21.672Z. Source: https://github.com/ecto/vcad
package/index.mjs CHANGED
@@ -245,6 +245,7 @@ __export(vcad_kernel_wasm_exports, {
245
245
  sectionMesh: () => sectionMesh,
246
246
  sheetMetalFoldedStep: () => sheetMetalFoldedStep,
247
247
  sheetMetalSequence: () => sheetMetalSequence,
248
+ simulateFlow: () => simulateFlow,
248
249
  simulateStrikeKernel: () => simulateStrikeKernel,
249
250
  sketchCircleSegments: () => sketchCircleSegments,
250
251
  sketchHitTest: () => sketchHitTest,
@@ -2797,6 +2798,17 @@ function sheetMetalSequence(chain_json) {
2797
2798
  wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);
2798
2799
  }
2799
2800
  }
2801
+ function simulateFlow(spec_json, options_json, include_fields) {
2802
+ const ptr0 = passStringToWasm0(spec_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
2803
+ const len0 = WASM_VECTOR_LEN;
2804
+ const ptr1 = passStringToWasm0(options_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
2805
+ const len1 = WASM_VECTOR_LEN;
2806
+ const ret = wasm.simulateFlow(ptr0, len0, ptr1, len1, include_fields);
2807
+ if (ret[2]) {
2808
+ throw takeFromExternrefTable0(ret[1]);
2809
+ }
2810
+ return takeFromExternrefTable0(ret[0]);
2811
+ }
2800
2812
  function simulateStrikeKernel(input_json) {
2801
2813
  let deferred3_0;
2802
2814
  let deferred3_1;
@@ -10249,6 +10261,25 @@ async function tryRunDrc(pcb) {
10249
10261
  return { ok: false, reason: "error", message: e instanceof Error ? e.message : String(e) };
10250
10262
  }
10251
10263
  }
10264
+ async function runFabPrep(pcb, options) {
10265
+ const wasm3 = await loadEcadWasm();
10266
+ if (!wasm3) {
10267
+ return { ok: false, reason: "unavailable", message: "ECAD kernel WASM not loaded" };
10268
+ }
10269
+ if (typeof wasm3.ecadFabPrep !== "function") {
10270
+ return {
10271
+ ok: false,
10272
+ reason: "unavailable",
10273
+ message: "kernel WASM predates ecadFabPrep"
10274
+ };
10275
+ }
10276
+ try {
10277
+ const out = wasm3.ecadFabPrep(JSON.stringify(pcb), options ? JSON.stringify(options) : void 0);
10278
+ return { ok: true, value: out };
10279
+ } catch (e) {
10280
+ return { ok: false, reason: "error", message: e instanceof Error ? e.message : String(e) };
10281
+ }
10282
+ }
10252
10283
  async function runPcbDfm(pcb, profile, rulePackToml) {
10253
10284
  const wasm3 = await loadEcadWasm();
10254
10285
  if (!wasm3 || typeof wasm3.ecadDfmCheck !== "function")
@@ -11275,6 +11306,7 @@ __export(dist_exports, {
11275
11306
  runDrc: () => runDrc,
11276
11307
  runDrcInRegion: () => runDrcInRegion,
11277
11308
  runErc: () => runErc,
11309
+ runFabPrep: () => runFabPrep,
11278
11310
  runPcbDfm: () => runPcbDfm,
11279
11311
  sampleSequence: () => sampleSequence,
11280
11312
  sampleTrackValue: () => sampleTrackValue,
@@ -40816,6 +40848,20 @@ var init_CHANGELOG = __esm({
40816
40848
  CHANGELOG_default = {
40817
40849
  $schema: "./changelog.schema.json",
40818
40850
  entries: [
40851
+ {
40852
+ id: "2026-07-24-visionos-app",
40853
+ version: "0.9.4",
40854
+ date: "2026-07-24",
40855
+ category: "feat",
40856
+ title: "vcad for Apple Vision Pro",
40857
+ summary: "The full native editor ported to visionOS: documents float in a volume with the feature tree, inspector, tool palette, and AI composer around them.",
40858
+ features: [
40859
+ "native",
40860
+ "visionos",
40861
+ "assembly",
40862
+ "patterns"
40863
+ ]
40864
+ },
40819
40865
  {
40820
40866
  id: "2026-07-24-router-keepout-edge-clearance",
40821
40867
  version: "0.9.4",
@@ -40834,6 +40880,24 @@ var init_CHANGELOG = __esm({
40834
40880
  "validate_for_fab"
40835
40881
  ]
40836
40882
  },
40883
+ {
40884
+ id: "2026-07-24-router-drill-aware-vias-pad-layer-stubs",
40885
+ version: "0.9.4",
40886
+ date: "2026-07-24",
40887
+ category: "fix",
40888
+ title: "Router vias clear drills; stubs leave pads on the pad's layer",
40889
+ summary: "The routing oracle now checks hole-to-hole spacing across layer spans (two vias on disjoint spans no longer collide in the drill file), probes a via barrel on every layer it spans, and can pin a connection's terminals so stubs leave a pad on a layer the pad is actually on instead of floating on an inner layer.",
40890
+ features: [
40891
+ "pcb",
40892
+ "autorouter",
40893
+ "drc"
40894
+ ],
40895
+ mcpTools: [
40896
+ "route_nets",
40897
+ "run_drc",
40898
+ "validate_for_fab"
40899
+ ]
40900
+ },
40837
40901
  {
40838
40902
  id: "2026-07-24-lattice-gauge-mcp",
40839
40903
  version: "0.9.4",
@@ -40865,6 +40929,26 @@ var init_CHANGELOG = __esm({
40865
40929
  "simulate_flow"
40866
40930
  ]
40867
40931
  },
40932
+ {
40933
+ id: "2026-07-24-fab-prep-drc-delta-receipt",
40934
+ version: "0.9.4",
40935
+ date: "2026-07-24",
40936
+ category: "feat",
40937
+ title: "One-command fab prep with a DRC-delta receipt",
40938
+ summary: "vcad fab-prep (and the fab_prep MCP tool) takes a routed board to a complete Gerber package in one call: opt-in logged rule calibration, verdict ladder, strip-and-re-route fix loop, dangling-copper prune, and a receipt that separates route-attributable violations from the board's own baseline.",
40939
+ features: [
40940
+ "pcb",
40941
+ "drc",
40942
+ "autorouter",
40943
+ "fabrication",
40944
+ "cli"
40945
+ ],
40946
+ mcpTools: [
40947
+ "fab_prep",
40948
+ "validate_for_fab",
40949
+ "export_gerber"
40950
+ ]
40951
+ },
40868
40952
  {
40869
40953
  id: "2026-07-23-router-post-route-legalization",
40870
40954
  version: "0.9.4",
@@ -51968,6 +52052,7 @@ var init_tool_metadata = __esm({
51968
52052
  annotations: RW,
51969
52053
  outputSchema: objectOut({ export_kicad: { type: "object" } })
51970
52054
  },
52055
+ fab_prep: { title: "Fab Prep", annotations: RW },
51971
52056
  validate_for_fab: { title: "Validate for Fab", annotations: RO },
51972
52057
  calc_impedance: { title: "Calc Impedance", annotations: RO },
51973
52058
  size_impedance: { title: "Size Impedance", annotations: RO },
@@ -59534,6 +59619,85 @@ function detectUnsupportedFeatures(pcb) {
59534
59619
  }
59535
59620
  return out;
59536
59621
  }
59622
+ async function fabPrep(args) {
59623
+ const ctx = resolveDocInput(args);
59624
+ const pcb = getDocPcb2(ctx.doc);
59625
+ if (!pcb) {
59626
+ return ecadError(
59627
+ "Document has no PCB \u2014 run place_components first (or open a document that has a board)"
59628
+ );
59629
+ }
59630
+ if (!await isEcadAvailable2()) {
59631
+ return ecadError(
59632
+ "fab_prep requires the kernel DRC/routing engine (ECAD WASM unavailable) \u2014 refusing to report an unverifiable fab-readiness verdict"
59633
+ );
59634
+ }
59635
+ const dryRun = Boolean(args.dry_run);
59636
+ const options = {
59637
+ calibrate_rules: Boolean(args.calibrate_rules),
59638
+ route_remaining: args.route_remaining === void 0 ? true : Boolean(args.route_remaining),
59639
+ prune_dangling: args.prune_dangling === void 0 ? true : Boolean(args.prune_dangling),
59640
+ max_rounds: Math.max(0, Math.round(Number(args.max_rounds ?? 8))),
59641
+ accept_rules: Array.isArray(args.accept_rules) ? args.accept_rules : [],
59642
+ verdict: {
59643
+ budget: Math.max(1, Math.round(Number(args.budget ?? 5e6))),
59644
+ max_cluster: Math.max(1, Math.round(Number(args.max_cluster ?? 6)))
59645
+ }
59646
+ };
59647
+ const out = await runFabPrep(pcb, options);
59648
+ if (!out.ok) {
59649
+ return ecadError(`fab_prep could not run: ${out.message}`);
59650
+ }
59651
+ const { report, pcb: fixed } = out.value;
59652
+ if (!dryRun) {
59653
+ pcb.traces = fixed.traces;
59654
+ pcb.traceArcs = fixed.traceArcs;
59655
+ pcb.vias = fixed.vias;
59656
+ pcb.rules = fixed.rules;
59657
+ }
59658
+ const payload = {
59659
+ success: true,
59660
+ ...dryRun ? { dry_run: true } : {},
59661
+ converged: report.converged,
59662
+ ...report.blocker ? { blocker: report.blocker } : {},
59663
+ headline: fabPrepHeadline(report),
59664
+ // Both numbers, always. A caller that sees only one of them is being told
59665
+ // something other than what this run established.
59666
+ drc_delta: {
59667
+ baseline_total: report.delta.baseline_total,
59668
+ final_total: report.delta.final_total,
59669
+ route_attributable_total: report.delta.route_attributable_total,
59670
+ route_attributable_blocking: report.delta.route_attributable_fixable,
59671
+ route_attributable_accepted: report.delta.route_attributable_accepted,
59672
+ by_rule: report.delta.rules,
59673
+ baseline_note: "baseline = this same board with every trace and via stripped, checked under the same rules. It is not zero on an imported fixture and is not supposed to be; the router is answerable for the difference, not the total."
59674
+ },
59675
+ connectivity: report.connectivity,
59676
+ ...report.accepted_rules.length > 0 ? { accepted_rules: report.accepted_rules } : {},
59677
+ calibration: {
59678
+ requested: report.calibration_requested,
59679
+ applied: report.calibration.applied,
59680
+ refused: report.calibration.refused
59681
+ },
59682
+ initial_verdict: report.initial_verdict,
59683
+ rounds: report.rounds,
59684
+ pruned: { traces: report.pruned_traces, vias: report.pruned_vias },
59685
+ // Cap the offender list: a non-converging run on a dense board can name
59686
+ // thousands, and the full list lives in the board's own DRC.
59687
+ offenders: report.delta.offenders.slice(0, 25),
59688
+ offender_count: report.delta.offenders.length,
59689
+ next_action: report.converged ? "export_gerber (the clean-DRC gate will now pass)" : "resolve the offenders above (fix_drc / route_nets / set_placement), then re-run fab_prep",
59690
+ ...docResultPayload(ctx)
59691
+ };
59692
+ return { content: [{ type: "text", text: JSON.stringify(payload) }] };
59693
+ }
59694
+ function fabPrepHeadline(report) {
59695
+ if (!report.converged) {
59696
+ return `NOT FAB-READY \u2014 ${report.delta.route_attributable_fixable} route-attributable violation(s) remain (${report.blocker ?? "loop did not converge"})`;
59697
+ }
59698
+ const waived = report.delta.route_attributable_accepted > 0 ? `, ${report.delta.route_attributable_accepted} waived under ${report.accepted_rules.join("+")}` : "";
59699
+ return `zero route-attributable violations${waived} \u2014 ${report.delta.final_total} on the finished board, ${report.delta.baseline_total} on the same board stripped of all routing`;
59700
+ }
59537
59701
  async function validateForFab(args) {
59538
59702
  const ctx = resolveDocInput(args);
59539
59703
  const pcb = getDocPcb2(ctx.doc);
@@ -64784,7 +64948,7 @@ async function fixDrc(args) {
64784
64948
  };
64785
64949
  return { content: [{ type: "text", text: JSON.stringify(payload) }] };
64786
64950
  }
64787
- var PCB_LAYER_SET, COPPER_LAYERS, COPPER_LAYER_SET, POSITION_TOLERANCE, PIN_SEP, pinKey, createSchematicSchema, docInputProperties, placeComponentsSchema, routeNetsSchema, runDrcSchema, runErcSchema, critiqueRouteSchema, routeDiffPairSchema, lengthMatchTracesSchema, exportGerberSchema, validateForFabSchema, exportKicadSchema, addCoilSchema, boardFromSolidSchema, addCoilArraySchema, windingLayoutSchema, calcImpedanceSchema, sizeImpedanceSchema, sizePdnSchema, calcCoilSchema, sizeCoilSchema, calcRfSchema, COIL_GEOMETRY, MU0, RAIL_PIN_NAMES, PIN_TYPES, CHIP_SIZE_CODES, CONNECTIVITY_GUARD_MAX_NETS, POWER_NET_RE, DRC_CATEGORY, DRC_DELTA_SAMPLE_CAP, DRC_DELTA_FULL_BOARD_MAX, LINT_CRYSTAL_MAX_MM, LINT_DECAP_MAX_MM, LINT_CONNECTOR_EDGE_MAX_MM, LINT_HIGH_CURRENT_SEP_MIN_MM, LINT_GROUND_NET_RE, LINT_SUPPLY_NET_RE, SENSITIVE_NET_RE, HIGH_CURRENT_CLASS_RE, refPrefix, dist2d, round2, sumSq, round33, vec2Schema, setBoardOutlineSchema, FOOTPRINT_FAMILIES, listFootprintsSchema, searchFootprintsSchema, getPadPositionsSchema, getFootprintSchema, ROTATION_CONVENTION, describePcbSchema, DESCRIBE_NET_NAME_CAP, addTraceSchema, addViaSchema, OZ_TO_MM, setStackupSchema, setPlacementSchema, addZoneSchema, deleteElementProps, deleteZoneSchema, deleteTraceSchema, deleteViaSchema, COPPER_KINDS, GET_COPPER_CAP, getCopperSchema, TIE_POSITION_TOL, addNetTieSchema, deleteNetTieSchema, undoSchema, setDesignRulesSchema, sizeTraceForCurrentSchema, addViaArraySchema, MAX_VIA_ARRAY, addMotorWindingSchema, calcMotorSchema, sig6, BEARING_FRICTION_MNM, checkSelfStartSchema, solidFromBoardSchema, FR4_DENSITY_KG_M3, COPPER_DENSITY_KG_M3, DEFAULT_COPPER_THICKNESS_MM, loopArea, MOUNTING_FP_RE, KEEPOUT_ECHO_CAP, INLINE_DOC_ECHO_CAP, searchElectronicPartsSchema, resolvePartSchema, findAlternativesSchema, verifySubstitutionSchema, buildReceiptSchema, verifyReceiptSchema, FIX_EPS, FIX_DRC_NEVER, fixDrcSchema, toolDefs20;
64951
+ var PCB_LAYER_SET, COPPER_LAYERS, COPPER_LAYER_SET, POSITION_TOLERANCE, PIN_SEP, pinKey, createSchematicSchema, docInputProperties, placeComponentsSchema, routeNetsSchema, runDrcSchema, runErcSchema, critiqueRouteSchema, routeDiffPairSchema, lengthMatchTracesSchema, exportGerberSchema, validateForFabSchema, fabPrepSchema, exportKicadSchema, addCoilSchema, boardFromSolidSchema, addCoilArraySchema, windingLayoutSchema, calcImpedanceSchema, sizeImpedanceSchema, sizePdnSchema, calcCoilSchema, sizeCoilSchema, calcRfSchema, COIL_GEOMETRY, MU0, RAIL_PIN_NAMES, PIN_TYPES, CHIP_SIZE_CODES, CONNECTIVITY_GUARD_MAX_NETS, POWER_NET_RE, DRC_CATEGORY, DRC_DELTA_SAMPLE_CAP, DRC_DELTA_FULL_BOARD_MAX, LINT_CRYSTAL_MAX_MM, LINT_DECAP_MAX_MM, LINT_CONNECTOR_EDGE_MAX_MM, LINT_HIGH_CURRENT_SEP_MIN_MM, LINT_GROUND_NET_RE, LINT_SUPPLY_NET_RE, SENSITIVE_NET_RE, HIGH_CURRENT_CLASS_RE, refPrefix, dist2d, round2, sumSq, round33, vec2Schema, setBoardOutlineSchema, FOOTPRINT_FAMILIES, listFootprintsSchema, searchFootprintsSchema, getPadPositionsSchema, getFootprintSchema, ROTATION_CONVENTION, describePcbSchema, DESCRIBE_NET_NAME_CAP, addTraceSchema, addViaSchema, OZ_TO_MM, setStackupSchema, setPlacementSchema, addZoneSchema, deleteElementProps, deleteZoneSchema, deleteTraceSchema, deleteViaSchema, COPPER_KINDS, GET_COPPER_CAP, getCopperSchema, TIE_POSITION_TOL, addNetTieSchema, deleteNetTieSchema, undoSchema, setDesignRulesSchema, sizeTraceForCurrentSchema, addViaArraySchema, MAX_VIA_ARRAY, addMotorWindingSchema, calcMotorSchema, sig6, BEARING_FRICTION_MNM, checkSelfStartSchema, solidFromBoardSchema, FR4_DENSITY_KG_M3, COPPER_DENSITY_KG_M3, DEFAULT_COPPER_THICKNESS_MM, loopArea, MOUNTING_FP_RE, KEEPOUT_ECHO_CAP, INLINE_DOC_ECHO_CAP, searchElectronicPartsSchema, resolvePartSchema, findAlternativesSchema, verifySubstitutionSchema, buildReceiptSchema, verifyReceiptSchema, FIX_EPS, FIX_DRC_NEVER, fixDrcSchema, toolDefs20;
64788
64952
  var init_ecad2 = __esm({
64789
64953
  "src/tools/ecad.ts"() {
64790
64954
  "use strict";
@@ -65150,6 +65314,46 @@ var init_ecad2 = __esm({
65150
65314
  },
65151
65315
  required: []
65152
65316
  };
65317
+ fabPrepSchema = {
65318
+ type: "object",
65319
+ properties: {
65320
+ ...docInputProperties,
65321
+ calibrate_rules: {
65322
+ type: "boolean",
65323
+ description: "Derive and apply design-rule calibration from the board's OWN declared via classes and pre-existing footprint holes (default FALSE). Imported boards routinely carry global minima that forbid the via class they themselves declare \u2014 e.g. a 0.21/0.12mm class under a 0.2mm minDrill, which flags every via on the board. Calibration only ever relaxes a rule to the point where the board's own GIVEN geometry stops being illegal, is floored at laser-microvia limits, and records every change with its derivation in the receipt. Off by default because silently relaxing DRC rules to make a board pass is how an unbuildable board ships."
65324
+ },
65325
+ route_remaining: {
65326
+ type: "boolean",
65327
+ description: "Route or certify the connections the board arrived without, before the fix loop (default TRUE). Each unrouted connection ends as Routed, ProvedInfeasible (with a bottleneck-cut certificate), or an honest unknown \u2014 never silently dropped."
65328
+ },
65329
+ max_rounds: {
65330
+ type: "number",
65331
+ description: "Maximum strip-and-re-route rounds (default 8). Each round censuses the violations the ROUTING is answerable for, strips those nets, and hands them back to the session-probed router."
65332
+ },
65333
+ budget: {
65334
+ type: "number",
65335
+ description: "Per-cluster search budget in node expansions for the complete router (default 5,000,000). Lower is faster and yields more honest unknowns."
65336
+ },
65337
+ max_cluster: {
65338
+ type: "number",
65339
+ description: "Maximum connections coalesced into one joint search window (default 6)."
65340
+ },
65341
+ prune_dangling: {
65342
+ type: "boolean",
65343
+ description: "Remove copper that reaches no pad or pour of its net before the final DRC (default TRUE)."
65344
+ },
65345
+ accept_rules: {
65346
+ type: "array",
65347
+ items: { type: "string" },
65348
+ description: 'DRC rule names whose route-attributable violations are ACCEPTED rather than fixed (e.g. ["MinTraceWidth"]). Real fab packages ship with real, named exceptions; the difference between that and a footgun is whether the exception is written down. Waived violations are still counted, still listed, and the waiver is named in the receipt \u2014 it stops blocking the verdict, it does not hide anything. An unrecognised rule name refuses the run rather than silently accepting nothing.'
65349
+ },
65350
+ dry_run: {
65351
+ type: "boolean",
65352
+ description: "Compute the receipt without writing the fixed board back to the session."
65353
+ }
65354
+ },
65355
+ required: []
65356
+ };
65153
65357
  exportKicadSchema = {
65154
65358
  type: "object",
65155
65359
  properties: {
@@ -66766,6 +66970,14 @@ var init_ecad2 = __esm({
66766
66970
  handler: (a) => exportKicad(a),
66767
66971
  behavior: behavior({})
66768
66972
  },
66973
+ {
66974
+ name: "fab_prep",
66975
+ pack: "ecad",
66976
+ description: "Take a routed board to fab-ready in one call, and return the DRC-delta receipt that says what was actually achieved. Runs the whole pipeline: optional rule calibration (opt-in, every change logged with its derivation), the verdict ladder over unrouted connections (each ends Routed / ProvedInfeasible / honest-unknown), then a strip-and-re-route fix loop until the violations the ROUTING is answerable for reach zero, then a dangling-copper prune. Mutates the session document. THE RECEIPT IS THE POINT: on an imported fixture absolute zero is not achievable \u2014 the same board stripped of all routing already violates its own rules \u2014 so the report always gives BOTH numbers (stripped-board baseline and finished board) and charges only the difference to the router. Fails closed: a loop that does not converge returns `converged:false` with the remaining offenders and does not pretend otherwise, and `export_gerber`'s clean-DRC gate still stands \u2014 this is the supported way to GET clean, not a way around it.",
66977
+ inputSchema: fabPrepSchema,
66978
+ handler: (a) => fabPrep(a),
66979
+ behavior: behavior({ writesDoc: true, geometry: true, mount: true })
66980
+ },
66769
66981
  {
66770
66982
  name: "validate_for_fab",
66771
66983
  pack: "ecad",
@@ -77719,8 +77931,8 @@ var init_server3 = __esm({
77719
77931
  init_order_feed();
77720
77932
  init_animate();
77721
77933
  PKG_VERSION = (() => {
77722
- if ("0.9.4-main.18") {
77723
- return "0.9.4-main.18";
77934
+ if ("0.9.4-main.19") {
77935
+ return "0.9.4-main.19";
77724
77936
  }
77725
77937
  try {
77726
77938
  const req = createRequire2(import.meta.url);
@@ -77729,8 +77941,8 @@ var init_server3 = __esm({
77729
77941
  return "0.0.0";
77730
77942
  }
77731
77943
  })();
77732
- BUILD_SHA = "48276771946e67b08cb31a66d123bdc2d7af926d";
77733
- BUILD_TIME = "2026-07-24T22:30:13.865Z";
77944
+ BUILD_SHA = "7f18700be295061f294b748d3d7aa957f34ddd1c";
77945
+ BUILD_TIME = "2026-07-25T13:19:21.672Z";
77734
77946
  SHORT_SHA = BUILD_SHA === "unknown" ? "unknown" : BUILD_SHA.slice(0, 7);
77735
77947
  VERSION_WITH_BUILD = SHORT_SHA === "unknown" ? PKG_VERSION : `${PKG_VERSION}+${SHORT_SHA}`;
77736
77948
  INSTANCE_ID = randomUUID6().slice(0, 8);
@@ -77990,6 +78202,7 @@ var init_server3 = __esm({
77990
78202
  "run_erc",
77991
78203
  "export_gerber",
77992
78204
  "export_kicad",
78205
+ "fab_prep",
77993
78206
  "validate_for_fab",
77994
78207
  "calc_impedance",
77995
78208
  "size_impedance",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vcad/mcp",
3
- "version": "0.9.4-main.18",
3
+ "version": "0.9.4-main.19",
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": "48276771946e67b08cb31a66d123bdc2d7af926d",
23
- "builtAt": "2026-07-24T22:30:13.865Z"
22
+ "sha": "7f18700be295061f294b748d3d7aa957f34ddd1c",
23
+ "builtAt": "2026-07-25T13:19:21.672Z"
24
24
  }
25
25
  }
Binary file