OCCTMCP

Interacción analítica con modelos CAD construidos sobre el núcleo CAD OCCT

Documentación

OCCTMCP

Swift Platforms License: LGPL v2.1+

Servidor MCP que da a los LLM la capacidad de crear, inspeccionar e iterar sobre modelos CAD 3D con OpenCASCADE a través de la familia OCCTSwift.

Parte del ecosistema OCCTSwift — consulta el mapa del ecosistema para ver cómo este paquete se asienta sobre las capas kernel, viewport, bridge y AIS. SemVer-estable desde v1.0.0.

La implementación Swift llama a OCCT directamente en proceso (sin subprocesos, sin marshalling JSONL) y expone 77 herramientas MCP tipadas que cubren creación, lecturas de escena, mutación, introspección, construcción, análisis, E/S, malla, dibujo, selección / remapeo, análisis de zonas de malla, inspección de malla, alineación y superposiciones de dimensiones.

Cómo Funciona

LLM picks a typed tool (boolean_op, transform_body, render_preview, …)
  → OCCTMCP runs the OCCT operation directly via OCCTSwift / Tools / AIS / Mesh
  → Writes BREP/STEP/PNG + manifest.json + annotations.json
  → OCCTSwiftViewport (optional) auto-reloads the 3D model

Para geometría novedosa que las herramientas tipadas no cubren, el LLM recurre a execute_script: código Swift arbitrario con la API completa de OCCTSwift, compilado y ejecutado en proceso.

Herramientas

77 herramientas, organizadas a continuación. Llama a get_api_reference({ category: "mcp_tools" }) para volcar el JSON Schema de cada herramienta de una sola vez, útil para el auto-descubrimiento del LLM. La mayoría de los flujos pueden responder «¿cuál es el volumen?», «ponlo rojo», «resta booleana de estos», «renderiza una vista previa», «añade una dimensión entre estas dos caras», «exporta a STEP» y «dibuja esto» sin tocar nunca execute_script.

Creación

HerramientaPropósito
execute_scriptEscribir y ejecutar código Swift CAD arbitrario (API completa de OCCTSwift)
get_scriptLeer el código fuente del script más reciente
get_api_referenceExplorar la API OCCTSwift por categoría

Lecturas de escena

HerramientaPropósito
get_sceneLeer el manifiesto de escena actual (cuerpos, colores, materiales)
export_modelListar las rutas de archivos BREP / STEP / STL / OBJ exportados
compare_versionsComparar la escena actual vs hace N ejecuciones (añadido / eliminado / apariencia / archivo cambiado)

Mutación de escena

HerramientaPropósito
remove_bodyEliminar un cuerpo de la escena (manifiesto + archivo BREP)
clear_sceneBorrar todos los cuerpos, opcionalmente conservar el historial de diferencias
rename_bodyCambiar el id de un cuerpo
set_appearanceActualizar color / opacidad / rugosidad / metalicidad / nombre mostrado

Introspección

