Files
kompas3d-mcp/docs/ARCHITECTURE.md
T

57 KiB
Raw Blame History

Архитектура MCP-сервера КОМПАС-3D (предлагаемый вариант)

Статус: реализовано и работает (v1+v2+STEP/assembly+direct-edit+inspection+package-A «богатые эскизы»+package-B «shell+rib+sweep+loft»+package-C «массивы и зеркало»+package-D start «переменные»+package-E «offset plane»+hole+hole_counterbore+hole_countersink+hole_conic+draft+assembly_add_component+assembly_add_mate+drawing_create_standard_views+drawing_fill_title_block+drawing_add_linear_dimension+drawing_add_diametral_dimension+drawing_add_radial_dimension+drawing_add_angular_dimension+drawing_add_rough+drawing_add_text+drawing_set_technical_requirements+ассоциативная привязка диаметрального/радиального к окружности (веха «2D-чертёж», инкремент 7)). Актуализировано по коду. Сопутствующий контекст по COM API КОМПАС — в ../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.Loggingstderr 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, измерения), AssemblyService (вставка компонентов в сборку, namespace Kompas.Mcp.Core.Assemblies), DrawingService (стандартные виды чертежа, namespace Kompas.Mcp.Core.Drawings), снимок. Все паттерны API5/API7 живут здесь.
Kompas.Mcp.Tests Юнит (без COM) + интеграционные (требуют КОМПАС). 278 тестов (168 unit + 110 integration). Все интеграционные классы наследуют IntegrationTestBase (IAsyncLifetime), который вызывает DocumentService.CloseAllAsync после каждого теста.

Принцип: только Core знает про COM. Host/Tools оперируют доменными DTO и вызывают Core; Host не содержит бизнес-логики.

Архитектурный принцип: MCP транслирует возможности SDK КОМПАС в общие инструменты (не под конкретную задачу). Методический слой поверх MCP — навык .claude/skills/kompas-3d/ (playbook'и, эвристики). Полигон отработки подходов — usecases/ (в .gitignore). Отдельный навык .claude/skills/kompas-fdm-design/ — DFM-методика для FDM/FFF 3D-печати (нависания, толщины, teardrop-отверстия, посадки, ориентация под прочность, elephant foot, бобышки/инсёрты/защёлки) с лёгким гео-аудитом через существующие Inspection-инструменты; работает поверх kompas-3d, слайсер вне границ.


5. Карта инструментов (81 инструмент)

Сгруппированы вокруг центрального цикла «эскиз ↔ операция». Имена — snake_case.

System

  • kompas_connect — attach/launch, возвращает версию и редакцию (GetSystemVersion, ApplicationName).
  • kompas_set_visible — показать/скрыть окно (IApplication.Visible).
  • kompas_status — состояние соединения, активный документ.

Documents (IApplication.DocumentsIDocuments)

  • 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)ksShellDefinitionFaceArray()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=0SetThinParam(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)part7Points3D.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).
  • hole_counterbore — отверстие с цековкой (цилиндрическое уширение сверху, под винт с цилиндрической головкой). Параметры: x,y,z, diameter, spotfaceDiameter (>diameter), spotfaceDepth, depth=0, throughAll=false. HoleType=ksHTCounterbore; HoleParameters приводится к ISpotfacingHoleParameters (SpotfacingDiameter, SpotfacingDepth) — настройка через configure-колбэк после фиксации типа. Для глухого: валидируется depth>spotDepth.
  • hole_countersink — отверстие с зенковкой (коническое уширение сверху, под винт с потайной головкой). Параметры: x,y,z, diameter, sinkDiameter (>diameter), sinkAngle (0<angle<180, типично 90°), depth=0, throughAll=false. HoleType=ksHTCountersinking; HoleParametersICountersinkHoleParameters (CountersinkType=ksCTDiameterAngle, CountersinkDiameter, CountersinkAngle). Все три инструмента отверстий используют общую логику размещения и подбора направления (HoleCore).
  • hole_conic — коническое (конусное) отверстие, сужающееся вглубь. Параметры: x,y,z, diameter (диаметр у основания/поверхности), conicAngle (угол конуса, 0<angle<180°), depth=0, throughAll=false. HoleType=ksHTConic; HoleParametersIConicHoleParameters (ConicType=ksCNAngle, ConicAngle). Завершает набор типов отверстий (простое, цековка, зенковка, коническое).
  • 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 ksInclineDefinitionFaceArray() (грани по индексам из list_faces) → SetPlane(базовая координатная плоскость)angledirection=!outwardCreate() → регистрация в _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; ksPart.GetFeature().VariableCollectionksVariable (все переменные; ksPart.VariableCollection() — только внешние); GetMeasurer()ksMeasurer. «Импорт STEP без истории» определяется структурно: bodyCount > 0 && нет формообразующих операций && features.Count <= bodyCount+1.

