using System.ComponentModel; using Kompas.Mcp.Core; using Kompas.Mcp.Core.Query; using ModelContextProtocol.Server; namespace Kompas.Mcp.Host.Tools; /// Инструменты запросов к модели. [McpServerToolType] public sealed class QueryTools(KompasSession session, QueryService query) { [McpServerTool(Name = "get_part_info")] [Description("Массово-центровочные характеристики активной детали: объём (мм³), масса (кг), площадь (мм²) и центр масс. Полезно для числовой проверки построения.")] public async Task GetPartInfo() { await session.ConnectAsync(); var i = await query.GetPartInfoAsync(); return $"Объём: {i.Volume:F2} мм³; масса: {i.Mass:F4} кг; площадь: {i.Area:F2} мм²; " + $"центр масс: ({i.CenterX:F2}, {i.CenterY:F2}, {i.CenterZ:F2})."; } [McpServerTool(Name = "list_components")] [Description("Перечислить компоненты верхнего уровня активной сборки: индекс, имя, обозначение, признак детали и габарит (мм). Индекс/имя — для последующего извлечения или осмотра детали.")] public async Task ListComponents() { await session.ConnectAsync(); var comps = await query.ListComponentsAsync(); if (comps.Count == 0) return "Компонентов нет (активный документ не сборка или пуст)."; var lines = comps.Select(c => { var mark = string.IsNullOrWhiteSpace(c.Marking) ? "" : $", обозн. \"{c.Marking}\""; return $" [{c.Index}] {(c.IsDetail ? "деталь" : "узел ")} \"{c.Name}\", " + $"габ {c.SizeX:F1}×{c.SizeY:F1}×{c.SizeZ:F1} мм{mark}"; }); return $"Компонентов: {comps.Count}\n" + string.Join("\n", lines); } [McpServerTool(Name = "list_faces")] [Description("Перечислить грани активной детали: индекс, тип поверхности (plane/cylinder/cone/sphere/torus/nurbs) и площадь (мм²). Индекс используйте в sketch_create_on_face_index. Удобно для надёжного выбора грани без угадывания координат.")] public async Task ListFaces() { await session.ConnectAsync(); var faces = await query.ListFacesAsync(); if (faces.Count == 0) return "Граней нет (модель пуста?)."; var lines = faces.Select(f => $" [{f.Index}] {f.Type}, площадь {f.Area:F2} мм²"); return $"Граней: {faces.Count}\n" + string.Join("\n", lines); } [McpServerTool(Name = "list_edges")] [Description("Перечислить рёбра активной детали: индекс, тип кривой (line/circle/arc/ellipse/nurbs) и длину (мм). Индекс используйте в fillet_edge_index / chamfer_edge_index для надёжного выбора ребра без угадывания координат.")] public async Task ListEdges() { await session.ConnectAsync(); var edges = await query.ListEdgesAsync(); if (edges.Count == 0) return "Рёбер нет (модель пуста?)."; var lines = edges.Select(e => $" [{e.Index}] {e.Type}, длина {e.Length:F2} мм"); return $"Рёбер: {edges.Count}\n" + string.Join("\n", lines); } [McpServerTool(Name = "get_bounding_box")] [Description("Габариты активной детали: координаты габаритного параллелепипеда (мм) и его размеры. Помогает оценить протяжённость модели и подобрать точки для выбора граней/рёбер.")] public async Task GetBoundingBox() { await session.ConnectAsync(); var b = await query.GetBoundingBoxAsync(); return $"Габарит: X [{b.MinX:F2}; {b.MaxX:F2}], Y [{b.MinY:F2}; {b.MaxY:F2}], Z [{b.MinZ:F2}; {b.MaxZ:F2}]; " + $"размеры (Д×Ш×В): {b.SizeX:F2} × {b.SizeY:F2} × {b.SizeZ:F2} мм."; } }