HerramientaPropósito
validate_geometryValidación de topología por cuerpo (isValid, recuentos de errores)
compute_metricsVolumen, área, centroide, caja delimitadora, ejes principales
query_topologyEncontrar caras / aristas / vértices que coincidan con criterios, devolver IDs estables. Los resultados de aristas (#119) llevan extremos (de todo tipo) más una dirección unitaria para aristas LINE, y circleCenter/radius/axis/startAngle/endAngle para aristas CIRCULAR
measure_distanceDistancia mínima + contactos entre dos cuerpos
measure_deviationDesviación de superficie firmada y resuelta espacialmente entre dos cuerpos — máx / rms / media / p95 / signedMean (sesgo sistemático sobresaliente(+)/hundido(−)) en cada dirección + worstPoint, más un barrido opcional de media firmada por sección a lo largo de un eje. La métrica de certificación de reconstrucción (measure_distance es solo-mínima). Ver signMode bajo QA de desviación y reconstrucción para qué vale el signo frente a una referencia abierta de pared delgada
measure_vertex_fit (#118)Tabla exacta de distancias por vértice desde los vértices propios de un cuerpo de malla hasta la geometría BRep real de un cuerpo objetivo (Shape.vertex(at:).distance(to:), tipo de entidad más cercana vía distanceSolutionDetail): el instrumento de ajuste de vértices que ni measure_distance (cuerpo-a-cuerpo, acotado) ni measure_deviation (malla-a-malla, aproximado) proporcionan. Tabla de los peores N por defecto; includeAllVertices: true para la tabla completa por vértice
recognize_featuresHuecos y agujeros mediante heurísticas AAG
inspect_assemblyRecorrer un árbol de ensamblaje XCAF (STEP / IGES / XBF)

Construcción

HerramientaPropósito
apply_featureTaladrar / redondear / chaflanar / extruir / girar / roscar / booleano (FeatureSpec)
transform_bodyTrasladar / rotar / escalar uniformemente (registra historial de identidad para remapeo)
boolean_opUnión / resta / intersección / división (registra historial por entrada para remapeo)
mirror_or_patternSimetría / patrón lineal / circular → N cuerpos nuevos

Análisis de ingeniería

HerramientaPropósito
check_thicknessAnálisis de espesor de pared con indicadores de zona delgada
analyze_clearanceInterferencia por pares / holgura mínima
heal_shapeReparar geometría importada / no estanca; estadísticas antes/después

QA de desviación y reconstrucción

Comparación firmada y resuelta espacialmente de una reconstrucción contra su malla de origen. Donde los escalares de measure_deviation pueden ocultar un error de forma sistemático (una sección transversal equivocada que se promedia), estos exponen dónde y en qué dirección se desvía el candidato. Renderizado puramente en Swift — sin Python/matplotlib.

¿Qué dirección es hacia fuera? measure_deviation, deviation_histogram y signed_deviation_heatmap comparten un mismo motor de distancia firmada, por lo que comparten un control signMode. El signo de una desviación depende de contra qué triángulo de referencia se juzga una muestra, y contra una referencia abierta, de pared delgada (un escaneo crudo / piel STL) el más cercano suele ser el equivocado: un flanco candidato situado a 4.5 mm dentro de una pared de 2 mm está solo a 2.5 mm de la superficie interior de la pared, así que esa superficie gana por proximidad y — mirando hacia la cavidad — reporta +2.5 sobresaliente para una pieza que está 4.5 hundida. Lado equivocado, magnitud equivocada, nada que lo señale. signMode: "robust" (el predeterminado desde v1.17.0) rechaza los triángulos de referencia cuya normal hacia fuera se opone a la de la propia muestra antes de que gane el más cercano superviviente, recuperando ambas cifras; las muestras sin superficie compatible a su alcance se reportan ambiguous y se retiran de las estadísticas firmadas en lugar de adivinarse. signMode: "nearest" restaura el signo crudo del triángulo más cercano previo a v1.17, que es correcto contra una referencia estanca / de superficie única. Un ambiguousFraction cercano a 1.0 significa que el bobinado de la referencia probablemente está invertido respecto al cuerpo muestreado; donde nada tiene un signo fiable, las cifras firmadas vuelven null en lugar de un cero que se leería como «perfectamente centrado».

Las dos familias de números responden a preguntas diferentes, y signMode mueve solo la segunda:

FamiliaMide hasta¿Lo mueve signMode?
Sin signo — max / rms / mean / p95 / worstPoint / symmetricHausdorff / maxAbs / withinTolerancela superficie de referencia más cercana, sea cual seaNo — mismo significado que antes de v1.17
Firmada — signedMean / signedMin / signedMax / sections / cubos de histograma / colores de mapa de calorla superficie a la que la muestra corresponde

Contra una referencia estanca, estas son la misma superficie y las familias coinciden. Contra una abierta de pared delgada divergen a propósito: max: 2.5 junto a signedMin: -4.5 dice que la geometría de referencia más cercana es una pared interior a 2.5 de distancia mientras que la piel a la que pertenece ese flanco está 4.5 por encima. Ambas son ciertas. Una brecha entre ellas es en sí misma la señal de que la referencia es de pared delgada.

HerramientaPropósito
deviation_histogramDistribución firmada de desviación punto-a-superficie: μ / σ / mediana / p95 / extremos sobresaliente-hundido, porcentaje dentro de ±tolerancia, histograma de cubos + PNG opcional. Una media no nula o forma bimodal ⇒ error sistemático
cross_section_compareCortar ambos cuerpos en N estaciones a lo largo de su solapamiento de extensión de eje compartido; media firmada / RMS / relación de áreas / desplazamiento de centroide por sección + un escalar de forma radial robusto a la pose, con PNGs de superposición. El modo outerEnvelope predeterminado compara contra el límite exterior de la referencia por cada dirección angular para que los retornos de ventanas interiores / trayectorias de marco de una pieza de pared delgada o escaneada no contaminen el agregado; cada estación reporta axisCoord (posición mundial a lo largo del eje). Maneja referencias de carcasa abierta (escaneo crudo / piel STL) cuyas secciones son arcos abiertos, reporta el rango overlap y advierte en estaciones que cortaron solo un cuerpo. El detector de mayor apalancamiento de una sección con forma incorrecta
symmetric_difference_volume (#122)La cifra directa de fidelidad geométrica que una desviación superficial media/RMS puede ocultar por cancelación: los dos volúmenes unilaterales entre un candidato y una referencia (solo-exceso, solo-falta) y su suma, vía el número de bobinado generalizado de OCCTSwiftMesh (robusto contra una referencia abierta/no estanca/auto-intersecante, a diferencia de la resta de boolean_op, que falla directamente contra una). Muestreo Monte Carlo determinista de secuencia Halton; reporta un error estándar y una verificación cruzada de volumen BREP exacto cuando está disponible
signed_deviation_heatmapRenderizar la superficie candidata coloreada por distancia firmada (sobresaliente = rojo, hundido = azul) mediante un mapa de colores divergente con leyenda de barra de color. Los triángulos cuyo signo no puede establecerse contra una referencia abierta/de pared delgada se renderizan en gris (ambiguousTriangles/ambiguousFraction, excluidos de signedMin/Max/Mean) en lugar de un rojo/azul al azar — ver signMode arriba
overlay_renderRenderizar la malla de referencia semitransparente sobre el sólido candidato opaco — ver la desviación en 3D

Análisis de malla (zonas)

La superficie de inspección de malla para escaneos crudos / pieles STL: dividir la malla de un cuerpo en zonas de superficie (plano / cilindro / esfera / cono, mediante el crecimiento de regiones por ángulo diedro de OCCTSwiftMesh + fusión por ajuste de primitivas), y luego medir cuánto se mantiene constante la sección transversal propia de cada zona a lo largo de un eje (un mapa de extensión loftable). Ambos son composición pura de dominio de malla — la lógica de agregación/veredicto aquí es independiente del propio motor de OCCTReconstruct, según la política de verificación analítica obligatoria.

HerramientaPropósito
segment_mesh_zonesDividir la malla de un cuerpo en zonas de superficie; cada zona obtiene un id zone:<bodyId>#<n> estable, una primitiva ajustada (tipo/parámetros/residual) y (opcionalmente) un render PNG categórico y/o su propio cuerpo de escena registrado
zone_continuity_sweepBarrer una zona (o cuerpo completo) a lo largo de un eje; reportar ejecuciones máximas dentro de tolerancia (extensiones loftables) e intervalos de desviación entre ellas, cada uno con tramos axisCoord mundiales y magnitudes
list_zonesInspeccionar el registro de zonas (<output_dir>/zones.json)
clear_zonesVaciar el registro de zonas, opcionalmente para un cuerpo
fit_primitives (#107)Informe de primitivas RANSAC estilo Schnabel (plano/cilindro/esfera/cono), reclamando inliers GLOBALES en lugar del crecimiento de regiones solo-adyacentes-por-arista de segment_mesh_zones — de modo que puede unificar una primitiva (p. ej. un cilindro interrumpido por un saliente) que la tabla de zonas mantiene dividida entre regiones. El zoneId opcional limita el ajuste a una zona; strategy: "auto" ejecuta un desempate diedro-vs-RANSAC y reporta cuál ganó. uncoveredFraction (triángulos sin primitiva reclamada) y un límite maxPrimitives se reportan como advertencias estrictamente separadas

Inspección de malla

La superficie de lista de verificación / medición de dominio de malla (Fase 2 de la expansión de análisis de malla): diagnóstico de integridad, espesor de pared, detección de simetría reflectante y alineación de dos cuerpos, todo trabajando directamente sobre la superficie teselada de un cuerpo en lugar de la topología BREP, de modo que no se degradan en carcasas facetadas (una importación STL cruda) como sí lo hace check_thickness.

ToolPropósito
mesh_diagnoseInforme de integridad de la lista de verificación de imprimibilidad: hermético, variedad de aristas/vértices, orientable, componentes conectados, bucles de contorno, característica de Euler / género, recuentos de triángulos duplicados/degenerados, señales de sliver, además de pase/aviso/fallo derivado checks[]. NO se verifica la auto-intersección (una limitación de OCCTSwiftMesh aguas arriba)
mesh_thicknessEspesor de pared en dominio de malla mediante el método de rayos (normal-opuesta, primer impacto, mediana promediada por cono opcional): el complemento de check_thickness para mallas brutas. Informa la distribución de espesores, una sección opcional por debajo del umbral y un PNG de histograma opcional
detect_symmetryDetectar simetría reflectiva (plano espejo): 3 planos candidatos PCA a través del centroide ponderado por área, cada uno verificado reflejando puntos muestreados y midiendo su distancia residual de regreso a la superficie. La detección de simetría rotacional/axial se pospone a una fase posterior
align_bodies (#104)Alineación estilo GOM: registrar un cuerpo fuente sobre un cuerpo de referencia mediante ICP punto-a-plano (pre-alineación PCA + muestreo de espacio normal + correspondencia recortada). mode: "bestFit" (predeterminado, pipeline completo) o "preAlign" (solo pose PCA/bbox gruesa). Devuelve la transformación recuperada (fila-mayor, traslación + rotación eje-ángulo) y estadísticas residuales; apply: true la escribe sobre el cuerpo fuente en el lugar con la misma semántica de historial que transform_body. Los pasos de las herramientas de desviación scan-vs-CAD necesitan antes de que sus números signifiquen algo
mesh_curvatureCurvatura discreta por vértice (tensor por cara de Rusinkiewicz) sobre la propia malla soldada de un cuerpo: curvaturas principales k1/k2, media, gaussiana, además de un render coloreado (colorBy) y estadísticas acotadas (medianas, flatFraction, highCurvatureFraction). No se necesita cuerpo de referencia
detect_mesh_features (#108)Contornos de características de anillos de pliegue (puertas, paneles, retornos de ventanas, huecos) en una malla de escaneo bruta mediante detección de aristas de plegado diedro: suelda la malla, encadena aristas de plegado que exceden minAngleDegrees en anillos cerrados y caminos abiertos (primero los más grandes), para mallas donde recognize_features (BREP/AAG) no tiene estructura B-rep contra la cual trabajar. Consciente de uniones (las intersecciones Y/T se dividen limpiamente). Informa el containingZones de cada anillo cuando segment_mesh_zones ya se ha ejecutado para el cuerpo. includePoints: true (#120) también devuelve la polilínea ordenada de vértices en coordenadas mundiales de cada anillo. Render opcional: la superficie más cada anillo como su propia superposición de wireframe coloreado categóricamente
fit_edge_chain (#121)Segmenta una cadena de puntos 3D ordenada (típicamente la polilínea de un anillo detect_mesh_features) en tramos de línea y arco circular: tipo por segmento, extremos, dirección unitaria (línea) o centro/radio/eje/ánguloInicio/ánguloFin (arco), y residuales de ajuste. Un STL bruto no tiene aristas curvas por construcción; un arco existe en la malla solo como un ajuste sobre una cadena de aristas rectas de facetas, que ni fit_primitives ni segment_mesh_zones (ambos ajustan SUPERFICIES, no cadenas de aristas) proporcionan. Las cadenas de múltiples radios se dividen en segmentos separados en lugar de colapsarse en un círculo promediado

Selección y reasignación

ToolPropósito
select_topologyElegir caras / aristas / vértices, obtener un selectionId estable. Los anclajes de arista (#119) llevan extremos (de todos los tipos) más una dirección unitaria para aristas LINE, y circleCenter/radius/axis/startAngle/endAngle para aristas CIRCULAR
remap_selectionLlevar selectionIds a través de mutaciones del mismo cuerpo (basado en historial para transformación / curación / booleano / aplicar_característica; heurística de centroide como respaldo en otros casos)
find_correspondencesMapear selectionIds de un cuerpo fuente a un cuerpo destino que es una transformación conocida del fuente — las salidas de mirror_or_pattern son el caso típico
select_by_featureSelección masiva por tipo de característica (por ejemplo, todos los bordes de agujeros)
list_selectionsInspeccionar el registro de selección en memoria
clear_selectionsLimpiar el registro

Anotaciones y superposiciones

ToolPropósito
add_dimensionAñadir una dimensión lineal / angular / radial; se renderiza en render_preview
add_scene_primitiveAñadir triedro / planoDeTrabajo / eje / nubeDePuntos / boundingBox / marcadorDeDiferencia
auto_dimensionColocación heurística de dimensiones para las extensiones principales
show_bounding_boxAñadir el AABB de un cuerpo como superposición
diff_overlayVisualizar la diferencia entre dos instantáneas
remove_scene_annotationEliminar una dimensión o primitiva por id
list_annotationsInspeccionar el sidecar de anotaciones

I/O

ToolPropósito
read_brepCargar un .brep desde disco a la escena (allowInvalid carga una forma de cara suelta / inválida para medición)
import_fileImportación multi-formato (STEP / IGES / STL / OBJ); ensamblaje XCAF opcional; allowInvalid para reconstrucciones en curso
export_sceneExportar a STEP / IGES / BREP / STL / OBJ / glTF / GLB
set_assembly_metadataModificar documento XCAF o metadatos por componente

Malla y visualización

ToolPropósito
generate_meshTeselar a triángulos + métricas de calidad
simplify_meshDecimación de malla QEM a .stl/.obj — envuelve Mesh.simplified de OCCTSwiftMesh (meshoptimizer compilado)
render_previewRender PNG de una sola vez con etiquetas de medición y superposiciones de primitivas. Las mallas a escala de cuerpo (escaneos importados, >10k aristas) se renderizan mediante una ruta lineal en segundos — superposiciones de aristas hasta 100k aristas, solo superficie más allá
pick_surface_pointLanzar un rayo enmarcado por render_preview a través de un píxel → punto de superficie mundial + selectionId (utilizable como ancla add_dimension)
generate_drawingDibujo técnico DXF multi-vista ISO 128-30 — bodyId para una sola pieza, o bodyIds (2+) para una hoja de ensamblaje de disposición general con lista de piezas + globos

Grafo topológico (bajo nivel)

ToolPropósito
graph_validateValidar el grafo topológico de un BREP (ruta bruta)
graph_compactEliminar nodos de grafo no referenciados; escribir BREP reconstruido
graph_dedupDeduplicar geometría de superficie / curva compartida
graph_mlExportar topología + muestras UV/arista como JSON compatible con ML
graph_selectAdyacencia / selección de grafo local: vecinos de cara (+ convexidad), caras de arista, aristas de vértice, adyacencia de caras (gAAG), clases de arista
feature_recognizeBolsillos + agujeros (ruta BREP bruta; recognize_features es el envoltorio consciente de la escena)

Grafo de reconstrucción (lectura/escritura)

LLM lectura/escritura sobre un grafo de reconstrucción atribuido — anotar decisiones por nodo y persistirlas. Respaldado por NodeAttributeStore de OCCTSwift 1.2.0 + GraphSnapshot Codable. Los nodos se abordan como <kind>:<index> (por ejemplo, face:3). El motor de reconstrucción (ajuste de superficies, detección de congruencia) vive en OCCTReconstruct; estas herramientas son la capa de anotar-y-persistir — reconstruct_force_fit registra una anulación para que el motor la honre, no reajusta aquí.

ToolPropósito
reconstruct_get_graphExportar el grafo atribuido como JSON — recuentos de topología, nodos anotados (con atributos reconstruct.*), clústeres de instancia. Inicia una sesión desde un bodyId o lee uno existente por sessionId
reconstruct_set_decisionAnotar el decidedBy de un nodo (geométrico / ml / humano) y/o aceptar-rechazar un ajuste propuesto
reconstruct_force_fitAnular el tipo de superficie ajustada de un nodo (por ejemplo, forzar cylinder)
reconstruct_confirm_instancesConfirmar / rechazar un clúster de congruencia ("estos N nodos son una definición de pieza")
reconstruct_export_sessionEscribir la instantánea de la sesión en disco (JSON estable en bytes)
reconstruct_import_sessionRecargar un archivo de instantánea en una sesión

Implementaciones

Este repo entrega dos implementaciones lado a lado:

  • Swift (Sources/, Package.swift): el servidor principal. En proceso contra OCCTSwift / OCCTSwiftMesh / OCCTSwiftTools / OCCTSwiftAIS / DrawingComposer usando el SDK MCP oficial de Swift. 77 herramientas. macOS 15+ (la plataforma arm64 de OCCT.xcframework).
  • Node / TypeScript (src/, dist/) — la implementación original. Se comunica con el CLI de occtkit para todo lo del lado Swift. 37 herramientas (la superficie previa a v0.4; selección / reasignación / anotaciones son solo Swift). Útil si no puedes ejecutar un binario de macOS.

Ambos hablan stdio MCP y leen/escriben el mismo formato de manifiesto.

Prerrequisitos

  • macOS 15+ (para la implementación Swift)
  • Swift 6.1+ / Xcode 16+
  • Solo para la implementación Node: Node.js 18+, más un clon hermano de OCCTSwiftScripts para que occtkit esté en $PATH (o make install él)

Configuración

Implementación Swift (recomendada)

git clone https://github.com/SecondMouseAU/OCCTMCP.git
cd OCCTMCP
swift build -c release

En .mcp.json de Claude Code:

{
  "mcpServers": {
    "occtmcp": {
      "command": "/path/to/OCCTMCP/.build/release/occtmcp-server"
    }
  }
}

El paquete Swift está publicado en el Swift Package Index.

Implementación Node

git clone https://github.com/SecondMouseAU/OCCTMCP.git
cd OCCTMCP
npm install
npm run build

En .mcp.json:

{
  "mcpServers": {
    "occtmcp": {
      "command": "node",
      "args": ["/path/to/OCCTMCP/dist/index.js"]
    }
  }
}

Ejemplo

El LLM puede autorar modelos CAD componiendo herramientas tipadas — la mayoría de los flujos cotidianos nunca tocan execute_script:

boolean_op(op: "subtract", aBodyId: "block", bBodyId: "hole", outputBodyId: "drilled")
  → "drilled" body added to the scene
select_topology(bodyId: "drilled", kind: "face", limit: 1)
  → returns selectionId "sel:drilled#face[12]"
add_dimension(kind: "linear", anchors: [...]) ; render_preview()

Para geometría novedosa, se puede entrar en execute_script con la API completa de OCCTSwift:

import OCCTSwift
import ScriptHarness

let ctx = ScriptContext()
let C = ScriptContext.Colors.self

let box = Shape.box(width: 40, height: 30, depth: 20)!
let hole = Shape.cylinder(radius: 5, height: 30)!
    .translated(by: SIMD3(20, -1, 10))!
let result = box.subtracting(hole)!
let filleted = result.filleted(radius: 2.0)!

try ctx.add(filleted, id: "part", color: C.steel, name: "Bracket")
try ctx.emit(description: "Filleted bracket with mounting hole")

Categorías de API

La herramienta get_api_reference proporciona documentación para:

  • primitivas — caja, cilindro, esfera, cono, toro, cuña
  • barridos — extruir, revolucionar, barrido de tubería, loft, reglado
  • booleanos — unión, resta, intersección, sección
  • modificaciones — redondeo, chaflán, cáscara, desplazamiento, conicidad, defeature
  • transformaciones — trasladar, rotar, escalar, reflejar
  • alambres — rectángulo, círculo, polígono, spline, hélice, desplazamiento
  • curvas2d/3d — línea, arco, elipse, bspline, bezier, interpolar
  • superficies — plano, cilindro, cono, esfera, extrusión, revolución, placa
  • análisis — volumen, área, distancia, límites, validación
  • import_export — STL, STEP, IGES, BREP, OBJ, PLY
  • mcp_tools — el JSON Schema de cada herramienta MCP (útil para auto-descubrimiento por LLM)

Versionado

OCCTMCP sigue Semantic Versioning. El puerto Swift alcanzó v1.0.0 el 2026-05-09 — con funcionalidad completa contra la implementación Node original, más una capa de herramientas de selección / reasignación / anotación que son solo Swift.

Los lanzamientos están etiquetados en GitHub. La rama main es la que sigue SPI.

Licencia

LGPL-2.1-o-posterior — igual que OCCTSwift.