Tree-Read / Model-Inspection Tools — Gap Analysis & Plan¶
Objective: Identify and plan the missing read-only / inspection tools that allow an LLM agent to query the current state of an open SolidWorks document before issuing write operations. Without these, an agent must operate blindly.
Problem Statement¶
The current 103-tool catalog is heavily write-biased: it can create parts, sketches, features, drawings, and assemblies, but it cannot read the current model state. This prevents self-correcting agent loops such as:
"What features are already in this part?" → plan next feature
"What components are in this assembly?" → avoid duplicate inserts
"What configurations exist?" → choose the right one before modifying dimensions
"Is there an active sketch?" → avoid creating a nested sketch by accident
Current Coverage Audit¶
Adapter-level inspection methods (pywin32_adapter.py)¶
| Method | Exists in adapter | Exposed as MCP tool | In base.py (abstract) | In mock_adapter.py |
|---|---|---|---|---|
get_model_info() |
✅ (line 1614) | ❌ | ❌ | ❌ |
get_mass_properties() |
✅ | ✅ get_mass_properties |
✅ | ✅ |
get_dimension(name) |
✅ | ✅ get_dimension |
✅ | ✅ |
get_material_properties() |
✅ (via tool) | ✅ get_material_properties |
— | — |
get_file_properties() |
✅ (via tool) | ✅ get_file_properties |
— | — |
Completely absent (not in adapter OR tools)¶
| Needed tool | SolidWorks COM API | Return data |
|---|---|---|
get_model_info |
IModelDoc2::GetTitle, .GetType, .GetPathName, FeatureManager.GetFeatureCount |
title, path, doc type, config name, is_dirty, feature count |
list_features |
FeatureManager.GetFeatureCount + FeatureByPositionReverse loop |
array of |
list_sketches |
Feature loop filtered by GetTypeName2() == "ProfileFeature" |
array of sketch names |
list_configurations |
IModelDoc2::GetConfigurationCount + GetConfigurationNames |
array of config name strings |
list_components |
IAssemblyDoc::GetComponents(True) |
array of |
list_mates |
IAssemblyDoc::GetComponents → GetMates |
array of mate type + entity names |
get_active_sketch |
IModelDoc2::SketchManager.ActiveSketch |
sketch name or null |
get_sketch_entities |
ISketch::GetSketchSegments |
array of {type, start, end} for each segment |
list_dimensions |
Equations manager / feature loop | array of |
get_active_configuration |
IModelDoc2::GetActiveConfiguration().GetName() |
config name string |
Prioritization¶
Priority 1 — "What am I looking at?" (single-round awareness)¶
These are the tools an agent needs before ANY modelling session:
-
get_model_info— type, title, path, active config, is_dirty, feature count. Partially done:pywin32_adapter.get_model_info()exists but is not wired. -
list_features— feature tree dump (name + type + suppression state). -
list_configurations— config names so the agent can choose one before editing.
Priority 2 — "What sketches / components exist?"¶
-
list_sketches— subset of feature tree filtered to sketch features. -
list_components(assembly-only) — component paths and counts. -
get_active_sketch— is editing mode currently inside a sketch? Which one?
Priority 3 — "What constraints/dimensions/mates are there?"¶
-
get_sketch_entities— segments in the active/named sketch. -
list_dimensions— named dimension=value pairs across the model. -
list_mates(assembly-only) — mate relationships between components.
Proposed Implementation¶
Step A — Wire get_model_info (lowest effort, highest value)¶
- Add abstract
get_model_info()toSolidWorksAdapterinadapters/base.py - Add mock implementation to
adapters/mock_adapter.py - Add delegating wrappers to
adapters/circuit_breaker.pyandadapters/connection_pool.py - Add
@mcp.tool("get_model_info")totools/analysis.py(or a newtools/inspection.py) - Add smoke payload to
tests/test_all_endpoints_harness.py - Update tool count 103 → 104 in docs + SVG
Step B — list_features (medium effort)¶
# pywin32_adapter implementation sketch
async def list_features(self, include_suppressed: bool = False) -> AdapterResult[list[dict]]:
def _list():
fm = self.currentModel.FeatureManager
count = fm.GetFeatureCount(True)
features = []
for i in range(count):
feat = fm.FeatureByPositionReverse(i)
if feat is None:
continue
suppressed = feat.IsSuppressed2(0, None)[0]
if not include_suppressed and suppressed:
continue
features.append({
"name": feat.Name,
"type": feat.GetTypeName2(),
"suppressed": suppressed,
"position": i,
})
return features
return self._handle_com_operation("list_features", _list)
Step C — list_configurations¶
async def list_configurations(self) -> AdapterResult[list[str]]:
def _list():
names = self.currentModel.GetConfigurationNames()
return list(names) if names else []
return self._handle_com_operation("list_configurations", _list)
Step D — list_components (assembly only)¶
async def list_components(self, top_level_only: bool = True) -> AdapterResult[list[dict]]:
def _list():
components = self.currentModel.GetComponents(top_level_only)
if not components:
return []
return [
{
"name": c.Name2,
"path": c.GetPathName(),
"suppressed": c.IsSuppressed(),
"visible": c.Visible,
}
for c in components
]
return self._handle_com_operation("list_components", _list)
Impact on Agent Workflows¶
Without these tools, an agent cannot implement these common correction loops:
# Current (blind) workflow
create_sketch(plane="Front") # fails if a sketch is already open
create_extrusion(depth=10) # fails if no closed profile
# With tree-read tools (self-correcting)
model_info = get_model_info() # → doc type: "Part", feature_count: 3
active = get_active_sketch() # → None (no open sketch)
features = list_features() # → [{name:"Boss-Extrude1", type:"Boss"}]
create_sketch(plane="Front") # now safe
Acceptance Criteria¶
When implemented, each tool must:
- Pass Level A (schema validation) in
test_all_endpoints_harness.py - Pass Level B (smoke call against mock adapter) returning expected mock data
- Be listed in the tool catalog under an appropriate
docs/user-guide/tool-catalog/page - Have a mock implementation that returns realistic-looking data for CI tests
- Not require a real SolidWorks session for unit tests