Variables — управление переменными модели (package D start)

  • create_variable — создать переменную (имя, начальное значение, примечание, флаг внешней).
  • set_variable — задать выражение (константа "30" или формула "width*2+5"); десятичный разделитель — точка; модель перестраивается, зависимые переменные пересчитываются.
  • delete_variable — удалить переменную (нельзя при наличии зависимых).

Реализовано через VariableService (src/Kompas.Mcp.Core/Modeling/VariableService.cs, API5), инструменты — VariableTools (src/Kompas.Mcp.Host/Tools/VariableTools.cs). DI: AddSingleton<VariableService>() в Program.cs.

Ключевые API-паттерны: создание — ТОЛЬКО через ksPart.GetFeature().VariableCollection (свойство корневого ksFeature), а НЕ ksPart.VariableCollection() (та возвращает только внешние); Expression — ведущее поле, Value — вычисленный результат; изменение через Expression + ksPart.RebuildModel(); после rebuild RCW переменной стал; значение перечитывается через свежую коллекцию (ReadValueFresh).

Ограничение: переменная управляет геометрией только в параметрической модели, где размеры эскизов привязаны к именам переменных. Наши эскизы строятся литеральными координатами — set_variable хранит и вычисляет значение, но геометрию не меняет. Связь размеров эскизов с переменными (параметрические эскизы через API2D) — не реализована (package D продолжение).

Assembly — построение сборок (AssemblyService, AssemblyTools, namespace Kompas.Mcp.Core.Assemblies)

  • assembly_add_component — вставить компонент (.m3d деталь или .a3d подсборка) из файла в активную сборку; задать положение origin (x,y,z мм, мировая СК сборки). Возвращает индекс и имя вставленного компонента. Реализовано через API7: IParts7.AddFromFile(path, ExternalFile=true, Redraw=true)IPart7IPlacement3D.SetOrigin(x,y,z)UpdatePlacement(true)RebuildModel(true). RequireActiveAssembly проверяет doc.DocumentType == ksDocumentAssembly до обращения к TopPart. Откат при неуспехе через IFeature7.Delete. DI: AddSingleton<AssemblyService>() в Program.cs.
  • assembly_add_mate — наложить сопряжение между гранями двух компонентов активной сборки по мировым точкам. Параметры: mateType (coincidence — грани заподлицо | distance — зазор value мм), x1,y1,z1, x2,y2,z2, value=0. Решатель позиционирует компоненты; возвращает статус valid. Реализовано через API7: top.MateConstraints (IMateConstraints3D) → Add(MateConstraintType)BaseObject1/2 (грани через top.FindObjectsByPoint(x,y,z,FirstLevel=false)) → ParamValueUpdate()RebuildModel(true); проверка mate.Valid (false → ошибка + откат mate.Owner.Delete). Enum MateType { Coincidence, Distance } в src/Kompas.Mcp.Core/Assemblies/MateType.cs; маппинг на MateConstraintType (mc_Coincidence=0, mc_Distance=5). Scope: coincidence/distance проверены вживую; прочие типы (parallel, concentric, …) — будущие инкременты.

