solidworks-mcp-python 1.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. solidworks_mcp/__init__.py +57 -0
  2. solidworks_mcp/adapters/__init__.py +40 -0
  3. solidworks_mcp/adapters/base.py +1882 -0
  4. solidworks_mcp/adapters/circuit_breaker.py +2052 -0
  5. solidworks_mcp/adapters/com_executor.py +252 -0
  6. solidworks_mcp/adapters/complexity_analyzer.py +272 -0
  7. solidworks_mcp/adapters/connection_pool.py +1884 -0
  8. solidworks_mcp/adapters/factory.py +366 -0
  9. solidworks_mcp/adapters/intelligent_router.py +218 -0
  10. solidworks_mcp/adapters/mock_adapter.py +4016 -0
  11. solidworks_mcp/adapters/pywin32_adapter.py +2842 -0
  12. solidworks_mcp/adapters/solidworks/__init__.py +17 -0
  13. solidworks_mcp/adapters/solidworks/bitmap.py +180 -0
  14. solidworks_mcp/adapters/solidworks/com_utils.py +56 -0
  15. solidworks_mcp/adapters/solidworks/dimension_layout.py +753 -0
  16. solidworks_mcp/adapters/solidworks/documentation.py +1476 -0
  17. solidworks_mcp/adapters/solidworks/drawing_standard.py +1993 -0
  18. solidworks_mcp/adapters/solidworks/face_selection.py +392 -0
  19. solidworks_mcp/adapters/solidworks/features.py +3362 -0
  20. solidworks_mcp/adapters/solidworks/io.py +3649 -0
  21. solidworks_mcp/adapters/solidworks/rebuild_diagnostics.py +269 -0
  22. solidworks_mcp/adapters/solidworks/rebuild_inspector.py +146 -0
  23. solidworks_mcp/adapters/solidworks/selection.py +308 -0
  24. solidworks_mcp/adapters/solidworks/sketch.py +2545 -0
  25. solidworks_mcp/adapters/sw_feature_errors.py +66 -0
  26. solidworks_mcp/adapters/sw_type_info.py +317 -0
  27. solidworks_mcp/adapters/vba_adapter.py +318 -0
  28. solidworks_mcp/adapters/vba_macro_executor.py +215 -0
  29. solidworks_mcp/agents/__init__.py +68 -0
  30. solidworks_mcp/agents/design_knowledge/assembly_patterns.md +127 -0
  31. solidworks_mcp/agents/design_knowledge/hinges.md +118 -0
  32. solidworks_mcp/agents/design_knowledge/snap_fits.md +93 -0
  33. solidworks_mcp/agents/design_knowledge/solidworks_basics.md +3 -0
  34. solidworks_mcp/agents/design_knowledge/tolerancing.md +128 -0
  35. solidworks_mcp/agents/harness.py +216 -0
  36. solidworks_mcp/agents/history_db.py +1508 -0
  37. solidworks_mcp/agents/retrieval_index.py +164 -0
  38. solidworks_mcp/agents/schemas.py +165 -0
  39. solidworks_mcp/agents/smoke_test.py +285 -0
  40. solidworks_mcp/agents/soc_exporter.py +650 -0
  41. solidworks_mcp/agents/soc_pickup.py +332 -0
  42. solidworks_mcp/agents/soc_rewind.py +221 -0
  43. solidworks_mcp/agents/vector_rag.py +665 -0
  44. solidworks_mcp/cache/__init__.py +5 -0
  45. solidworks_mcp/cache/response_cache.py +164 -0
  46. solidworks_mcp/config.py +729 -0
  47. solidworks_mcp/exceptions.py +37 -0
  48. solidworks_mcp/security/__init__.py +68 -0
  49. solidworks_mcp/security/auth.py +128 -0
  50. solidworks_mcp/security/cors.py +27 -0
  51. solidworks_mcp/security/rate_limiting.py +90 -0
  52. solidworks_mcp/security/runtime.py +155 -0
  53. solidworks_mcp/server.py +777 -0
  54. solidworks_mcp/server_cli_fixed.py +120 -0
  55. solidworks_mcp/setup/__init__.py +1 -0
  56. solidworks_mcp/setup/cli.py +399 -0
  57. solidworks_mcp/setup/clients.py +157 -0
  58. solidworks_mcp/setup/config_file.py +230 -0
  59. solidworks_mcp/setup/handshake.py +202 -0
  60. solidworks_mcp/setup/launcher.py +102 -0
  61. solidworks_mcp/setup/legacy.py +100 -0
  62. solidworks_mcp/setup/registration.py +193 -0
  63. solidworks_mcp/setup/solidworks.py +49 -0
  64. solidworks_mcp/tools/__init__.py +64 -0
  65. solidworks_mcp/tools/analysis.py +723 -0
  66. solidworks_mcp/tools/automation.py +578 -0
  67. solidworks_mcp/tools/docs_discovery.py +1476 -0
  68. solidworks_mcp/tools/drawing.py +1015 -0
  69. solidworks_mcp/tools/drawing_analysis.py +456 -0
  70. solidworks_mcp/tools/drawing_automation.py +627 -0
  71. solidworks_mcp/tools/engineering_data.py +466 -0
  72. solidworks_mcp/tools/error_classifier.py +232 -0
  73. solidworks_mcp/tools/export.py +833 -0
  74. solidworks_mcp/tools/file_facts.py +40 -0
  75. solidworks_mcp/tools/file_management.py +1473 -0
  76. solidworks_mcp/tools/input_compat.py +17 -0
  77. solidworks_mcp/tools/macro_recording.py +464 -0
  78. solidworks_mcp/tools/modeling.py +2360 -0
  79. solidworks_mcp/tools/sketching.py +1422 -0
  80. solidworks_mcp/tools/template_management.py +367 -0
  81. solidworks_mcp/tools/tool_boundary.py +280 -0
  82. solidworks_mcp/tools/vba_generation.py +1145 -0
  83. solidworks_mcp/ui/__init__.py +9 -0
  84. solidworks_mcp/ui/local_llm.py +725 -0
  85. solidworks_mcp/ui/routers/__init__.py +10 -0
  86. solidworks_mcp/ui/routers/checkpoint.py +24 -0
  87. solidworks_mcp/ui/routers/docs.py +47 -0
  88. solidworks_mcp/ui/routers/llm.py +83 -0
  89. solidworks_mcp/ui/routers/local_model.py +69 -0
  90. solidworks_mcp/ui/routers/model.py +75 -0
  91. solidworks_mcp/ui/routers/preview.py +38 -0
  92. solidworks_mcp/ui/routers/session.py +161 -0
  93. solidworks_mcp/ui/routers/viewer.py +154 -0
  94. solidworks_mcp/ui/schemas.py +502 -0
  95. solidworks_mcp/ui/server.py +298 -0
  96. solidworks_mcp/ui/service.py +481 -0
  97. solidworks_mcp/ui/services/__init__.py +136 -0
  98. solidworks_mcp/ui/services/_utils.py +958 -0
  99. solidworks_mcp/ui/services/checkpoint_service.py +1110 -0
  100. solidworks_mcp/ui/services/docs_service.py +282 -0
  101. solidworks_mcp/ui/services/llm_service.py +956 -0
  102. solidworks_mcp/ui/services/model_service.py +459 -0
  103. solidworks_mcp/ui/services/parameter_repair_service.py +314 -0
  104. solidworks_mcp/ui/services/preview_service.py +489 -0
  105. solidworks_mcp/ui/services/session_service.py +1389 -0
  106. solidworks_mcp/utils/__init__.py +9 -0
  107. solidworks_mcp/utils/feature_tree_classifier.py +342 -0
  108. solidworks_mcp/utils/logging.py +76 -0
  109. solidworks_mcp/utils/validation.py +77 -0
  110. solidworks_mcp/version.py +8 -0
  111. solidworks_mcp_python-1.5.0.dist-info/METADATA +410 -0
  112. solidworks_mcp_python-1.5.0.dist-info/RECORD +115 -0
  113. solidworks_mcp_python-1.5.0.dist-info/WHEEL +4 -0
  114. solidworks_mcp_python-1.5.0.dist-info/entry_points.txt +3 -0
  115. solidworks_mcp_python-1.5.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,1015 @@
