Новый слой «модель как данные» (приоритетный над model_snapshot): - describe_model — структурный «паспорт» детали одним вызовом (габарит, МЦХ, тела, сводка топологии, дерево построения с параметрами, переменные) - list_features / list_bodies / list_variables - describe_face / describe_edge (drill-down по индексу) - measure (расстояние/угол между гранями/рёбрами/вершинами) - model_snapshot понижен до fallback для визуально-пространственных вопросов Реализация: ModelInspectionService (COM) + чистый InspectionText (рендер, группировка, детект «импорт без истории») + record-модели; InspectionTools. Дерево читается через ksPart.GetFeature()->SubFeatureCollection; точный тип и параметры операций берутся из GetObject()->GetDefinition() (ksFeature.type отдаёт лишь coarse o3d_entity). Снимок дерева также включает слои conversion (STEP), editing (move_face/solid) и validation, развивавшиеся параллельно. Полный прогон: 61 тест зелёный, 43 MCP-инструмента. Документация (README, ARCHITECTURE, OPEN_QUESTIONS, CLAUDE.md, presentation.html) синхронизирована. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
26 KiB
Архитектура MCP-сервера КОМПАС-3D (предлагаемый вариант)
Статус: реализовано и работает (v1+v2+STEP/assembly+direct-edit+inspection). Актуализировано по коду. Сопутствующий контекст по COM API КОМПАС — в
../CLAUDE.md. Имена интерфейсов и перечислений сверены со справкой SDK через.claude/skills/kompas-sdk-research/kdoc.py(навык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
Подключение к КОМПАС
- Разрешить 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 фиксировать в логе. - Attach к запущенному экземпляру:
Marshal.GetActiveObject(progId). Если не запущен — launch:Activator.CreateInstance(Type.GetTypeFromProgID(progId)). - Если зашли через API5 — получить современное приложение:
IApplication appl = (IApplication)kompas.ksGetApplication7();(черезKOMPAS.Application.7IApplicationуже на руках). 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) + интеграционные (требуют КОМПАС). 60 тестов. |
Принцип: только Core знает про COM. Host/Tools оперируют доменными DTO и вызывают Core; Host не содержит бизнес-логики.
Архитектурный принцип: MCP транслирует возможности SDK КОМПАС в общие инструменты (не под конкретную задачу). Методический слой поверх MCP — навык .claude/skills/kompas-3d/ (playbook'и, эвристики). Полигон отработки подходов — usecases/ (в .gitignore).
5. Карта инструментов (43 инструмента)
Сгруппированы вокруг центрального цикла «эскиз ↔ операция». Имена — 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_add_line/sketch_add_circle/sketch_add_arc/sketch_add_rectangle.sketch_close— завершить редактирование.- Жизненный цикл:
NewEntity(o3d_sketch)→SetPlane(plane|face)→BeginEdit()→ksLineSeg/ksCircle/ … →EndEdit().
Features (3D-операции)
extrude_boss/extrude_cut— sketch, depth, direction, endType.revolve_boss/revolve_cut— угол.rebuild— перестроить деталь.
Edit (прямое редактирование)
move_face— сдвинуть грань по мировой точке (x,y,z, мм) на distance мм вдоль нормали; distance>0 — наружу (добавить материал), <0 — внутрь. Работает на импортированной B-rep. Реализовано через API7IPart7.FindObjectsByPoint+FaceMover; контейнерыISurfaceContainer/IModelContainerполучаются COM-QI отIPart7в рантайме. Проверено: top_spacer 39.45→41.45 мм.
Selection / Query
get_part_info— МЦХ через API5ksPart.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# SDKModelContextProtocolэто поддерживает). Параметры: формат (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):
Document3D()/IKompasDocument3D→IPart7(вершинная деталь,pTop_Part).part.NewEntity(o3d_sketch)→GetDefinition()→SetPlane(базовая_плоскость | грань)→Create();BeginEdit()→ рисование примитивов (ksLineSeg,ksCircle,ksArcByPoint, …) →EndEdit().part.NewEntity(o3d_bossExtrusion)→ksBossExtrusionDefinition→SetSideParam(direction, ksEndTypeEnum, depth, …)→SetSketch(эскиз)→Create(). Для выреза —o3d_cutExtrusion; для вращения —o3d_bossRotated/o3d_cutRotated.- Выбор грани для следующего эскиза:
part.EntityCollection(o3d_face)→SelectByPoint(x, y, z)→ элемент коллекции как плоскость эскиза. - Снимок результата:
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. Сборка и запуск
dotnet build -c Release -r win-x64 # сборка
# → kompas-mcp.exe (self-contained, win-x64)
Регистрация stdio-сервера у клиента (пример для конфигурации Claude Desktop):
{
"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): документы, эскизы, выдавливание/вырез, вращение, скругление/фаска, снимок; get_part_info, get_bounding_box, list_faces, list_edges; import_step, export_step, list_components; move_face (прямое редактирование грани, работает на импортированной B-rep); describe_model, list_features, list_bodies, list_variables, describe_face, describe_edge, measure (структурный осмотр модели).
Следующие приоритеты:
- Рассечение/перемещение тела как MCP-инструменты (
SplitSolids/BodyRepositions) — механика есть, продуктизация не закончена. - Массивы (
ILinearPattern,ICircularPattern). - Свойства документа:
IPropertyMng/IPropertyKeeper. - Полноценное 2D-черчение: виды, линии/дуги/окружности, размеры (
ILinearDimension, …), штриховки, тексты. - Спецификации (
ISpecification), построение сборок и сопряжения. - Транспорт 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; менять не планируется.