Drawing — 2D-чертёж (DrawingService, DrawingTools, namespace Kompas.Mcp.Core.Drawings)

  • drawing_create_standard_views(partFilePath, scale, x, y) — создать стандартные ассоциативные виды (спереди/сверху/слева, ksPtFront/ksPtUp/ksPtLeft) сохранённой 3D-модели (.m3d/.a3d) на активном чертеже. Реализовано через API7 IKompasDocument2D.ViewsAndLayersManager.Views.AddStandartViews(path, "#Спереди", object[]{1,3,5}, x, y, scale, dx=20, dy=20)object[] передаётся как SAFEARRAY VT_I4. Проверки: created==3 строго; непустота — сумма IView.ObjectCount новых видов (по разнице IView.Number) >0, иначе ошибка + откат (IView.Delete). Возвращает DrawingViewsResult{Created,Total,ViewNumbers}ViewNumbers содержит номера созданных видов (для адресации при простановке размеров). Модель должна быть сохранена до вызова.
  • drawing_fill_title_block(designation?, name?, material?) — заполнить графы основной надписи (штампа) активного чертежа. designation = обозначение документа (графа 2), name = наименование изделия (графа 1), material = материал (графа 3); нужно хотя бы одно поле. Реализовано: doc2d.LayoutSheets.ItemByNumber[1].Stamp (IStamp) → stamp.Text[columnId].Str = text (индексированное свойство; IText.Str замещает содержимое без Clear) → stamp.Update(). Номера граф ksStampEnum: обозначение=2, наименование=1, материал=3. Свой enum StampField + StampFields.ColumnId/Collect в src/Kompas.Mcp.Core/Drawings/StampField.cs. Возвращает число заполненных граф.
  • drawing_add_linear_dimension(x1,y1,x2,y2,x3,y3, orientation, viewNumber) — поставить линейный размер на виде активного чертежа. Координаты (x1,y1)-(x2,y2) — выносные точки в локальной СК вида (мм); (x3,y3) — положение размерной линии; orientation: horizontal|vertical|parallel; viewNumber — номер вида (0=первый). Значение измеряется автоматически (AutoNominalValue=true). Реализовано: (ISymbols2DContainer)view (COM-QI от конкретного IView, не от листа — размер попадает именно в этот вид) → LineDimensions.Add()ILineDimensionUpdate()Valid((IDimensionText)dim).NominalValue. Ключевая находка: размеры не входят в IView.ObjectCount (он считает геометрию IDrawingContainer); проверять через ISymbols2DContainer.LineDimensions.Count. Откат через dim.Delete() при ошибке или нулевом значении. Свой enum DimensionOrientation {Horizontal, Vertical, Parallel} + DimensionOrientations.Parse/ToKompas. Валидаторы RequireFiniteCoords + RequireDistinctPoints. Новые файлы: DimensionOrientation.cs, DrawingDimensionResult.cs; инструмент в DrawingTools.cs.
  • drawing_add_diametral_dimension(xc,yc,radius, angle, viewNumber, associate=false) — поставить диаметральный размер (Ø) окружности на виде активного чертежа. xc,yc — центр, radius — радиус (мм, локальная СК вида); angle — направление выноски (градусы → радианы через DimensionAngles.ToRadians); viewNumber — номер вида (0=первый). associate=false — «свободный» размер без привязки (значение = 2·radius); associate=trueассоциативный режим: xc/yc/radius служат ключом для поиска спроецированной окружности на виде (IDrawingContainer.Circles, поиск по центру+радиусу с допуском 1 мм) через CircularObjectMatch; найденная окружность присваивается dim.BaseObject, значение (Ø) читается из геометрии и обновляется вместе с моделью. Реализовано: RequireSymbols2DContainer(viewNumber) + RequireViewContainersDiametralDimensions.Add()IDiametralDimensionUpdate()Valid((IDimensionText)dim).NominalValue. Валидатор DrawingValidation.RequirePositiveRadius.
  • drawing_add_radial_dimension(xc,yc,radius, angle, viewNumber, associate=false) — поставить радиальный размер (R) окружности/дуги на виде активного чертежа. xc,yc — центр, radius — радиус (мм, локальная СК вида); angle — направление выноски (°, по умолчанию 0); viewNumber — номер вида. Возвращаемое значение равно радиусу (не диаметру). associate=false — «свободный» размер (значение = radius); associate=trueассоциативный режим: поиск окружности по xc/yc/radius в IDrawingContainer.Circles (допуск 1 мм) через CircularObjectMatch, привязка dim.BaseObject, значение из геометрии. Реализовано: RequireSymbols2DContainer(viewNumber) + RequireViewContainersRadialDimensions.Add()IRadialDimension (Xc, Yc, Radius, Angle в радианах, DimensionType=true, AutoNominalValue=true) → Update()ValidNominalValue. Переиспользует RequirePositiveRadius и DimensionAngles.ToRadians.
  • drawing_add_angular_dimension(xc,yc, x1,y1, x2,y2, x3,y3, angleType, viewNumber) — поставить угловой размер между двумя сторонами на виде активного чертежа. xc,yc — вершина угла; x1,y1 — точка на стороне 1; x2,y2 — точка на стороне 2; x3,y3 — положение размерной дуги (задаёт её радиус); angleType = "min" (острый) | "max" (тупой, 180°-min) | "more" (рефлексный >180°); viewNumber — номер вида. Значение в градусах измеряется автоматически. Реализовано: RequireSymbols2DContainer(viewNumber)AngleDimensions.Add(ksDrADimension)IAngleDimension (Xc, Yc, X1, Y1, X2, Y2, X3, Y3, DimensionType=ksAngleDimTypeEnum, AutoNominalValue=true) → Update()ValidNominalValue. Новый enum AngleDimensionType {Min, Max, More} + AngleDimensionTypes.Parse/ToKompas в DimensionOrientation.cs; 9 unit-тестов для маппинга. Размер «свободный» (без BaseObject). Валидаторы RequireFiniteCoords + RequireDistinctPoints.
  • drawing_add_rough(x,y, value?, signType, angle, viewNumber) — поставить знак шероховатости на виде. x,y — положение знака в локальной СК вида (мм); value — текст параметра (напр. "Ra 1.6"; пусто = знак без значения); signType: "delete" (с удалением слоя материала) | "without" (без удаления) | "none" (без указания); angle — угол наклона оси знака (°, по умолч. 0); viewNumber — номер вида. Реализовано: ISymbols2DContainer.Roughs.Add()IRough (BranchX0/Y0/Angle) → (IRoughParams)rough (SignType=ksRoughSignEnum, RoughParamText.Str = value) → Update()Valid. Новый enum RoughSignType {NoProcessing, DeleteMaterial, WithoutDeleteMaterial} + RoughSignTypes.Parse/ToKompas в Drawings/RoughSignType.cs. Возвращает DrawingAnnotationResult { Value, ViewNumber }.
  • drawing_add_text(x,y, text, angle, viewNumber) — свободная текстовая надпись на виде стилем по умолчанию. x,y — точка привязки (СК вида, мм); text — содержимое (\n — многострочно); angle — угол (°, по умолч. 0); viewNumber — номер вида. Реализовано: (IDrawingContainer)view.DrawingTexts.Add()IDrawingText (X/Y/Angle) → (IText)dt.Str = textUpdate()Valid. ВАЖНО: текст живёт в IDrawingContainer (контейнер геометрии вида), НЕ в ISymbols2DContainer; попадание проверяется через DrawingTexts.Count. Возвращает DrawingAnnotationResult { Value, ViewNumber }.
  • drawing_set_technical_requirements(text) — технические требования чертежа (единый текстовый блок, уровень документа, не вида). text — строки через \n. Реализовано: (IDrawingDocument)doc.TechnicalDemandtd.Text.Str = texttd.Update(). Перезаписывает прежние (не добавляет). Возвращает число строк.

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_commandIApplication.ExecuteKompasCommand(commandID, post) для команд, ещё не обёрнутых в типизированные инструменты. Доступность проверять через IsKompasCommandEnable.