1
+ """Drawing tools for SolidWorks MCP Server.
2
+
3
+ Provides tools for creating drawing views, adding dimensions, annotations, and managing
4
+ technical drawings in SolidWorks.
5
+ """
6
+
7
+ from typing import Any
8
+
9
+ from fastmcp import FastMCP
10
+ from pydantic import BaseModel, Field
11
+
12
+ from ..adapters.base import SolidWorksAdapter
13
+ from .input_compat import CompatInput
14
+ from .tool_boundary import (
15
+ UnsupportedOperationError,
16
+ normalize_input,
17
+ require_capability,
18
+ require_success,
19
+ with_tool_boundary,
20
+ )
21
+
22
+ # Input schemas using Python 3.14 built-in types
23
+
24
+
25
+ class CreateDrawingViewInput(BaseModel):
26
+ """Input schema for creating drawing views.
27
+
28
+ Attributes:
29
+ model_path (str): The model path value.
30
+ orientation (str): The orientation value.
31
+ position_x (float): The position x value.
32
+ position_y (float): The position y value.
33
+ scale (float): The scale value.
34
+ view_type (str): The view type value.
35
+ """
36
+
37
+ model_path: str = Field(description="Path to the SolidWorks model file")
38
+ view_type: str = Field(
39
+ description="Type of view (orthographic, isometric, section, detail)"
40
+ )
41
+ position_x: float = Field(default=100.0, description="X position in drawing (mm)")
42
+ position_y: float = Field(default=200.0, description="Y position in drawing (mm)")
43
+ scale: float = Field(default=1.0, description="View scale factor")
44
+ orientation: str = Field(
45
+ default="front", description="View orientation (front, top, right, isometric)"
46
+ )
47
+
48
+
49
+ class AddDimensionInput(BaseModel):
50
+ """Input schema for adding dimensions.
51
+
52
+ Attributes:
53
+ dimension_type (str): The dimension type value.
54
+ entity1 (str): The entity1 value.
55
+ entity2 (str | None): The entity2 value.
56
+ position_x (float): The position x value.
57
+ position_y (float): The position y value.
58
+ precision (int): The precision value.
59
+ """
60
+
61
+ dimension_type: str = Field(
62
+ description="Type of dimension (linear, radial, angular, diameter)"
63
+ )
64
+ entity1: str = Field(description="First entity to dimension (edge, face, point)")
65
+ entity2: str | None = Field(
66
+ default=None, description="Second entity for linear/angular dimensions"
67
+ )
68
+ position_x: float = Field(description="X position for dimension text")
69
+ position_y: float = Field(description="Y position for dimension text")
70
+ precision: int = Field(default=2, description="Number of decimal places")
71
+
72
+
73
+ class AddNoteInput(BaseModel):
74
+ """Input schema for adding notes/annotations.
75
+
76
+ Attributes:
77
+ font_size (float): The font size value.
78
+ leader_attachment (str | None): The leader attachment value.
79
+ position_x (float): The position x value.
80
+ position_y (float): The position y value.
81
+ text (str): The text value.
82
+ """
83
+
84
+ text: str = Field(description="Note text content")
85
+ position_x: float = Field(description="X position for note")
86
+ position_y: float = Field(description="Y position for note")
87
+ font_size: float = Field(default=12.0, description="Font size in points")
88
+ leader_attachment: str | None = Field(
89
+ default=None, description="Entity to attach leader line to"
90
+ )
91
+
92
+
93
+ class CreateSectionViewInput(BaseModel):
94
+ """Input schema for creating section views.
95
+
96
+ Attributes:
97
+ label (str): The label value.
98
+ scale (float): The scale value.
99
+ section_line_end (list[float]): The section line end value.
100
+ section_line_start (list[float]): The section line start value.
101
+ view_position_x (float): The view position x value.
102
+ view_position_y (float): The view position y value.
103
+ """
104
+
105
+ section_line_start: list[float] = Field(
106
+ description="Start point of section line as [x, y]",
107
+ min_length=2,
108
+ max_length=2,
109
+ json_schema_extra={"items": {"type": "number"}},
110
+ )
111
+ section_line_end: list[float] = Field(
112
+ description="End point of section line as [x, y]",
113
+ min_length=2,
114
+ max_length=2,
115
+ json_schema_extra={"items": {"type": "number"}},
116
+ )
117
+ view_position_x: float = Field(description="X position for section view")
118
+ view_position_y: float = Field(description="Y position for section view")
119
+ scale: float = Field(default=1.0, description="Section view scale")
120
+ label: str = Field(default="A", description="Section view label")
121
+
122
+
123
+ class CreateDetailViewInput(BaseModel):
124
+ """Input schema for creating detail views.
125
+
126
+ Attributes:
127
+ center_x (float): The center x value.
128
+ center_y (float): The center y value.
129
+ label (str): The label value.
130
+ radius (float): The radius value.
131
+ scale (float): The scale value.
132
+ view_position_x (float): The view position x value.
133
+ view_position_y (float): The view position y value.
134
+ """
135
+
136
+ center_x: float = Field(description="X center of detail circle")
137
+ center_y: float = Field(description="Y center of detail circle")
138
+ radius: float = Field(description="Radius of detail circle")
139
+ view_position_x: float = Field(description="X position for detail view")
140
+ view_position_y: float = Field(description="Y position for detail view")
141
+ scale: float = Field(default=2.0, description="Detail view scale")
142
+ label: str = Field(default="A", description="Detail view label")
143
+
144
+
145
+ class UpdateSheetFormatInput(BaseModel):
146
+ """Input schema for updating sheet format.
147
+
148
+ Attributes:
149
+ approved_by (str): The approved by value.
150
+ checked_by (str): The checked by value.
151
+ drawing_number (str): The drawing number value.
152
+ drawn_by (str): The drawn by value.
153
+ format_file (str): The format file value.
154
+ sheet_size (str): The sheet size value.
155
+ title (str): The title value.
156
+ """
157
+
158
+ format_file: str = Field(description="Path to sheet format template (.slddrt)")
159
+ sheet_size: str = Field(default="A3", description="Sheet size (A4, A3, A2, A1, A0)")
160
+ title: str = Field(default="", description="Drawing title")
161
+ drawn_by: str = Field(default="", description="Drawn by field")
162
+ checked_by: str = Field(default="", description="Checked by field")
163
+ approved_by: str = Field(default="", description="Approved by field")
164
+ drawing_number: str = Field(default="", description="Drawing number")
165
+
166
+
167
+ class AutoCenterMarksInput(CompatInput):
168
+ """Input schema for auto-inserting drawing centre marks.
169
+
170
+ Attributes:
171
+ view_name (str): Name of a view on the active drawing.
172
+ mark_holes (bool): Mark holes / bores.
173
+ mark_fillets (bool): Mark fillets.
174
+ mark_slots (bool): Mark slots.
175
+ """
176
+
177
+ view_name: str = Field(
178
+ description="Name of a view on the active drawing, e.g. 'Drawing View1'"
179
+ )
180
+ mark_holes: bool = Field(default=True, description="Mark holes / bores")
181
+ mark_fillets: bool = Field(default=False, description="Mark fillets")
182
+ mark_slots: bool = Field(default=True, description="Mark slots")
183
+
184
+ def model_post_init(self, __context: Any) -> None:
185
+ if not self.view_name.strip():
186
+ raise ValueError("view_name is required")
187
+
188
+
189
+ class DrawingCreationInput(CompatInput):
190
+ """Input schema for creating a new drawing.
191
+
192
+ Attributes:
193
+ auto_populate_views (bool): The auto populate views value.
194
+ model_file (str | None): The model file value.
195
+ output_path (str | None): The output path value.
196
+ scale (str): The scale value.
197
+ sheet_format (str | None): The sheet format value.
198
+ sheet_size (str): The sheet size value.
199
+ template (str | None): The template value.
200
+ title (str): The title value.
201
+ """
202
+
203
+ template: str | None = Field(default=None, description="Drawing template file path")
204
+ model_file: str | None = Field(
205
+ default=None, description="Model file to create drawing from"
206
+ )
207
+ sheet_size: str = Field(default="A3", description="Sheet size")
208
+ title: str = Field(default="", description="Drawing title")
209
+ output_path: str | None = Field(default=None, description="Output drawing path")
210
+ sheet_format: str | None = Field(default=None, description="Sheet format")
211
+ scale: str = Field(default="1:1", description="Drawing scale")
212
+ auto_populate_views: bool = Field(
213
+ default=False, description="Automatically populate standard views"
214
+ )
215
+
216
+
217
+ class DrawingViewInput(CompatInput):
218
+ """Input schema for drawing view operations.
219
+
220
+ Attributes:
221
+ drawing_path (str | None): The drawing path value.
222
+ model_file (str | None): The model file value.
223
+ operation (str): The operation value.
224
+ parameters (dict[str, Any]): The parameters value.
225
+ parent_view (str | None): The parent view value.
226
+ position (list[float] | None): The position value.
227
+ scale (str | None): The scale value.
228
+ view_name (str | None): The view name value.
229
+ view_type (str | None): The view type value.
230
+ """
231
+
232
+ drawing_path: str | None = Field(default=None, description="Path to drawing file")
233
+ view_name: str | None = Field(default=None, description="Name of the drawing view")
234
+ operation: str = Field(
235
+ default="add", description="Operation to perform (create, update, delete)"
236
+ )
237
+ model_file: str | None = Field(default=None, description="Model file path")
238
+ view_type: str | None = Field(default=None, description="Type of view")
239
+ parent_view: str | None = Field(default=None, description="Parent view alias")
240
+ position: list[float] | None = Field(default=None, description="View position")
241
+ scale: str | None = Field(default=None, description="View scale")
242
+ parameters: dict[str, Any] = Field(default={}, description="View parameters")
243
+
244
+
245
+ class DimensionInput(CompatInput):
246
+ """Input schema for dimension operations.
247
+
248
+ Attributes:
249
+ dimension_name (str | None): The dimension name value.
250
+ dimension_type (str | None): The dimension type value.
251
+ drawing_path (str | None): The drawing path value.
252
+ entities (list[str] | None): The entities value.
253
+ entity1 (str | None): The entity1 value.
254
+ entity2 (str | None): The entity2 value.
255
+ operation (str | None): The operation value.
256
+ position (list[float] | None): The position value.
257
+ position_x (float | None): The position x value.
258
+ position_y (float | None): The position y value.
259
+ precision (int): The precision value.
260
+ tolerance (str | None): The tolerance value.
261
+ value (float | None): The value value.
262
+ """
263
+
264
+ drawing_path: str | None = Field(default=None, description="Path to drawing file")
265
+ dimension_name: str | None = Field(
266
+ default=None, description="Name of the dimension"
267
+ )
268
+ operation: str | None = Field(
269
+ default="add", description="Operation to perform (add, update, delete)"
270
+ )
271
+ value: float | None = Field(default=None, description="Dimension value")
272
+ dimension_type: str | None = Field(default=None, description="Type of dimension")
273
+ entities: list[str] | None = Field(
274
+ default=None, description="Entities to dimension"
275
+ )
276
+ entity1: str | None = Field(default=None, description="Primary entity alias")
277
+ entity2: str | None = Field(default=None, description="Secondary entity alias")
278
+ position: list[float] | None = Field(default=None, description="Dimension position")
279
+ position_x: float | None = Field(default=None, description="Position X alias")
280
+ position_y: float | None = Field(default=None, description="Position Y alias")
281
+ precision: int = Field(default=2, description="Precision alias")
282
+ tolerance: str | None = Field(default=None, description="Dimension tolerance")
283
+
284
+ def model_post_init(self, __context: Any) -> None:
285
+ """Provide model post init support for the dimension input.
286
+
287
+ Args:
288
+ __context (Any): The context value.
289
+
290
+ Returns:
291
+ None: None.
292
+ """
293
+ if self.entities:
294
+ if self.entity1 is None and len(self.entities) >= 1:
295
+ self.entity1 = self.entities[0]
296
+ if self.entity2 is None and len(self.entities) >= 2:
297
+ self.entity2 = self.entities[1]
298
+ if self.position and len(self.position) >= 2:
299
+ if self.position_x is None:
300
+ self.position_x = float(self.position[0])
301
+ if self.position_y is None:
302
+ self.position_y = float(self.position[1])
303
+
304
+
305
+ class AnnotationInput(CompatInput):
306
+ """Input schema for annotation operations.
307
+
308
+ Attributes:
309
+ annotation_type (str): The annotation type value.
310
+ approved_by (str): The approved by value.
311
+ checked_by (str): The checked by value.
312
+ drawing_number (str): The drawing number value.
313
+ drawing_path (str | None): The drawing path value.
314
+ drawn_by (str): The drawn by value.
315
+ font_size (float): The font size value.
316
+ leader_attachment (str | None): The leader attachment value.
317
+ position (list[float] | None): The position value.
318
+ position_x (float | None): The position x value.
319
+ position_y (float | None): The position y value.
320
+ text (str): The text value.
321
+ """
322
+
323
+ drawing_path: str | None = Field(default=None, description="Path to drawing file")
324
+ annotation_type: str = Field(
325
+ description="Type of annotation (note, balloon, surface_finish, etc.)"
326
+ )
327
+ text: str = Field(description="Annotation text content")
328
+ position_x: float | None = Field(
329
+ default=None, description="X position for annotation"
330
+ )
331
+ position_y: float | None = Field(
332
+ default=None, description="Y position for annotation"
333
+ )
334
+ position: list[float] | None = Field(
335
+ default=None, description="Annotation position"
336
+ )
337
+ font_size: float = Field(default=12.0, description="Font size in points")
338
+ leader_attachment: str | None = Field(
339
+ default=None, description="Entity to attach leader line to"
340
+ )
341
+ drawn_by: str = Field(default="", description="Drawn by field")
342
+ checked_by: str = Field(default="", description="Checked by field")
343
+ approved_by: str = Field(default="", description="Approved by field")
344
+ drawing_number: str = Field(default="", description="Drawing number")
345
+
346
+ def model_post_init(self, __context: Any) -> None:
347
+ """Provide model post init support for the annotation input.
348
+
349
+ Args:
350
+ __context (Any): The context value.
351
+
352
+ Returns:
353
+ None: None.
354
+ """
355
+ if self.position is not None and len(self.position) >= 2:
356
+ if self.position_x is None:
357
+ self.position_x = float(self.position[0])
358
+ if self.position_y is None:
359
+ self.position_y = float(self.position[1])
360
+
361
+
362
+ async def register_drawing_tools(
363
+ mcp: FastMCP, adapter: SolidWorksAdapter, config: dict[str, Any]
364
+ ) -> int:
365
+ """Register drawing tools with FastMCP.
366
+
367
+ Registers comprehensive technical drawing tools for SolidWorks automation including view
368
+ creation, dimensioning, annotation, and drawing standards validation. Essential for
369
+ automated documentation workflows.
370
+
371
+ Args:
372
+ mcp (FastMCP): The mcp value.
373
+ adapter (SolidWorksAdapter): Adapter instance used for the operation.
374
+ config (dict[str, Any]): Configuration values for the operation.
375
+
376
+ Returns:
377
+ int: The computed numeric result.
378
+
379
+ Example:
380
+ ```python
381
+ from solidworks_mcp.tools.drawing import register_drawing_tools
382
+
383
+ tool_count = await register_drawing_tools(mcp, adapter, config)
384
+ print(f"Registered {tool_count} drawing tools")
385
+ ```
386
+ """
387
+ mcp = with_tool_boundary(mcp)
388
+ tool_count = 0
389
+
390
+ @mcp.tool()
391
+ async def create_drawing_view(input_data: CreateDrawingViewInput) -> dict[str, Any]:
392
+ """Create a drawing view of a SolidWorks model.
393
+
394
+ Creates technical drawing views including orthographic projections, isometric views,
395
+ section views, and detail views from 3D models. Essential for generating production
396
+ drawings and technical documentation.
397
+
398
+ Args:
399
+ input_data (CreateDrawingViewInput): The input data value.
400
+
401
+ Returns:
402
+ dict[str, Any]: A dictionary containing the resulting values.
403
+
404
+ Example:
405
+ ```python
406
+ # Create front orthographic view of a part
407
+ result = await create_drawing_view({
408
+ "model_path": "C:/Models/bracket.sldprt",
409
+ "view_type": "orthographic",
410
+ "position_x": 150.0, "position_y": 250.0,
411
+ "scale": 1.0,
412
+ "orientation": "front"
413
+ })
414
+
415
+ if result["status"] == "success":
416
+ view = result["drawing_view"]
417
+ print(f"Created {view['view_type']} view at {view['scale']}:1 scale")
418
+ # Ready for dimensioning and annotation
419
+ ```
420
+
421
+ Note:
422
+ - Model file must exist and be accessible
423
+ - Drawing sheet must be active before creating views
424
+ - View positioning follows drawing sheet coordinate system
425
+ - Multiple views can reference the same model file
426
+ """
427
+ require_capability(
428
+ adapter,
429
+ "create_drawing_view",
430
+ "Active adapter does not support create_drawing_view; no "
431
+ f"{input_data.view_type} view of {input_data.model_path} was created.",
432
+ )
433
+ result = await adapter.create_drawing_view(input_data.model_dump())
434
+ require_success(result, "Failed to create drawing view")
435
+ return {
436
+ "status": "success",
437
+ "message": f"Created {input_data.view_type} view of {input_data.model_path}",
438
+ "data": result.data,
439
+ "execution_time": result.execution_time,
440
+ }
441
+
442
+ @mcp.tool()
443
+ async def add_dimension(input_data: AddDimensionInput) -> dict[str, Any]:
444
+ """Add a dimension to the current drawing.
445
+
446
+ Creates dimensional annotations on drawing views including linear, radial, angular, and
447
+ diameter dimensions. Essential for manufacturing specifications and quality control
448
+ documentation.
449
+
450
+ Args:
451
+ input_data (AddDimensionInput): The input data value.
452
+
453
+ Returns:
454
+ dict[str, Any]: A dictionary containing the resulting values.
455
+
456
+ Example:
457
+ ```python
458
+ # Add diameter dimension to a hole
459
+ result = await add_dimension({
460
+ "dimension_type": "diameter",
461
+ "entity1": "Circle1",
462
+ "entity2": None,
463
+ "position_x": 100.0, "position_y": 150.0,
464
+ "precision": 2
465
+ })
466
+
467
+ if result["status"] == "success":
468
+ dim = result["dimension"]
469
+ print(f"Added {dim['type']} dimension with {dim['precision']} decimals")
470
+ # Dimension now drives manufacturing specification
471
+ ```
472
+
473
+ Note:
474
+ - Entities must be visible in current drawing view
475
+ - Dimension placement affects drawing readability
476
+ - Precision should match manufacturing tolerances
477
+ - Some dimension types require specific entity combinations
478
+ """
479
+ if hasattr(input_data, "model_dump"):
480
+ payload = input_data.model_dump()
481
+ else:
482
+ payload = dict(input_data)
483
+
484
+ dimension_type = payload.get("dimension_type")
485
+ entity1 = payload.get("entity1")
486
+ entity2 = payload.get("entity2")
487
+ position_x = payload.get("position_x")
488
+ position_y = payload.get("position_y")
489
+
490
+ if (entity1 is None or entity2 is None) and payload.get("entities"):
491
+ entities = payload["entities"]
492
+ if entity1 is None and len(entities) >= 1:
493
+ entity1 = entities[0]
494
+ if entity2 is None and len(entities) >= 2:
495
+ entity2 = entities[1]
496
+
497
+ if (position_x is None or position_y is None) and payload.get("position"):
498
+ position = payload["position"]
499
+ if len(position) >= 2:
500
+ if position_x is None:
501
+ position_x = position[0]
502
+ if position_y is None:
503
+ position_y = position[1]
504
+
505
+ # Feed the alias-normalized values back into the payload so the
506
+ # adapter call sees entity1/entity2/position_x/position_y even
507
+ # when the caller only supplied entities/position.
508
+ payload["entity1"] = entity1
509
+ payload["entity2"] = entity2
510
+ payload["position_x"] = position_x
511
+ payload["position_y"] = position_y
512
+
513
+ require_capability(
514
+ adapter,
515
+ "add_dimension",
516
+ f"Active adapter does not support add_dimension; no "
517
+ f"{dimension_type} dimension was added.",
518
+ )
519
+ result = await adapter.add_dimension(payload)
520
+ require_success(result, "Failed to add dimension")
521
+ return {
522
+ "status": "success",
523
+ "message": "Dimension added successfully",
524
+ "data": result.data,
525
+ "execution_time": result.execution_time,
526
+ }
527
+
528
+ @mcp.tool()
529
+ async def add_note(input_data: AddNoteInput) -> dict[str, Any]:
530
+ """Add a note or annotation to the current drawing.
531
+
532
+ Creates text annotations, callouts, and notes on drawings for specifications,
533
+ instructions, and additional manufacturing information. Essential for comprehensive
534
+ technical documentation.
535
+
536
+ Args:
537
+ input_data (AddNoteInput): The input data value.
538
+
539
+ Returns:
540
+ dict[str, Any]: A dictionary containing the resulting values.
541
+
542
+ Example:
543
+ ```python
544
+ # Add material specification note with leader
545
+ result = await add_note({
546
+ "text": "Material: AISI 1018 Steel
547
+ Hardness: 150-200 HB",
548
+ "position_x": 200.0, "position_y": 50.0,
549
+ "font_size": 10.0,
550
+ "leader_attachment": "Face1"
551
+ })
552
+
553
+ if result["status"] == "success":
554
+ note = result["note"]
555
+ print(f"Added note at {note['font_size']}pt font size")
556
+ # Note provides critical manufacturing information
557
+ ```
558
+
559
+ Note:
560
+ - Text supports standard annotation symbols and formatting
561
+ - Leader attachment improves clarity for specific features
562
+ - Font size should comply with drawing standards
563
+ - Position carefully to avoid dimension conflicts
564
+ """
565
+ require_capability(
566
+ adapter,
567
+ "add_note",
568
+ "Active adapter does not support add_note; no note was added.",
569
+ )
570
+ result = await adapter.add_note(input_data.model_dump())
571
+ require_success(result, "Failed to add note")
572
+ return {
573
+ "status": "success",
574
+ "message": f"Added note: {input_data.text[:30]}...",
575
+ "data": result.data,
576
+ "execution_time": result.execution_time,
577
+ }
578
+
579
+ @mcp.tool()
580
+ async def create_section_view(input_data: CreateSectionViewInput) -> dict[str, Any]:
581
+ """Create a section view of the current drawing.
582
+
583
+ Generates section views that show internal features by cutting through the part along a
584
+ specified section line. Essential for revealing hidden geometry, internal structures,
585
+ and complex assemblies.
586
+
587
+ Args:
588
+ input_data (CreateSectionViewInput): The input data value.
589
+
590
+ Returns:
591
+ dict[str, Any]: A dictionary containing the resulting values.
592
+
593
+ Example:
594
+ ```python
595
+ # Create vertical section through center of part
596
+ result = await create_section_view({
597
+ "section_line_start": (50.0, 0.0),
598
+ "section_line_end": (50.0, 100.0),
599
+ "view_position_x": 300.0, "view_position_y": 150.0,
600
+ "scale": 1.5,
601
+ "label": "A"
602
+ })
603
+
604
+ if result["status"] == "success":
605
+ section = result["section_view"]
606
+ print(f"Created section {section['label']}-A at {section['scale']}:1")
607
+ # Section reveals internal features clearly
608
+ ```
609
+
610
+ Note:
611
+ - Section line direction determines view orientation
612
+ - Section views automatically show cut surfaces with hatching
613
+ - Label follows ANSI/ISO drafting standards (A-A, B-B, etc.)
614
+ - Essential for showing internal features and assemblies
615
+ """
616
+ raise UnsupportedOperationError(
617
+ "No adapter capability exists for cutting a section view "
618
+ "along a section line; create_section_view cannot compute "
619
+ "the cut geometry, so no view was created. Use SolidWorks "
620
+ "directly (Insert > Drawing View > Section) instead."
621
+ )
622
+
623
+ @mcp.tool()
624
+ async def create_detail_view(input_data: CreateDetailViewInput) -> dict[str, Any]:
625
+ """Create a detail view of a specific area.
626
+
627
+ Generates magnified detail views of specific regions to show fine features, tight
628
+ tolerances, and intricate geometry that requires enhanced visibility for manufacturing
629
+ and inspection.
630
+
631
+ Args:
632
+ input_data (CreateDetailViewInput): The input data value.
633
+
634
+ Returns:
635
+ dict[str, Any]: A dictionary containing the resulting values.
636
+
637
+ Example:
638
+ ```python
639
+ # Create 4x detail view of small threaded hole
640
+ result = await create_detail_view({
641
+ "center_x": 25.0, "center_y": 15.0,
642
+ "radius": 8.0, # 16mm diameter detail area
643
+ "view_position_x": 250.0, "view_position_y": 300.0,
644
+ "scale": 4.0, # 4:1 magnification
645
+ "label": "A"
646
+ })
647
+
648
+ if result["status"] == "success":
649
+ detail = result["detail_view"]
650
+ print(f"Created detail {detail['label']} at {detail['scale']}:1")
651
+ # Detail shows thread profile clearly for machining
652
+ ```
653
+
654
+ Note:
655
+ - Detail circle size determines what geometry is magnified
656
+ - Higher scale factors reveal fine features for precision work
657
+ - Label follows standard drafting conventions (Detail A, etc.)
658
+ - Essential for communicating tight tolerance requirements
659
+ """
660
+ raise UnsupportedOperationError(
661
+ "No adapter capability exists for magnifying the "
662
+ "geometry inside a detail circle; create_detail_view "
663
+ "cannot compute the detail geometry, so no view was "
664
+ "created. Use SolidWorks directly (Insert > Drawing "
665
+ "View > Detail) instead."
666
+ )
667
+
668
+ @mcp.tool()
669
+ async def update_sheet_format(input_data: UpdateSheetFormatInput) -> dict[str, Any]:
670
+ """Update the sheet format and title block information.
671
+
672
+ Applies drawing templates and updates title block fields with project information,
673
+ revision data, and drawing metadata. Essential for standardized documentation and
674
+ drawing control.
675
+
676
+ Args:
677
+ input_data (UpdateSheetFormatInput): The input data value.
678
+
679
+ Returns:
680
+ dict[str, Any]: A dictionary containing the resulting values.
681
+
682
+ Example:
683
+ ```python
684
+ # Apply company standard format with project info
685
+ result = await update_sheet_format({
686
+ "format_file": "C:/Templates/company_format.slddrt",
687
+ "sheet_size": "A3",
688
+ "title": "Mounting Bracket Assembly",
689
+ "drawn_by": "J. Smith",
690
+ "checked_by": "M. Johnson",
691
+ "approved_by": "R. Wilson",
692
+ "drawing_number": "DWG-001-Rev-A"
693
+ })
694
+
695
+ if result["status"] == "success":
696
+ format_info = result["sheet_format"]
697
+ print(f"Applied {format_info['sheet_size']} format")
698
+ # Drawing now has proper title block and company branding
699
+ ```
700
+
701
+ Note:
702
+ - Format file must exist and be compatible with SolidWorks version
703
+ - Title block fields support company-specific customization
704
+ - Sheet size affects drawing layout and scaling decisions
705
+ - Essential for drawing control and document management systems
706
+ """
707
+ require_capability(
708
+ adapter,
709
+ "update_sheet_format",
710
+ "Active adapter does not support update_sheet_format; the "
711
+ "sheet format and title block were not changed.",
712
+ )
713
+ result = await adapter.update_sheet_format(input_data.model_dump())
714
+ require_success(result, "Failed to update sheet format")
715
+ return {
716
+ "status": "success",
717
+ "message": f"Updated sheet format to {input_data.sheet_size}",
718
+ "data": result.data,
719
+ "execution_time": result.execution_time,
720
+ }
721
+
722
+ @mcp.tool()
723
+ async def auto_dimension_view(input_data: dict[str, Any]) -> dict[str, Any]:
724
+ """Automatically dimension a drawing view.
725
+
726
+ Analyzes drawing view geometry and automatically adds common dimensions including
727
+ overall sizes, hole diameters, radii, and critical features. Accelerates drawing
728
+ completion and ensures comprehensive dimensioning coverage.
729
+
730
+ Args:
731
+ input_data (dict[str, Any]): The input data value.
732
+
733
+ Returns:
734
+ dict[str, Any]: A dictionary containing the resulting values.
735
+
736
+ Example:
737
+ ```python
738
+ # Auto-dimension main view with baseline dimensions
739
+ result = await auto_dimension_view({
740
+ "view_name": "Front View",
741
+ "dimension_types": ["linear", "diameter"],
742
+ "include_baseline": True,
743
+ "include_centerlines": True
744
+ })
745
+
746
+ if result["status"] == "success":
747
+ auto_dims = result["auto_dimensions"]
748
+ print(f"Added {auto_dims['dimensions_added']} dimensions")
749
+ print(f"Coverage: {auto_dims['coverage']}")
750
+ # Drawing now has comprehensive dimensioning
751
+ ```
752
+
753
+ Note:
754
+ - Analyzes feature geometry to determine appropriate dimensions
755
+ - Follows drafting standards for dimension placement
756
+ - May require manual adjustment for optimal readability
757
+ - Significantly reduces manual dimensioning time
758
+ """
759
+ require_capability(
760
+ adapter,
761
+ "auto_dimension_view",
762
+ "Active adapter does not support auto_dimension_view; no "
763
+ "dimensions were added.",
764
+ )
765
+ result = await adapter.auto_dimension_view(input_data)
766
+ require_success(result, "Failed to auto-dimension view")
767
+ return {
768
+ "status": "success",
769
+ "message": "Auto-dimensioned drawing view",
770
+ "data": result.data,
771
+ "execution_time": result.execution_time,
772
+ }
773
+
774
+ @mcp.tool()
775
+ async def check_drawing_standards(input_data: dict[str, Any]) -> dict[str, Any]:
776
+ """Check the current drawing against drafting standards.
777
+
778
+ Validates drawing compliance with industry drafting standards including ANSI Y14.5, ISO
779
+ 128, and DIN standards. Identifies non-compliance issues and provides recommendations
780
+ for improvement.
781
+
782
+ Args:
783
+ input_data (dict[str, Any]): The input data value.
784
+
785
+ Returns:
786
+ dict[str, Any]: A dictionary containing the resulting values.
787
+
788
+ Example:
789
+ ```python
790
+ # Comprehensive ANSI standards check
791
+ result = await check_drawing_standards({
792
+ "standard": "ANSI",
793
+ "check_categories": ["dimensions", "tolerances", "symbols"],
794
+ "severity_filter": "warning"
795
+ })
796
+
797
+ if result["status"] == "success":
798
+ check = result["standards_check"]
799
+ print(f"Compliance Score: {check['compliance_score']}%")
800
+ print(f"Warnings: {len(check['warnings'])}")
801
+ print(f"Errors: {len(check['errors'])}")
802
+ # Address issues to improve drawing quality
803
+ ```
804
+
805
+ Note:
806
+ - Standards compliance ensures drawing acceptance in industry
807
+ - Regular checking prevents costly revision cycles
808
+ - Automated validation reduces human error in review process
809
+ - Essential for quality management and ISO certification
810
+ """
811
+ raise UnsupportedOperationError(
812
+ "No adapter capability exists for checking drafting "
813
+ "standards compliance; check_drawing_standards cannot "
814
+ "inspect the drawing, so no compliance score was "
815
+ "computed. Use SolidWorks Design Checker for this."
816
+ )
817
+
818
+ @mcp.tool()
819
+ async def create_technical_drawing(
820
+ input_data: DrawingCreationInput,
821
+ ) -> dict[str, Any]:
822
+ """Create a technical drawing from a SolidWorks part or assembly.
823
+
824
+ Supports selecting a template, output path, sheet format, scale, and optional auto-
825
+ population of standard views for documentation.
826
+
827
+ Args:
828
+ input_data (DrawingCreationInput): The input data value.
829
+
830
+ Returns:
831
+ dict[str, Any]: A dictionary containing the resulting values.
832
+ """
833
+ require_capability(
834
+ adapter,
835
+ "create_technical_drawing",
836
+ "Active adapter does not support create_technical_drawing; "
837
+ "no drawing was created.",
838
+ )
839
+ result = await adapter.create_technical_drawing(input_data.model_dump())
840
+ require_success(result, "Failed to create technical drawing")
841
+ return {
842
+ "status": "success",
843
+ "message": "Technical drawing created successfully",
844
+ "data": result.data,
845
+ "execution_time": result.execution_time,
846
+ }
847
+
848
+ @mcp.tool()
849
+ async def add_drawing_view(input_data: DrawingViewInput) -> dict[str, Any]:
850
+ """Add, update, or remove a drawing view in an existing drawing.
851
+
852
+ Supports configuring the target drawing, view type, parent view, scale, and placement
853
+ coordinates for common drawing view workflows.
854
+
855
+ Args:
856
+ input_data (DrawingViewInput): The input data value.
857
+
858
+ Returns:
859
+ dict[str, Any]: A dictionary containing the resulting values.
860
+ """
861
+ require_capability(
862
+ adapter,
863
+ "add_drawing_view",
864
+ "Active adapter does not support add_drawing_view; no view was added.",
865
+ )
866
+ result = await adapter.add_drawing_view(input_data.model_dump())
867
+ require_success(result, "Failed to add drawing view")
868
+ return {
869
+ "status": "success",
870
+ "message": "Drawing view added successfully",
871
+ "data": result.data,
872
+ "execution_time": result.execution_time,
873
+ }
874
+
875
+ @mcp.tool()
876
+ async def add_annotation(input_data: AnnotationInput) -> dict[str, Any]:
877
+ """Add an annotation such as a note, balloon, or surface symbol.
878
+
879
+ Places annotation text in a drawing with optional font size, leader attachment, and
880
+ title-block style metadata fields.
881
+
882
+ Args:
883
+ input_data (AnnotationInput): The input data value.
884
+
885
+ Returns:
886
+ dict[str, Any]: A dictionary containing the resulting values.
887
+ """
888
+ require_capability(
889
+ adapter,
890
+ "add_annotation",
891
+ "Active adapter does not support add_annotation; no annotation was added.",
892
+ )
893
+ result = await adapter.add_annotation(input_data.model_dump())
894
+ require_success(result, "Failed to add annotation")
895
+ return {
896
+ "status": "success",
897
+ "message": "Annotation added successfully",
898
+ "data": result.data,
899
+ "execution_time": result.execution_time,
900
+ }
901
+
902
+ @mcp.tool()
903
+ async def update_title_block(input_data: dict[str, Any]) -> dict[str, Any]:
904
+ """Update title block fields for the active drawing.
905
+
906
+ Applies drawing metadata such as title, drawing number, and approval fields to keep
907
+ documentation aligned with standards.
908
+
909
+ Args:
910
+ input_data (dict[str, Any]): The input data value.
911
+
912
+ Returns:
913
+ dict[str, Any]: A dictionary containing the resulting values.
914
+ """
915
+ require_capability(
916
+ adapter,
917
+ "update_title_block",
918
+ "Active adapter does not support update_title_block; the "
919
+ "title block was not changed.",
920
+ )
921
+ result = await adapter.update_title_block(input_data)
922
+ require_success(result, "Failed to update title block")
923
+ return {
924
+ "status": "success",
925
+ "message": "Title block updated successfully",
926
+ "data": result.data,
927
+ "execution_time": result.execution_time,
928
+ }
929
+
930
+ @mcp.tool()
931
+ async def list_drawing_views() -> dict[str, Any]:
932
+ """List the views on the active drawing.
933
+
934
+ Read-only. Use it to find an existing view's name before targeting it
935
+ (e.g. with ``auto_center_marks``). Errors when the active document is
936
+ not a drawing.
937
+
938
+ Returns:
939
+ dict[str, Any]: ``status``, ``views`` (view names, sheet formats
940
+ excluded) and ``count``.
941
+
942
+ Example:
943
+ ```python
944
+ await list_drawing_views()
945
+ ```
946
+ """
947
+ result = await adapter.list_drawing_views()
948
+ require_success(result, context="Failed to list drawing views")
949
+ views = list(result.data or [])
950
+ return {
951
+ "status": "success",
952
+ "message": (
953
+ f"{len(views)} view(s): {', '.join(views)}"
954
+ if views
955
+ else "The drawing has no views"
956
+ ),
957
+ "views": views,
958
+ "count": len(views),
959
+ "execution_time": result.execution_time,
960
+ }
961
+
962
+ @mcp.tool()
963
+ async def auto_center_marks(
964
+ input_data: AutoCenterMarksInput,
965
+ ) -> dict[str, Any]:
966
+ """Auto-insert centre marks on circular features in a drawing view.
967
+
968
+ Runs SolidWorks' automatic centre-mark insertion for the named view.
969
+ The API does not report how many marks it added, so the response
970
+ gives the view's centre-mark count before and after and the delta.
971
+ A run that added nothing is still a success — the view may have no
972
+ un-marked holes.
973
+
974
+ Args:
975
+ input_data (AutoCenterMarksInput): The view and which feature
976
+ types to mark.
977
+
978
+ Returns:
979
+ dict[str, Any]: Status plus ``center_marks_before`` /
980
+ ``center_marks_after`` / ``center_marks_added``.
981
+
982
+ Example:
983
+ ```python
984
+ await auto_center_marks({"view_name": "Drawing View1"})
985
+ ```
986
+ """
987
+ require_capability(
988
+ adapter,
989
+ "auto_center_marks",
990
+ "Active adapter does not support auto_center_marks; "
991
+ "no centre marks were inserted.",
992
+ )
993
+ input_data = normalize_input(input_data, AutoCenterMarksInput)
994
+ result = await adapter.auto_center_marks(
995
+ input_data.view_name,
996
+ input_data.mark_holes,
997
+ input_data.mark_fillets,
998
+ input_data.mark_slots,
999
+ )
1000
+ require_success(result, context="Failed to insert centre marks")
1001
+ data = result.data if isinstance(result.data, dict) else {}
1002
+ added = data.get("center_marks_added")
1003
+ return {
1004
+ "status": "success",
1005
+ "message": (
1006
+ f"Inserted {added} centre mark(s) on {input_data.view_name}"
1007
+ if isinstance(added, int)
1008
+ else f"Ran centre-mark insertion on {input_data.view_name}"
1009
+ ),
1010
+ "data": data,
1011
+ "execution_time": result.execution_time,
1012
+ }
1013
+
1014
+ tool_count = 14 # Number of tools registered
1015
+ return tool_count