345 lines
35 KiB
Markdown
345 lines
35 KiB
Markdown
# Архитектура MCP-сервера КОМПАС-3D (предлагаемый вариант)
|
||
|
||
> Статус: **реализовано и работает** (v1+v2+STEP/assembly+direct-edit+inspection+package-A «богатые эскизы»+package-B «shell+rib+sweep+loft»+package-C «массивы и зеркало»+package-E «offset plane»+`hole`+`draft`). Актуализировано по коду.
|
||
> Сопутствующий контекст по COM API КОМПАС — в [`../CLAUDE.md`](../CLAUDE.md).
|
||
> Имена интерфейсов и перечислений сверены со справкой SDK по MD-базе знаний `docs/Kompas3D_SDK/` (навык `kompas-sdk-research`).
|
||
|
||
---
|
||
|
||
## 1. Назначение и контекст
|
||
|
||
Строим **MCP-сервер**, который даёт LLM управлять CAD-системой **КОМПАС-3D** (АСКОН):
|
||
создавать/открывать документы, строить 2D-геометрию, 3D-детали и сборки, читать/писать
|
||
параметры, запускать команды.
|
||
|
||
Жёсткие рамки, заданные природой API:
|
||
|
||
- **Только Windows, только x64** — КОМПАС автоматизируется через **COM Automation API**;
|
||
разрядность сервера должна совпадать с разрядностью установленного КОМПАС.
|
||
- **КОМПАС должен быть установлен и запускаем на той же машине.** Сервер — это **COM-клиент**,
|
||
а не самостоятельный геометрический движок. Без работающего экземпляра КОМПАС инструменты
|
||
бесполезны.
|
||
- Целевая среда — **КОМПАС-3D v24 Home** (LT-редакция); часть возможностей полной редакции
|
||
может быть недоступна.
|
||
|
||
Две сосуществующие версии API (подробнее — `CLAUDE.md`):
|
||
|
||
| | Точка входа | Namespace (C#) | Когда |
|
||
|---|---|---|---|
|
||
| **API5** (legacy) | `KompasObject` | `Kompas6API5` | bootstrap-подключение, построение 3D через `ksPart` |
|
||
| **API7** (современный) | `IApplication` | `KompasAPI7` | всё новое: документы, параметры, операции |
|
||
|
||
---
|
||
|
||
## 2. Выбранный стек
|
||
|
||
| Решение | Выбор | Обоснование |
|
||
|---|---|---|
|
||
| Язык / платформа | **.NET 8 (LTS), C#, `win-x64`** | COM-интероп первого класса; SDK поставляет именно C#-примеры и `.tlb` |
|
||
| MCP SDK | **`ModelContextProtocol`** (официальный C# SDK) | хостинг через `Microsoft.Extensions.Hosting`, DI, готовый stdio-транспорт |
|
||
| Транспорт | **stdio** | локальный клиент (Claude Desktop / IDE) запускает сервер дочерним процессом на машине с КОМПАС — проще и безопаснее всего |
|
||
| COM-интероп | COM-references на `.tlb` из `SDK\lib` | строгая типизация интерфейсов API7 (`IApplication`, `IPart7`, …) на этапе компиляции |
|
||
| Логи | `Microsoft.Extensions.Logging` → **stderr** | **stdout занят протоколом MCP** — туда писать нельзя |
|
||
| Сериализация | `System.Text.Json` | штатно в .NET, без зависимостей |
|
||
|
||
Подключаемые типобиблиотеки (`C:\Program Files\ASCON\KOMPAS-3D v24 Home\SDK\lib`):
|
||
`kAPI5.tlb`, `kAPI7.tlb`, `ksConstants.tlb`, `ksConstants3D.tlb`, `kAPI2D5COM.tlb`, `kAPI3D5COM.tlb`.
|
||
Namespaces: `Kompas6API5`, `KompasAPI7`, `Kompas6Constants`, `Kompas6Constants3D`, `KAPITypes`.
|
||
|
||
### Почему C#, а не Python
|
||
|
||
Python (comtypes/pywin32) технически способен управлять COM, но КОМПАС-API активно использует
|
||
конструкции, болезненные для динамического интеропа: `out`/`ref`-параметры (например,
|
||
`ExecuteKompasCommand(commandID, post, &retval)`), `SAFEARRAY`/динамические массивы
|
||
(`ksDynamicArray`, `ksLtVariant`), мосты API5↔API7 (`ksGetApplication7`, `TransferInterface`) и
|
||
обязательный STA + насос сообщений. В C# всё это покрыто строго типизированным interop, что
|
||
снижает риск и стоимость поддержки.
|
||
|
||
---
|
||
|
||
## 3. Модель процесса и потоков (ключевой раздел)
|
||
|
||
COM-объекты КОМПАС живут в **STA (Single-Threaded Apartment)**, экземпляр приложения —
|
||
**единственный** и **однопоточный**. Отсюда — центральное архитектурное ограничение:
|
||
|
||
- Сервер держит **один выделенный STA-поток**, который **владеет всеми без исключения
|
||
COM-вызовами**. Асинхронные обработчики MCP-инструментов (поток-пул) **маршалят** работу в этот
|
||
поток через очередь/диспетчер (например, `BlockingCollection<Func<…>>` или собственный
|
||
`SynchronizationContext`). Это автоматически **сериализует** доступ к КОМПАС.
|
||
- STA-поток крутит **насос сообщений Windows** и периодически вызывает
|
||
`IApplication.PumpWaitingMessages()` / при необходимости `EnableTaskAccess(false)` на время
|
||
пакетных операций — чтобы диалоги и колбэки КОМПАС не приводили к взаимоблокировке.
|
||
|
||
```
|
||
MCP client ──stdio──> Host (поток-пул, async)
|
||
│ ставит задачу в очередь
|
||
▼
|
||
┌─────────────────────────┐
|
||
│ STA-поток (COM owner) │ ← насос сообщений + PumpWaitingMessages
|
||
│ KompasObject / IApplication
|
||
└─────────────────────────┘
|
||
│ COM
|
||
▼
|
||
КОМПАС-3D.exe
|
||
```
|
||
|
||
### Подключение к КОМПАС
|
||
|
||
1. Разрешить ProgID. На целевой машине (v24 Home) **проверено**: зарегистрированы
|
||
`KOMPAS.Application.7` и `KOMPAS.Application.5`, а `KOMPASLT.*` **отсутствует** — то есть
|
||
Home-редакция использует обычные ProgID, а не LT. Порядок попыток:
|
||
`KOMPAS.Application.7` (прямой API7) → `KOMPAS.Application.5` (+ `ksGetApplication7()`) →
|
||
`KOMPASLT.Application.5` (запасной, для других инсталляций). Выбранный ProgID фиксировать в логе.
|
||
2. **Attach** к запущенному экземпляру: `Marshal.GetActiveObject(progId)`.
|
||
Если не запущен — **launch**: `Activator.CreateInstance(Type.GetTypeFromProgID(progId))`.
|
||
3. Если зашли через API5 — получить современное приложение:
|
||
`IApplication appl = (IApplication)kompas.ksGetApplication7();` (через `KOMPAS.Application.7` `IApplication` уже на руках).
|
||
4. `appl.Visible = true;` — показать окно КОМПАС; дальше работать через интерфейсы API7.
|
||
|
||
### Жизненный цикл COM
|
||
|
||
- Корневые RCW (`KompasObject`, `IApplication`) держим на всё время жизни сервера.
|
||
- Временные объекты освобождаем (`Marshal.ReleaseComObject`) в обратном порядке создания.
|
||
- `appl.Quit()` вызываем **только если экземпляр запустили мы сами** (флаг «launched-by-us»);
|
||
к чужому запущенному КОМПАС не применяем.
|
||
|
||
---
|
||
|
||
## 4. Слои решения
|
||
|
||
Проекты solution `KompasMcp.slnx` (спайк-проекты ConnectSpike/ReconSpike удалены; их механика покрыта тестами):
|
||
|
||
| Проект | Ответственность |
|
||
|---|---|
|
||
| **Kompas.Mcp.Host** | Точка входа. Сборка MCP-сервера (stdio), DI (в т.ч. `ConversionService`), логи в stderr, старт и владение STA-потоком, graceful shutdown. Определения инструментов по категориям (System / Documents / Sketch / Features / Query / Conversion). **Тонкий слой**: валидация аргументов → постановка задачи на STA-поток → форматирование результата/ошибки в MCP-ответ. |
|
||
| **Kompas.Mcp.Core** | COM-слой. Менеджер соединения, менеджер документов, построитель эскизов и операций, `ConversionService` (STEP импорт/экспорт), `QueryService` (МЦХ, грани, рёбра, компоненты), `ModelInspectionService` (дерево операций, тела, переменные, drill-down, измерения), снимок. Все паттерны API5/API7 живут здесь. |
|
||
| **Kompas.Mcp.Tests** | Юнит (без COM) + интеграционные (требуют КОМПАС). 115 тестов (69 unit + 46 integration). |
|
||
|
||
Принцип: **только `Core` знает про COM**. `Host`/Tools оперируют доменными DTO и вызывают `Core`; `Host` не содержит бизнес-логики.
|
||
|
||
Архитектурный принцип: **MCP транслирует возможности SDK КОМПАС в общие инструменты** (не под конкретную задачу). Методический слой поверх MCP — навык `.claude/skills/kompas-3d/` (playbook'и, эвристики). Полигон отработки подходов — `usecases/` (в .gitignore).
|
||
|
||
---
|
||
|
||
## 5. Карта инструментов (64 инструмента)
|
||
|
||
Сгруппированы вокруг центрального цикла «эскиз ↔ операция». Имена — `snake_case`.
|
||
|
||
**System**
|
||
- `kompas_connect` — attach/launch, возвращает версию и редакцию (`GetSystemVersion`, `ApplicationName`).
|
||
- `kompas_set_visible` — показать/скрыть окно (`IApplication.Visible`).
|
||
- `kompas_status` — состояние соединения, активный документ.
|
||
|
||
**Documents** (`IApplication.Documents` → `IDocuments`)
|
||
- `document_create` — тип `part | assembly | drawing | fragment` (`DocumentTypeEnum`: Part=4, Assembly=5, Drawing=1, Fragment=2).
|
||
- `document_open` / `document_save` / `document_close` / `document_active`.
|
||
|
||
**Sketch** (2D-геометрия внутри 3D-эскиза)
|
||
- `sketch_create` — на базовой плоскости (`o3d_planeXOY` / `XOZ` / `YOZ`) или на выбранной грани.
|
||
- `sketch_create_on_offset_plane` — эскиз на плоскости, смещённой от базовой (XOY/XOZ/YOZ) на `offset` мм; вспомогательная геометрия через `o3d_planeOffset=14` / `ksPlaneOffsetDefinition`. Разблокирует `loft` (параллельные сечения на разной высоте). Начало пакета E «вспомогательная геометрия».
|
||
- `sketch_add_line` / `sketch_add_circle` / `sketch_add_arc` / `sketch_add_arc_3points` / `sketch_add_rectangle`.
|
||
- `sketch_add_ellipse` (centre, semi-axes A/B, rotation angle) / `sketch_add_polyline` (point chain, closed) / `sketch_add_polygon` (regular, inscribed/circumscribed) / `sketch_add_spline` (cubic NURBS, closed) / `sketch_add_point`.
|
||
- `sketch_close` — завершить редактирование.
|
||
- Жизненный цикл: `NewEntity(o3d_sketch)` → `SetPlane(plane|face)` → `BeginEdit()` →
|
||
`ksLineSeg` / `ksCircle` / `ksArcBy3Points` / `ksArcByAngle` / `ksEllipse` / `ksRegularPolygon` / `ksNurbs` / … → `EndEdit()`.
|
||
- `PartModeler` split into partial classes: `PartModeler.cs` (core), `PartModeler.Sketch.cs`, `PartModeler.Features.cs`. Static `SketchGeometry` class holds mappings and validators. Point lists use `record SketchPoint(X, Y)` (JSON `x`/`y`). All angles in degrees.
|
||
- `CoordinateAxis.cs` (`src/Kompas.Mcp.Core/Modeling/`) — enum `CoordinateAxis {X,Y,Z}` + `CoordinateAxes.ToObj3dType/Parse` (→ `o3d_axisOX/OY/OZ = 71/72/73`), analogous to `BasePlane.cs`.
|
||
|
||
**Features** (3D-операции)
|
||
- `extrude_boss` / `extrude_cut` — sketch, depth, direction, endType.
|
||
- `revolve_boss` / `revolve_cut` — угол.
|
||
- `shell` — превратить тело в оболочку: открыть грани по индексам (`faceIndices`, ≥1, из `list_faces`), задать толщину стенки (`thickness` мм), направление (`outward`, по умолчанию внутрь). Реализовано через API5 `ksPart.NewEntity(o3d_shellOperation=43)` → `ksShellDefinition` → `FaceArray()` → `Create()`. Маппинг: `thinType = !outward`.
|
||
- `rib` — построить ребро жёсткости от разомкнутого контура эскиза до тела. Параметры: `sketchId`, `thickness` (мм), `side` (`left|right|up|down` → 0/1/2/3), `symmetric` (толщина симметрична плоскости), `angle` (уклон стенок, °). Реализовано через `ksPart.NewEntity(o3d_ribOperation=44)` → `ksRibDefinition` (`SetSketch`, `SetThinParam`). `symmetric=true`: `SetThinParam(dtBoth, t/2, t/2)`; иначе `SetThinParam(dtNormal, t, 0)`. Контур должен не касаться тела концами — КОМПАС дотягивает полотно сам.
|
||
- `sweep` — кинематическая операция: перемещение замкнутого профиля (эскиз `profileSketchId`) вдоль траектории (эскиз `pathSketchId`), образуя сплошное тело. Профиль и траектория на разных (обычно перпендикулярных) плоскостях. Реализовано через `ksPart.NewEntity(o3d_baseEvolution=45)` → `ksBaseEvolutionDefinition` (`SetSketch(профиль)` → `PathPartArray().Add(траектория)` → `sketchShiftType=0` → `SetThinParam(false)`) → `Create()`. Валидация: `profileSketchId != pathSketchId`.
|
||
- `loft` — операция по сечениям: построить сплошное тело по ≥2 закрытым эскизам-сечениям на параллельных плоскостях. Реализовано через `ksPart.NewEntity(o3d_baseLoft=30)` → `ksBaseLoftDefinition` (`Sketchs().Add(каждое сечение)` → `SetLoftParam(closed=false,false,true)` → `SetThinParam(false)`) → `Create()`. Для сечений не на базовых плоскостях использовать `sketch_create_on_offset_plane`.
|
||
- `linear_pattern` — линейный массив операций вдоль координатной оси (`o3d_meshCopy=35`, `ksMeshCopyDefinition`); параметры: `featureIds[]`, `axis` (X/Y/Z), `count` (включает исходный, ≥2), `step` (мм). `SetAxis1` + `SetCopyParamAlongAxis(true,0,count,step,false)` + `count2=1` (выключает 2-е направление).
|
||
- `circular_pattern` — круговой массив вокруг координатной оси (`o3d_circularCopy=36`, `ksCircularCopyDefinition`); параметры: `featureIds[]`, `axis`, `count`, `step` (угол° между соседними), `reverse`, `geometric`. Свойства `count1=1`/`count2=count`/`step2=angle°`/`factor2=false`/`inverce=reverse` задаются напрямую; `GetOperationArray()`.
|
||
- `mirror_operation` — зеркальная копия операций (`o3d_mirrorOperation=48`, `ksMirrorCopyDefinition`); параметры: `featureIds[]`, `plane` (XOY/XOZ/YOZ). `SetPlane` + `GetOperationArray()`.
|
||
- `mirror_body` — зеркало всего тела (`o3d_mirrorAllOperation=49`, `ksMirrorCopyAllDefinition`); параметр: `plane`. `ChooseBodies()` не приводится к `ksChooseBodies` и не нужен — операция отражает все тела, сохраняя оригинал (объём удваивается).
|
||
- `hole` — цилиндрическое отверстие (сквозное или глухое) на грани, найденной по мировой точке (x,y,z). Параметры: `diameter` (мм), `depth` (мм, для глухого), `throughAll`. Реализовано через **API7** (`HoleService`, `src/Kompas.Mcp.Core/Modeling/HoleService.cs`) — в API5 интерфейс `ksHoleDefinition` отсутствует в interop. Паттерн: `(IModelContainer)part7` → `Points3D.Add()` (центр, `IPoint3D`) → `Holes3D.Add()` → `IHole3D` (`HoleType=ksHTBase`, `Diameter`, `DepthType`, `Depth`, `EndFaceType=ksEFFlat`) → `(IHoleDisposal)hole` (`BaseSurface=грань` через `FindObjectsByPoint`, `Perpendicular=true`, `AssociationVertex=point`) → `Update()` → `RebuildDocument()`. Направление сверления определяется **по факту убыли объёма**: `Direction=true` → Rebuild → сравнить объём (API5 `CalcMassInertiaProperties`); если не убыл → `Direction=false`. При неуспехе — откат через `IFeature7.Delete()`. Возвращает подтверждение без id (отверстие не попадает в реестр `_features` API5).
|
||
- `draft` — уклон граней на угол `angle` (°, строго 0–90) относительно нейтральной координатной плоскости `neutralPlane` (XOY/XOZ/YOZ). `outward=true` — расширение (добавляет материал), `false` — сужение. Реализовано через **API5** `ksInclineDefinition` (`o3d_incline=42`) — операция называется Incline в API5, а не Draft. Паттерн: `ksPart.NewEntity(o3d_incline)` → `GetDefinition() as ksInclineDefinition` → `FaceArray()` (грани по индексам из `list_faces`) → `SetPlane(базовая координатная плоскость)` → `angle` → `direction=!outward` → `Create()` → регистрация в `_features`. Эмпирика: `direction=false`=расширение, `direction=true`=сужение — **обратно справке** → маппинг `def.direction = !outward`. Валидация: `RequireDraftAngle(0<angle<90)`. Регистрируется в `_features` → применимы массивы и зеркало (пакет C).
|
||
- `rebuild` — перестроить деталь.
|
||
|
||
**Edit** (прямое редактирование)
|
||
- `move_face` — сдвинуть грань по мировой точке (x,y,z, мм) на distance мм вдоль нормали; distance>0 — наружу (добавить материал), <0 — внутрь. Работает на импортированной B-rep. Реализовано через API7 `IPart7.FindObjectsByPoint` + `FaceMover`; контейнеры `ISurfaceContainer`/`IModelContainer` получаются COM-QI от `IPart7` в рантайме. Проверено: top_spacer 39.45→41.45 мм.
|
||
- `split_solid_by_plane` — рассечь тело плоскостью (по грани или базовой плоскости).
|
||
- `move_body` — переместить тело на заданный вектор (dx/dy/dz, мм).
|
||
- `boolean_union` — булева операция объединения тел.
|
||
|
||
**Selection / Query**
|
||
- `get_part_info` — МЦХ через API5 `ksPart.CalcMassInertiaProperties(ST_MIX_MM|ST_MIX_KG)`.
|
||
- `get_bounding_box` — габарит (`ksPart.GetGabarit`).
|
||
- `list_faces` / `list_edges` — перечислить грани и рёбра детали с классификацией и мерами.
|
||
- `list_components` — перечислить компоненты верхнего уровня сборки (индекс, имя, обозначение, признак детали, габарит) через `TopPart → IParts7`.
|
||
|
||
**Conversion** (`ConversionTools.cs`, `ConversionService.cs`)
|
||
- `import_step` — импорт .step/.stp в новый документ через встроенный конвертер КОМПАС (код `ksConverterFromSTEP=-3`); параметры `type` (assembly|part), `createComponentFiles`.
|
||
- `export_step` — экспорт активного 3D-документа в STEP; `format` = auto|ap203|ap214|ap242.
|
||
|
||
**Inspection — структурный осмотр модели (приоритетный над снимком)**
|
||
- `describe_model` — структурный «паспорт» детали одним вызовом: габарит, МЦХ, тела, сводка топологии (грани/рёбра по типам), дерево построения с параметрами, переменные. **Предпочитать перед `model_snapshot`** — не тратит токены изображения.
|
||
- `list_features` — дерево построения с параметрами (глубина/радиус/катеты), имена узлов локализованы КОМПАС.
|
||
- `list_bodies` — тела детали: тип (твёрдое/поверхность) и число граней.
|
||
- `list_variables` — переменные модели (имя/выражение/значение, флаги external/информационная).
|
||
- `describe_face` — drill-down грани по индексу: тип, площадь, нормаль, радиус, число рёбер.
|
||
- `describe_edge` — drill-down ребра по индексу: тип, длина, смежные грани, концевые вершины.
|
||
- `measure` — расстояние и угол между двумя объектами (face|edge|vertex по индексам), единица `ST_MIX_MM`.
|
||
|
||
Реализовано через `ModelInspectionService` (`src/Kompas.Mcp.Core/Query/ModelInspectionService.cs`),
|
||
рендер текста — `InspectionText` (`InspectionText.cs`, юнит-тестируем без COM).
|
||
Ключевые API-паттерны: `ksPart.GetFeature()` → `ksFeatureCollection` (дерево); `BodyCollection()` → `ksBody`; `VariableCollection()` → `ksVariable`; `GetMeasurer()` → `ksMeasurer`.
|
||
«Импорт STEP без истории» определяется структурно: `bodyCount > 0 && нет формообразующих операций && features.Count <= bodyCount+1`.
|
||
|
||
**Vision — визуальная обратная связь (fallback)**
|
||
- `model_snapshot` — отрендерить активный 3D-документ в PNG и вернуть **как image-контент MCP**,
|
||
чтобы мультимодальный агент *увидел* промежуточный результат. Использовать для визуально-пространственных
|
||
вопросов, когда структурный осмотр (`describe_model`) недостаточен.
|
||
- `set_view` — задать ориентацию вида (`iso` / `front` / `top` / `right` / …), zoom-to-fit и режим
|
||
отображения (`ShadedWireframe`) перед снимком — иначе снимок берётся со случайного текущего ракурса.
|
||
|
||
> **Механизм.** `ksDocument3D.RasterFormatParam()` → `IRasterFormatParam` рендерит документ в растр;
|
||
> свойство **`resultArrayBytes`** возвращает изображение как **массив байт в память** (без временного
|
||
> файла). Альтернатива — экспортные функции `ksSaveAsToRasterFormat[W]`. Полученные байты сервер
|
||
> упаковывает в image-контент MCP-ответа (C# SDK `ModelContextProtocol` это поддерживает).
|
||
> Параметры: формат (PNG/JPEG/BMP/TIFF), разрешение, цвет/`greyScale`.
|
||
> Снимки делать после значимых операций (не после каждой линии) — каждый кадр расходует
|
||
> токены изображения в контексте агента. На v24 Home качество/доступность рендера проверить на прототипе.
|
||
|
||
**Escape hatch (опционально)**
|
||
- `run_kompas_command` — `IApplication.ExecuteKompasCommand(commandID, post)` для команд,
|
||
ещё не обёрнутых в типизированные инструменты. Доступность проверять через
|
||
`IsKompasCommandEnable`.
|
||
|
||
### Замечание об API5 vs API7 для 3D-операций
|
||
|
||
API7 создаёт операции через `IPart7` → (QueryInterface) `IModelContainer` → `IExtrusions.Add()`
|
||
→ `IExtrusion`. Примеры SDK при этом активно используют **API5-путь** (`ksPart.NewEntity(o3d_…)` →
|
||
`ksBossExtrusionDefinition.SetSideParam/SetSketch` → `Create()`), который хорошо документирован.
|
||
**Стратегия v1:** предпочитать API7 там, где он покрывает операцию; падать на API5 `ksPart`-путь
|
||
там, где он проще/надёжнее (мост — `kompas.TransferInterface`). Выбор фиксировать в `Core`.
|
||
|
||
---
|
||
|
||
## 6. Центральный сценарий: цикл «эскиз → операция → эскиз»
|
||
|
||
Основной пользовательский поток v1 — итеративное параметрическое моделирование.
|
||
|
||
```
|
||
document_create(part)
|
||
│
|
||
▼
|
||
sketch_create(plane = XOY) ──► sketch_add_circle(...) ──► sketch_close
|
||
│
|
||
▼
|
||
extrude_boss(sketch, depth=…, dir=dtNormal, end=etBlind) → цилиндр
|
||
│
|
||
▼
|
||
set_view(iso, fit) → model_snapshot 👁 агент СМОТРИТ на результат и решает следующий шаг
|
||
│
|
||
▼
|
||
select_face_by_point(x,y,z) ← выбираем верхнюю грань
|
||
│
|
||
▼
|
||
sketch_create(face = выбранная) ──► sketch_add_circle(...) ──► sketch_close
|
||
│
|
||
▼
|
||
extrude_cut(sketch, depth=…) → отверстие
|
||
│
|
||
▼
|
||
model_snapshot 👁 проверка результата
|
||
│
|
||
└──────────► повторять: смотрим → новая грань → новый эскиз → новая операция
|
||
```
|
||
|
||
Соответствие API (на STA-потоке, через `Core`):
|
||
|
||
1. `Document3D()` / `IKompasDocument3D` → `IPart7` (вершинная деталь, `pTop_Part`).
|
||
2. `part.NewEntity(o3d_sketch)` → `GetDefinition()` → `SetPlane(базовая_плоскость | грань)` →
|
||
`Create()`; `BeginEdit()` → рисование примитивов (`ksLineSeg`, `ksCircle`, `ksArcByPoint`, …) →
|
||
`EndEdit()`.
|
||
3. `part.NewEntity(o3d_bossExtrusion)` → `ksBossExtrusionDefinition` →
|
||
`SetSideParam(direction, ksEndTypeEnum, depth, …)` → `SetSketch(эскиз)` → `Create()`.
|
||
Для выреза — `o3d_cutExtrusion`; для вращения — `o3d_bossRotated`/`o3d_cutRotated`.
|
||
4. Выбор грани для следующего эскиза:
|
||
`part.EntityCollection(o3d_face)` → `SelectByPoint(x, y, z)` → элемент коллекции как плоскость
|
||
эскиза.
|
||
5. Снимок результата: `set_view` (ориентация + fit) → `ksDocument3D.RasterFormatParam()` →
|
||
`IRasterFormatParam.resultArrayBytes` → image-контент MCP. Агент анализирует кадр и выбирает
|
||
следующий шаг.
|
||
|
||
Используемые перечисления: `ksDirectionTypeEnum` (`dtNormal`/`dtReverse`/`dtBoth`/`dtMiddlePlane`),
|
||
`ksEndTypeEnum` (`etBlind`/`etThroughAll`/`etUpTo…`), `Obj3dType` (`o3d_sketch`, `o3d_bossExtrusion`,
|
||
`o3d_cutExtrusion`, `o3d_face`, `o3d_planeXOY`, …).
|
||
|
||
---
|
||
|
||
## 7. Обработка ошибок и безопасность
|
||
|
||
- **Трансляция ошибок COM** в структурированные MCP-ошибки: проверять HRESULT каждого вызова и
|
||
опрашивать `kompas.ksGetLastError()` / `IApplication.KompasError`; возвращать клиенту код + текст.
|
||
- **Null-чек после каждого приведения** COM-интерфейса (любой каст может вернуть `null`).
|
||
- **`.Init()` на param-структурах** перед использованием (`GetParamStruct(...)` → `.Init()`).
|
||
- **Гарантированный `EndEdit`** для эскизов через `try/finally` — незакрытый эскиз ломает документ.
|
||
- **Подтверждение деструктивных операций**: закрытие без сохранения, перезапись файла, `Quit` —
|
||
только по явному флагу в аргументах инструмента.
|
||
- **Модель состояния**: инструменты по умолчанию работают с «активным документом»; опционально —
|
||
явный хэндл/идентификатор документа.
|
||
|
||
---
|
||
|
||
## 8. Сборка и запуск
|
||
|
||
```powershell
|
||
dotnet build -c Release -r win-x64 # сборка
|
||
# → kompas-mcp.exe (self-contained, win-x64)
|
||
```
|
||
|
||
Регистрация stdio-сервера у клиента (пример для конфигурации Claude Desktop):
|
||
|
||
```json
|
||
{
|
||
"mcpServers": {
|
||
"kompas3d": { "command": "C:\\path\\to\\kompas-mcp.exe", "args": [] }
|
||
}
|
||
}
|
||
```
|
||
|
||
**Ручная проверка (smoke):** запустить КОМПАС (или дать серверу запустить его) → через инструменты
|
||
построить простую деталь (выдавить окружность в цилиндр, затем `extrude_cut` — отверстие) →
|
||
убедиться визуально в окне КОМПАС → сохранить `.m3d`.
|
||
|
||
---
|
||
|
||
## 9. Стратегия тестирования
|
||
|
||
- **Интеграционные тесты** (требуют установленного КОМПАС): xUnit, категория `Integration`,
|
||
гейтятся (не идут в обычном CI без КОМПАС). Покрывают связку Core↔COM и центральный цикл.
|
||
- **Unit-тесты** чистой логики **без COM**: маппинг строк↔перечислений, валидация аргументов,
|
||
форматирование результатов/ошибок.
|
||
- **Smoke MCP**: проверка протокола через **MCP Inspector** или тестовый клиент (list tools, вызов
|
||
`kompas_connect`/`document_create`).
|
||
|
||
---
|
||
|
||
## 10. Дорожная карта
|
||
|
||
**Реализовано (v1+v2+STEP/assembly+direct-edit+inspection+package-A+package-B+package-C+package-E start+hole+draft):** документы, эскизы (полный набор 2D-примитивов: линия, окружность, дуга, дуга по 3 точкам, прямоугольник, эллипс, ломаная, правильный многоугольник, сплайн NURBS, точка), **вспомогательная геометрия (`sketch_create_on_offset_plane`)**, выдавливание/вырез, вращение, скругление/фаска, **оболочка (`shell`)**, **ребро жёсткости (`rib`)**, **кинематическая операция (`sweep`)**, **операция по сечениям (`loft`)**, **линейный/круговой массив и зеркало (`linear_pattern`, `circular_pattern`, `mirror_operation`, `mirror_body`)**, **отверстие (`hole`, API7)**, **уклон (`draft`, API5 `ksInclineDefinition`)**, снимок; `get_part_info`, `get_bounding_box`, `list_faces`, `list_edges`; `import_step`, `export_step`, `list_components`; **`move_face`**, **`split_solid_by_plane`**, **`move_body`**, **`boolean_union`** (прямое редактирование и булевы операции); **`describe_model`, `list_features`, `list_bodies`, `list_variables`, `describe_face`, `describe_edge`, `measure`** (структурный осмотр модели).
|
||
|
||
**Следующие приоритеты:**
|
||
1. Пакет E «вспомогательная геометрия» (продолжение) — ось, точка, плоскость по трём точкам / по углу.
|
||
4. Рассечение/перемещение тела как MCP-инструменты (`SplitSolids`/`BodyRepositions`) — механика есть, продуктизация не закончена.
|
||
5. Свойства документа: `IPropertyMng` / `IPropertyKeeper`.
|
||
6. Полноценное 2D-черчение: виды, линии/дуги/окружности, размеры (`ILinearDimension`, …), штриховки, тексты.
|
||
7. Спецификации (`ISpecification`), построение сборок и сопряжения.
|
||
8. Транспорт **HTTP/SSE** — как опция для удалённых клиентов.
|
||
|
||
---
|
||
|
||
## 11. Открытые вопросы
|
||
|
||
- **Прямое редактирование B-rep, перемещение грани**: решено — `move_face` (`FaceEditService`) работает через `IPart7.FindObjectsByPoint` + `FaceMover`; проверено на импортированной B-rep. Рассечение/перемещение тела (`SplitSolids`/`BodyRepositions`) — механика есть, инструменты не реализованы (потенциальная следующая опция).
|
||
- **Дерево операций, тела, переменные, геометрические запросы**: решено — `ModelInspectionService` + `InspectionTools` (7 инструментов); юнит-тестируемый рендер через `InspectionText`.
|
||
- **Утечки транзитных RCW** в `PartModeler` (унаследованный паттерн): `EntityCollection`, `GetTopPart()` не освобождаются, накапливаются за длинную сессию.
|
||
- **Насос сообщений / CancellationToken**: `CancellationToken` не прерывает идущий COM-вызов; зависший модальный диалог КОМПАС блокирует всю очередь.
|
||
- **Embed Interop Types vs вендорские interop-сборки**: выбраны вендорские DLL из SDK `Samples/Common`; менять не планируется.
|