57 KiB
Архитектура 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.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, измерения), 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.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(). PartModelersplit into partial classes:PartModeler.cs(core),PartModeler.Sketch.cs,PartModeler.Features.cs. StaticSketchGeometryclass holds mappings and validators. Point lists userecord SketchPoint(X, Y)(JSONx/y). All angles in degrees.CoordinateAxis.cs(src/Kompas.Mcp.Core/Modeling/) — enumCoordinateAxis {X,Y,Z}+CoordinateAxes.ToObj3dType/Parse(→o3d_axisOX/OY/OZ = 71/72/73), analogous toBasePlane.cs.
Features (3D-операции)
extrude_boss/extrude_cut— sketch, depth, direction, endType.revolve_boss/revolve_cut— угол.shell— превратить тело в оболочку: открыть грани по индексам (faceIndices, ≥1, изlist_faces), задать толщину стенки (thicknessмм), направление (outward, по умолчанию внутрь). Реализовано через API5ksPart.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 → сравнить объём (API5CalcMassInertiaProperties); если не убыл →Direction=false. При неуспехе — откат черезIFeature7.Delete(). Возвращает подтверждение без id (отверстие не попадает в реестр_featuresAPI5).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;HoleParameters→ICountersinkHoleParameters(CountersinkType=ksCTDiameterAngle,CountersinkDiameter,CountersinkAngle). Все три инструмента отверстий используют общую логику размещения и подбора направления (HoleCore).hole_conic— коническое (конусное) отверстие, сужающееся вглубь. Параметры:x,y,z,diameter(диаметр у основания/поверхности),conicAngle(угол конуса, 0<angle<180°),depth=0,throughAll=false.HoleType=ksHTConic;HoleParameters→IConicHoleParameters(ConicType=ksCNAngle,ConicAngle). Завершает набор типов отверстий (простое, цековка, зенковка, коническое).draft— уклон граней на уголangle(°, строго 0–90) относительно нейтральной координатной плоскостиneutralPlane(XOY/XOZ/YOZ).outward=true— расширение (добавляет материал),false— сужение. Реализовано через API5ksInclineDefinition(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. Реализовано через API7IPart7.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— МЦХ через 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; ksPart.GetFeature().VariableCollection → ksVariable (все переменные; 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)→IPart7→IPlacement3D.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)) →ParamValue→Update()→RebuildModel(true); проверкаmate.Valid(false → ошибка + откатmate.Owner.Delete). EnumMateType { 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) на активном чертеже. Реализовано через API7IKompasDocument2D.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. Свой enumStampField+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()→ILineDimension→Update()→Valid→((IDimensionText)dim).NominalValue. Ключевая находка: размеры не входят вIView.ObjectCount(он считает геометриюIDrawingContainer); проверять черезISymbols2DContainer.LineDimensions.Count. Откат черезdim.Delete()при ошибке или нулевом значении. Свой enumDimensionOrientation {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)+RequireViewContainers→DiametralDimensions.Add()→IDiametralDimension→Update()→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)+RequireViewContainers→RadialDimensions.Add()→IRadialDimension(Xc,Yc,Radius,Angleв радианах,DimensionType=true,AutoNominalValue=true) →Update()→Valid→NominalValue. Переиспользует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()→Valid→NominalValue. Новый enumAngleDimensionType {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. Новый enumRoughSignType {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 = text→Update()→Valid. ВАЖНО: текст живёт вIDrawingContainer(контейнер геометрии вида), НЕ вISymbols2DContainer; попадание проверяется черезDrawingTexts.Count. ВозвращаетDrawingAnnotationResult { Value, ViewNumber }.drawing_set_technical_requirements(text)— технические требования чертежа (единый текстовый блок, уровень документа, не вида).text— строки через\n. Реализовано:(IDrawingDocument)doc.TechnicalDemand→td.Text.Str = text→td.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# 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+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); первый шаг к «умному» чертежу.
Следующие приоритеты:
- Пакет D «параметрика» (продолжение) — связь размеров эскизов с переменными (параметрические эскизы через API2D). ⚠️ Исследовано:
ksCDimWithVariableнедоступен из внешней автоматизации — см.docs/superpowers/specs/2026-05-27-parametric-sketch-findings.md. - Пакет E «вспомогательная геометрия» (продолжение) — ось, точка, плоскость по трём точкам / по углу.
- Рассечение/перемещение тела как MCP-инструменты (
SplitSolids/BodyRepositions) — механика есть, продуктизация не закончена. - Свойства документа:
IPropertyMng/IPropertyKeeper. - 2D-чертёж (продолжение): инкремент 7 добавил ассоциативную привязку диаметрального/радиального размера к окружности (
associate=true). Нереализовано: привязка к дуге (Arcs), ассоциативный угловой размер (BaseObject1/2, отрезки), ассоциативная шероховатость (IRough.BaseObject), рамка/формат листа, выноски (Leaders), обозначения баз (Bases), допуски формы (Tolerances). - Сборки — продолжение: дополнительные типы сопряжений (
parallel,perpendicular,concentric,angle,tangency;coincidence/distanceреализованы); авто-позиционирование компонентов; спецификации (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; менять не планируется.