Skip to content

Releases: SecondMouseAU/OCCTMCP

v1.9.0 — surface deviation + invalid-shape loading (inspection/measurement)

20 Jun 00:17
8a8d0c8

Choose a tag to compare

Measurement & inspection improvements, with Node↔Swift parity restored via OCCTSwiftScripts v1.4.0.

New

  • measure_deviation — directed + symmetric surface deviation (one-sided / symmetric Hausdorff) between two bodies. The metric for certifying a reconstruction against its source mesh; measure_distance is minimum-only. Reports {max, rms, mean, worstPoint} per direction + symmetricHausdorff. (#41, #46)
  • compute_metricsboundingBoxOptimal — opt-in tight extent (BRepBndLib::AddOptimal); the default Bnd_Box over-reports curved B-spline geometry. (#44, #45)
  • read_brep / import_fileallowInvalid — load a topologically invalid / loose-face shape (an in-progress reconstruction) into the scene so the analysis tools can measure it. (#41 Gap 2, #48)

Fixed

  • execute_script pinned a pre-1.0 OCCTSwiftScripts → stale OCCTSwift; now tracks the server cohort. (#42, #43)

Node parity

  • measure_deviation, compute_metrics boundingBoxOptimal, and read_brep / import_file allowInvalid are now in both servers (Node wraps the new occtkit verbs). Node tool count 36 → 37. (#47, #48)

Cohort

OCCTSwift 1.8.0, OCCTSwiftScripts 1.4.0.

v1.8.0 — graph_select + graph_ml convexity

18 Jun 23:30
6f4cacd

Choose a tag to compare

Adds the B-rep graph selection primitives (OCCTMCP#38).

  • graph_select — local adjacency/selection on a BREP path: face-neighbors (+ convexity + shared-edge count via the kernel AAG), edge-faces, vertex-edges, face-adjacency (full gAAG), edges-class (boundary|non-manifold|seam|degenerate). The selection/pointer primitive without dumping the whole graph.
  • graph_ml — now augments its output with a convexity-attributed faceAdjacency block (kernel-direct AAG), completing the graph_ml half of #38.

Bumps the OCCTSwiftScripts pin to v1.2.0. Builds against OCCTSwift 1.7.1 (OCCT 8.0.0p1). (#39, closes #38)

v1.7.1 — re-pin OCCT 8.0.0p1 cohort

18 Jun 21:35

Choose a tag to compare

Re-pin to the OCCT 8.0.0p1 cohort: OCCTSwift 1.7.1, OCCTSwiftMesh 1.1.1, OCCTSwiftTools 1.1.2, OCCTSwiftAIS 1.0.3, OCCTSwiftScripts 1.0.5, OCCTSwiftViewport 1.1.20. No API changes; 36 tests pass.

v1.7.0 — General-arrangement assembly drawings

13 Jun 23:24
7a4056a

Choose a tag to compare

General-arrangement / assembly drawings

Bumps OCCTSwiftScripts 1.0.3 → 1.0.4 (DrawingComposer GA overloads, OCCTSwiftScripts#50) and surfaces them through generate_drawing.

  • generate_drawing accepts bodyIds (2+) → a general-arrangement assembly sheet: shared views, a parts list, and a numbered balloon per body (via Composer.render(spec:components:)). A single bodyId still gives a standard part drawing (sections / dimensions honoured). bodyId is now optional; bodyIds takes precedence.
  • DrawingReport gains componentCount + partCount.
  • New integration test (two-body GA sheet). 36 tests green.

⚠️ Cohort dependency bump

OCCTSwiftScripts 1.0.4 raised its OCCTSwift floor to 1.3.1, so this forces OCCTSwift 1.2.0 → 1.4.0 (OCCT.xcframework 1.3.2) across the cohort. Verified with a clean build — no OCCTMCP API breakage. Declared OCCTSwift floor bumped to 1.3.1.

🤖 Generated with Claude Code

v1.6.0 — pick_surface_point

12 Jun 10:58
d7c3636

Choose a tag to compare

New: pick_surface_point

Repins OCCTSwiftViewport 1.0.4 → 1.1.20 (tap-to-measure, SecondMouseAU/OCCTSwiftViewport#68) and adds an MCP tool that surfaces the viewport's ray→surface-point pick math headlessly.

Cast a ray through pixel (screenX, screenY) of a render_preview-framed view (pass the same options you render with) and get back the nearest world-space surface point on a body: hit, bodyId, point [x,y,z], distance, and a selectionId.

The selectionId is a valid add_dimension anchor, so you can pick two arbitrary surface points and dimension between them — not just topology centroids. Implemented with Ray.fromCamera + SceneRaycast.cast.

Details

  • New RayPickTool; SelectionRegistry.recordPointSnapshot for free-point anchors.
  • Dispatch uses numberValue so integer pixels survive the JSON int/double round-trip.
  • New integration test (pick ×2 → add_dimension). 35 tests pass.
  • README: 57 tools.

🤖 Generated with Claude Code

v1.5.0 — reconstruct_* tool group (consume OCCTSwift v1.2.0)

05 Jun 09:17
f525330

Choose a tag to compare

OCCTMCP v1.5.0 — reconstruct_* tool group (consume OCCTSwift v1.2.0)

MINOR — additive new tool surface. No breaking changes.

OCCTSwift v1.2.0 closes #168 with a TopologyGraph per-node attribute store + Codable GraphSnapshot round-trip. This release consumes that to ship the reconstruct_* group (#33) — LLM read/write over an attributed reconstruction graph, the missing piece for driving the OCCTReconstruct mesh-to-solid pipeline from a model.

New tools (6 → 56 total)

Tool Direction Purpose
reconstruct_get_graph read Topology counts + annotated nodes (with reconstruct.* attrs) + instance clusters
reconstruct_set_decision write decidedBy (geometric/ml/human) + accept/reject
reconstruct_force_fit write Record a forced surface-type override
reconstruct_confirm_instances write Confirm/reject a congruence cluster
reconstruct_export_session read Byte-stable GraphSnapshot to disk
reconstruct_import_session write Reload a snapshot into a session

Design

  • ReconstructRegistry — actor-backed sessionId → TopologyGraph, mirroring SelectionRegistry/HistoryRegistry. All graph access is actor-isolated.
  • Nodes addressed by the self-describing <kind>:<index> string (e.g. face:3), parseable both ways.
  • reconstruct.* namespaced attribute keys; engine-written keys (residual/confidence/…) round-trip through get_graph/export_session untouched.
  • Scope boundary: the reconstruction engine (surface fitting, congruence detection) lives in OCCTReconstruct. reconstruct_force_fit records the override for the engine to honour — it does not re-fit here. This resolves the issue's "override and re-fit" wording toward its own out-of-scope note.
  • Swift-only, consistent with selection / remap / annotations / history (Node remains the portable 36-tool subset).

Dependency

  • OCCTSwift pin 1.1.0 → 1.2.0. No other cohort members moved.

Tests

34 swift-testing cases (was 28). New ReconstructToolsTests.swift covers node addressing, each write path, the export→import round-trip, and byte-stability of the canonical snapshot. swift build + swift test green.

v1.4.2 — floor + lock the crash-fixed Viewport cohort

26 May 06:33
c9d3c69

Choose a tag to compare

OCCTMCP was locked to OCCTSwiftViewport 1.0.2 — the version with the uncatchable NormalSmoothing.quantize() crash on body load (Viewport #30). render-preview rasterizes through Viewport, so the server could trap on large or ill-bounded models.

Floors + lock raised to the crash-fixed cohort: Viewport 1.0.2 → 1.0.4, Tools 1.1.0 → 1.1.1, AIS 1.0.1 → 1.0.2, Scripts 1.0.2 → 1.0.3. Build clean; all 28 tests pass.

🤖 Generated with Claude Code

v1.4.1 — drop swift-sdk fork branch (official tagged SDK)

26 May 06:18
4bd23f7

Choose a tag to compare

Dependency hygiene — drop the swift-sdk fork branch

OCCTMCP depended on the gsdali/swift-sdk fork branch add-value-numbervalue — a moving, non-reproducible reference. This release switches to the official modelcontextprotocol/swift-sdk at a tagged version (from: "0.11.0" → resolves to 0.12.1).

The fork's only delta from upstream was a single Value.numberValue accessor (proposed upstream in modelcontextprotocol/swift-sdk#225, PR #226, still open). It is now back-ported verbatim in Sources/OCCTMCPCore/Value+NumberValue.swift and will be removed once the SDK ships the property.

Impact

No behavioral change — numberValue is identical. The dependency graph is now reproducible (version-locked at 0.12.1 instead of a branch that could move or disappear). Build clean; all 28 tests pass.

🤖 Generated with Claude Code

v1.4.0 — consume OCCTSwift v1.1.0 + drop identity-flag workaround

10 May 00:00
6614714

Choose a tag to compare

OCCTMCP v1.4.0 — consume OCCTSwift v1.1.0 + drop identity-flag workaround

OCCTSwift v1.1.0 closes #167 with TopologyGraph.findDerivedOrSelf(of:) and hasHistoryRecord(for:) — unambiguous answers to "where did this node end up?":

  • non-empty derivatives → modified
  • [] → explicitly deleted
  • [self] → no record at all (untouched)

This release consumes those and removes the v1.3 workaround.

What changed

  • HistoryRegistry's Entry { graph, isIdentityPreserving } reverts to a plain graph store. recordIdentityHistory* keep their topology-count guards but no longer write self-records or set a flag.
  • RemapTools.remapViaHistory switches from findDerived + flag plumbing to findDerivedOrSelf. Empty result is now a definitive fate=lost. Cleaner control flow.
  • recordKind inside recordBoolean / recordSingleInputHistory skips writing identity records (input mapped to its own index in the post graph). Without this skip, OCCT-reported "modified to same index" cases would get conflated with explicit deletes by findDerivedOrSelf — the fillet integration test exposed this on the cutover.

History opt-in matrix as of v1.4

Tool Path Notes
transform_body implicit identity (no records written) every node maps 1:1; findDerivedOrSelf returns [self]
heal_shape implicit identity if guards pass falls back to heuristic if shape repair changed topology
boolean_op per-input via *WithFullHistory identity-mapping records skipped at write time
apply_feature per-feature via BuildResult.histories[id] every spec kind covered (OCCTSwift v1.0.4)
mirror_or_pattern use find_correspondences instead different contract

Tests

25 swift-testing cases — same surface as v1.3.0; no new tests, no removed tests. All four history-asserting integration tests still pass; the fillet one passes only after the recordKind identity-skip fix landed, which proves we're now exercising the findDerivedOrSelf semantics correctly.

v1.3.0 — find_correspondences (closes #24) + history-fix

09 May 20:39
9223bac

Choose a tag to compare

OCCTMCP v1.3.0 — find_correspondences (closes #24) + history-fix

Adds the cross-body selection-mapping tool that closes the last gap in the remap matrix, and fixes two latent bugs that turned out to hide each other.

find_correspondences — new tool (50 total)

Maps selectionIds from a source body onto a target body that's a known transform of the source — typically a mirror_or_pattern output. Different contract from remap_selection: not "X mutated into Y on the same body" but "X on body A corresponds to Y on body B under transform T".

find_correspondences({
  sourceSelectionIds: ["sel:src#face[3]"],
  targetBodyId: "mirror-src",
  transform: {
    kind: "mirror",
    planeOrigin: [0, 0, 0],
    planeNormal: [1, 0, 0]
  }
}) → { correspondences: [{ sourceSelectionId, targetSelectionId, fate, confidenceMm }] }

v1 supports translate / mirror / rotate hints. Compound transforms, bbox-alignment inference, and reading mirror_or_pattern manifest metadata as transform defaults are tracked as follow-ups in #24.

Fixed: identity history was a placebo

OCCT's TopologyGraph.findDerived returns empty for identity records (original == replacement). The recordIdentityHistory loop in HistoryRegistry was writing exactly such no-op records — so findDerived always returned empty and remap_selection fell back to the centroid heuristic. Every prior test asserting fate=preserved + confidenceMm=0 was passing because the centroid heuristic also returned 0 (non-overlapping unions, holes on opposite-side faces, etc.).

HistoryRegistry now stores an Entry { graph, isIdentityPreserving }. Identity-preserving recorders set the flag and skip the self-record loop. RemapTools treats findDerived empty + flag set as preserved-at-same-index. transform_body's history path is real for the first time.

Fixed: JSON ints failing in tool dispatch

When a client encodes Value.double(0), the SDK's JSONEncoder writes 0 (no decimal). The decoder picks .int(0). Tool dispatches reading coordinate arrays via arr[N].doubleValue got nil. LLMs sending [0, 0, 1] for unit vectors hit this constantly.

New Value.asDouble extension accepts either .int or .double; 11 array sites + 3 scalar sites converted across transform_body / mirror_or_pattern / select_topology / find_correspondences etc.

Updated history opt-in matrix

Tool Path Notes
transform_body identity flag every node maps 1:1; flag short-circuits findDerived empty to preserved
heal_shape identity flag if guards pass falls back to heuristic if topology counts changed
boolean_op per-input via *WithFullHistory recorded under output + both inputs
apply_feature per-feature via BuildResult.histories[id] every spec kind covered (OCCTSwift v1.0.4)
mirror_or_pattern use find_correspondences instead different contract — pattern instances aren't OCCT-derivatives

Tests

25 swift-testing cases (was 24). New findCorrespondencesAcrossMirror builds a 20³ box at +X, mirrors about YZ, picks a face on the source, calls find_correspondences, asserts fate=matched + targetSelectionId.hasPrefix("sel:mirror-src#face[") + confidenceMm < 0.01. The existing historyRemapPreservesAcrossTransform now actually exercises the history path (was a placebo before this release).