Замечание об API5 vs API7 для 3D-операций

API7 создаёт операции через IPart7 → (QueryInterface) IModelContainerIExtrusions.Add()IExtrusion. Примеры SDK при этом активно используют API5-путь (ksPart.NewEntity(o3d_…)ksBossExtrusionDefinition.SetSideParam/SetSketchCreate()), который хорошо документирован. Стратегия 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() / IKompasDocument3DIPart7 (вершинная деталь, pTop_Part).
  2. part.NewEntity(o3d_sketch)GetDefinition()SetPlane(базовая_плоскость | грань)Create(); BeginEdit() → рисование примитивов (ksLineSeg, ksCircle, ksArcByPoint, …) → EndEdit().
  3. part.NewEntity(o3d_bossExtrusion)ksBossExtrusionDefinitionSetSideParam(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. Сборка и запуск

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+package-A+package-B+package-C+package-D start+package-E start+hole+hole_counterbore+hole_countersink+hole_conic+draft+assembly_add_component+assembly_add_mate+drawing_create_standard_views+drawing_fill_title_block+drawing_add_linear_dimension+drawing_add_diametral_dimension+drawing_add_radial_dimension+drawing_add_angular_dimension+drawing_add_rough+drawing_add_text+drawing_set_technical_requirements+associate для диаметрального/радиального): документы, эскизы (полный набор 2D-примитивов: линия, окружность, дуга, дуга по 3 точкам, прямоугольник, эллипс, ломаная, правильный многоугольник, сплайн NURBS, точка), вспомогательная геометрия (sketch_create_on_offset_plane), выдавливание/вырез, вращение, скругление/фаска, оболочка (shell), ребро жёсткости (rib), кинематическая операция (sweep), операция по сечениям (loft), линейный/круговой массив и зеркало (linear_pattern, circular_pattern, mirror_operation, mirror_body), отверстие (hole, API7), цековка (hole_counterbore, API7), зенковка (hole_countersink, API7), коническое отверстие (hole_conic, 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 (структурный осмотр модели); create_variable, set_variable, delete_variable (управление переменными, package D start); assembly_add_component (вставка компонента в сборку, API7, AssemblyService); assembly_add_mate (сопряжения coincidence/distance, API7, IMateConstraints3D); drawing_create_standard_views (стандартные ассоциативные виды чертежа, API7, DrawingService); drawing_fill_title_block (заполнение основной надписи/штампа: обозначение, наименование, материал; IStamp.Text[id].Str, API7, DrawingService); drawing_add_linear_dimension (линейный размер на виде чертежа: ISymbols2DContainer/LineDimensions.Add/ILineDimension, координаты в локальной СК вида, API7, DrawingService); drawing_add_diametral_dimension (диаметральный размер Ø: ISymbols2DContainer.DiametralDimensions.Add/IDiametralDimension, Xc/Yc/Radius/Angle в радианах, API7, DrawingService; associate=true — ассоциативная привязка к спроецированной окружности через dim.BaseObject, CircularObjectMatch); drawing_add_radial_dimension (радиальный размер R: ISymbols2DContainer.RadialDimensions.Add/IRadialDimension, значение = радиус, API7, DrawingService; associate=true — ассоциативная привязка аналогично диаметральному); drawing_add_angular_dimension (угловой размер: ISymbols2DContainer.AngleDimensions.Add/IAngleDimension, angleType=min/max/more, значение в градусах, API7, DrawingService); drawing_add_rough (знак шероховатости: ISymbols2DContainer.Roughs.Add/IRough/IRoughParams, signType=delete/without/none, API7, DrawingService); drawing_add_text (свободная текстовая надпись на виде: IDrawingContainer.DrawingTexts.Add/IDrawingText/IText, API7, DrawingService); drawing_set_technical_requirements (технические требования чертежа: IDrawingDocument.TechnicalDemand/ITechnicalDemand/IText, уровень документа, API7, DrawingService). Класс «2D-чертёж» (инкремент 6): стандартные виды, основная надпись, размеры (линейный, диаметральный, радиальный, угловой), текстовые обозначения (шероховатость, свободный текст, технические требования). Инкремент 7: ассоциативная привязка диаметрального и радиального размеров к спроецированной окружности (IDrawingContainer.Circles, поиск по центру+радиусу с допуском 1 мм, CircularObjectMatch, dim.BaseObject = circle); первый шаг к «умному» чертежу.

Следующие приоритеты:

  1. Пакет D «параметрика» (продолжение) — связь размеров эскизов с переменными (параметрические эскизы через API2D). ⚠️ Исследовано: ksCDimWithVariable недоступен из внешней автоматизации — см. docs/superpowers/specs/2026-05-27-parametric-sketch-findings.md.
  2. Пакет E «вспомогательная геометрия» (продолжение) — ось, точка, плоскость по трём точкам / по углу.
  3. Рассечение/перемещение тела как MCP-инструменты (SplitSolids/BodyRepositions) — механика есть, продуктизация не закончена.
  4. Свойства документа: IPropertyMng / IPropertyKeeper.
  5. 2D-чертёж (продолжение): инкремент 7 добавил ассоциативную привязку диаметрального/радиального размера к окружности (associate=true). Нереализовано: привязка к дуге (Arcs), ассоциативный угловой размер (BaseObject1/2, отрезки), ассоциативная шероховатость (IRough.BaseObject), рамка/формат листа, выноски (Leaders), обозначения баз (Bases), допуски формы (Tolerances).
  6. Сборки — продолжение: дополнительные типы сопряжений (parallel, perpendicular, concentric, angle, tangency; coincidence/distance реализованы); авто-позиционирование компонентов; спецификации (ISpecification).
  7. Транспорт 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; менять не планируется.