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,9 @@
1
+ """Utilities for SolidWorks MCP Server."""
2
+
3
+ from .logging import setup_logging
4
+ from .validation import validate_environment
5
+
6
+ __all__ = [
7
+ "setup_logging",
8
+ "validate_environment",
9
+ ]
@@ -0,0 +1,342 @@
1
+ """Helpers for classifying SolidWorks model families from feature-tree snapshots."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Mapping
6
+ from typing import Any
7
+
8
+ _SHEET_METAL_TOKENS = (
9
+ "sheet-metal",
10
+ "sheet metal",
11
+ "base-flange",
12
+ "edge-flange",
13
+ "sketched bend",
14
+ "miter flange",
15
+ "hem",
16
+ "jog",
17
+ "unfold",
18
+ "fold",
19
+ "flatten",
20
+ "flat-pattern",
21
+ )
22
+
23
+ _ADVANCED_SOLID_TOKENS = (
24
+ "loft",
25
+ "boundary",
26
+ "sweep",
27
+ "shell",
28
+ "surface",
29
+ "split",
30
+ "combine",
31
+ "rib",
32
+ "dome",
33
+ )
34
+
35
+ _REVOLVE_TOKENS = (
36
+ "revolve",
37
+ "bossrevolve",
38
+ "boss-revolve",
39
+ "cutrevolve",
40
+ "cut-revolve",
41
+ )
42
+
43
+ _EXTRUDE_TOKENS = (
44
+ "extrude",
45
+ "boss-extrude",
46
+ "cut-extrude",
47
+ "bosscutextrude",
48
+ "featureextrusion",
49
+ )
50
+
51
+ _ASSEMBLY_TOKENS = ("mate", "component", "subassembly")
52
+ _DRAWING_TOKENS = (
53
+ "sheet format",
54
+ "drawing view",
55
+ "section view",
56
+ "detail view",
57
+ "model view",
58
+ )
59
+
60
+
61
+ def _as_lower_text(value: Any) -> str:
62
+ """Build internal as lower text.
63
+
64
+ Args:
65
+ value (Any): The value value.
66
+
67
+ Returns:
68
+ str: The resulting text value.
69
+ """
70
+
71
+ return str(value or "").strip().lower()
72
+
73
+
74
+ def _feature_text(feature: Mapping[str, Any]) -> str:
75
+ """Build internal feature text.
76
+
77
+ Args:
78
+ feature (Mapping[str, Any]): The feature value.
79
+
80
+ Returns:
81
+ str: The resulting text value.
82
+ """
83
+
84
+ name = _as_lower_text(feature.get("name"))
85
+ feature_type = _as_lower_text(feature.get("type"))
86
+ return f"{name} {feature_type}".strip()
87
+
88
+
89
+ def _has_any(texts: list[str], tokens: tuple[str, ...]) -> bool:
90
+ """Build internal has any.
91
+
92
+ Args:
93
+ texts (list[str]): The texts value.
94
+ tokens (tuple[str, ...]): The tokens value.
95
+
96
+ Returns:
97
+ bool: True if any, otherwise False.
98
+ """
99
+
100
+ return any(token in text for token in tokens for text in texts)
101
+
102
+
103
+ def _match_examples(
104
+ texts: list[str], tokens: tuple[str, ...], limit: int = 4
105
+ ) -> list[str]:
106
+ """Build internal match examples.
107
+
108
+ Args:
109
+ texts (list[str]): The texts value.
110
+ tokens (tuple[str, ...]): The tokens value.
111
+ limit (int): The limit value. Defaults to 4.
112
+
113
+ Returns:
114
+ list[str]: A list containing the resulting items.
115
+ """
116
+
117
+ matches: list[str] = []
118
+ for text in texts:
119
+ if any(token in text for token in tokens):
120
+ matches.append(text)
121
+ if len(matches) >= limit:
122
+ break
123
+ return matches
124
+
125
+
126
+ def classify_feature_tree_snapshot(
127
+ model_info: Mapping[str, Any] | None,
128
+ features: list[Mapping[str, Any]] | None,
129
+ ) -> dict[str, Any]:
130
+ """Classify a model family from model-info and feature-tree snapshots.
131
+
132
+ The output is intentionally simple and explainable so agents can use it as a planning
133
+ primitive rather than as a black-box prediction.
134
+
135
+ Args:
136
+ model_info (Mapping[str, Any] | None): The model info value.
137
+ features (list[Mapping[str, Any]] | None): The features value.
138
+
139
+ Returns:
140
+ dict[str, Any]: A dictionary containing the resulting values.
141
+ """
142
+
143
+ feature_list = list(features or [])
144
+ feature_texts = [_feature_text(feature) for feature in feature_list]
145
+ document_type = _as_lower_text((model_info or {}).get("type")) or "unknown"
146
+
147
+ evidence: list[str] = []
148
+ warnings: list[str] = []
149
+ next_actions: list[str] = []
150
+
151
+ family = "unknown"
152
+ workflow = "inspect-more"
153
+ confidence = "low"
154
+ needs_vba = False
155
+
156
+ if document_type == "assembly" or _has_any(feature_texts, _ASSEMBLY_TOKENS):
157
+ family = "assembly"
158
+ workflow = "assembly-planning"
159
+ confidence = "high" if document_type == "assembly" else "medium"
160
+ evidence.append("Assembly document or mate/component evidence detected")
161
+ next_actions.extend(
162
+ [
163
+ "List components and mates before planning inserts or edits",
164
+ "Delegate part-level reconstruction for each component separately",
165
+ ]
166
+ )
167
+ elif document_type == "drawing" or _has_any(feature_texts, _DRAWING_TOKENS):
168
+ family = "drawing"
169
+ workflow = "drawing-review"
170
+ confidence = "high" if document_type == "drawing" else "medium"
171
+ evidence.append("Drawing document or drawing-view evidence detected")
172
+ next_actions.append("Use drawing tools instead of part-modeling tools")
173
+ elif _has_any(feature_texts, _SHEET_METAL_TOKENS):
174
+ family = "sheet_metal"
175
+ workflow = "vba-sheet-metal"
176
+ confidence = "high"
177
+ needs_vba = True
178
+ evidence.extend(
179
+ _match_examples(feature_texts, _SHEET_METAL_TOKENS)
180
+ or ["Sheet metal features detected in the tree"]
181
+ )
182
+ next_actions.extend(
183
+ [
184
+ "Preserve base-flange and bend dependency order",
185
+ "If cuts appear between Unfold and Fold, keep them in flat-pattern state",
186
+ "Prefer a VBA-aware reconstruction plan until direct sheet metal tools exist",
187
+ ]
188
+ )
189
+ elif _has_any(feature_texts, _ADVANCED_SOLID_TOKENS):
190
+ family = "advanced_solid"
191
+ workflow = "vba-advanced-solid"
192
+ confidence = "medium"
193
+ needs_vba = True
194
+ evidence.extend(
195
+ _match_examples(feature_texts, _ADVANCED_SOLID_TOKENS)
196
+ or ["Advanced solid or surface features detected"]
197
+ )
198
+ next_actions.extend(
199
+ [
200
+ "Plan around loft/sweep/shell boundaries before issuing build commands",
201
+ "Prefer macro-backed execution for unsupported direct-MCP features",
202
+ ]
203
+ )
204
+ elif _has_any(feature_texts, _REVOLVE_TOKENS):
205
+ family = "revolve"
206
+ workflow = "direct-mcp-revolve"
207
+ confidence = "high"
208
+ evidence.extend(
209
+ _match_examples(feature_texts, _REVOLVE_TOKENS)
210
+ or ["Revolve features detected"]
211
+ )
212
+ next_actions.extend(
213
+ [
214
+ "Locate the axis sketch or centerline before recreating the profile",
215
+ "Verify the half-profile closes on the revolve axis",
216
+ ]
217
+ )
218
+ elif _has_any(feature_texts, _EXTRUDE_TOKENS):
219
+ family = "extrude"
220
+ workflow = "direct-mcp-extrude"
221
+ confidence = "high"
222
+ evidence.extend(
223
+ _match_examples(feature_texts, _EXTRUDE_TOKENS)
224
+ or ["Extrude features detected"]
225
+ )
226
+ next_actions.extend(
227
+ [
228
+ "Read the driving sketch before recreating downstream cuts or fillets",
229
+ "Verify closed-loop profiles before extrusion",
230
+ ]
231
+ )
232
+ else:
233
+ non_reference_count = 0
234
+ sketch_like_count = 0
235
+ for feature in feature_list:
236
+ feature_type = _as_lower_text(feature.get("type"))
237
+ if feature_type and feature_type not in {
238
+ "refplane",
239
+ "originprofilefeature",
240
+ }:
241
+ non_reference_count += 1
242
+ if feature_type in {"profilefeature", "3dprofilefeature", "sketch"}:
243
+ sketch_like_count += 1
244
+
245
+ if sketch_like_count > 0 and sketch_like_count == non_reference_count:
246
+ family = "sketch_only"
247
+ workflow = "inspect-more"
248
+ confidence = "low"
249
+ evidence.append("Only sketch-like features were found in the tree snapshot")
250
+ warnings.append(
251
+ "Feature tree may be incomplete for this adapter/runtime; do not infer the 3D family from sketches alone"
252
+ )
253
+ next_actions.extend(
254
+ [
255
+ "Combine feature-tree output with mass properties and exported images",
256
+ "Prefer reading the original file in SolidWorks before planning a rebuild",
257
+ ]
258
+ )
259
+ else:
260
+ warnings.append(
261
+ "No strong feature-family evidence found; keep planning provisional"
262
+ )
263
+ next_actions.extend(
264
+ [
265
+ "Inspect more of the model state before building",
266
+ "Avoid committing to direct-MCP or VBA-only paths until evidence improves",
267
+ ]
268
+ )
269
+
270
+ return {
271
+ "document_type": document_type or "unknown",
272
+ "family": family,
273
+ "recommended_workflow": workflow,
274
+ "confidence": confidence,
275
+ "needs_vba": needs_vba,
276
+ "evidence": evidence,
277
+ "warnings": warnings,
278
+ "next_actions": next_actions,
279
+ "feature_count": len(feature_list),
280
+ }
281
+
282
+
283
+ def build_component_tree(features: list[Mapping[str, Any]] | None) -> dict[str, Any]:
284
+ """Reconstruct a nested component/sub-component tree from a flat
285
+ ``list_features`` result.
286
+
287
+ ``list_features`` returns a single flat list — see
288
+ ``openspec/changes/archive/2026-10-30-assembly-aware-list-features/design.md`` for why:
289
+ several existing callers (feature-tree diffing, feature-family
290
+ classification, the MCP tool's ``count`` field) assume
291
+ ``AdapterResult.data`` is a flat ``list[dict]`` unconditionally, so the
292
+ adapter contract stays flat. Each descriptor carries ``component``
293
+ (owning component, or ``None`` for the document's own features) and
294
+ ``component_parent`` (that component's immediate parent component, or
295
+ ``None`` for a top-level component), which is enough to rebuild the
296
+ tree a caller actually wants to *look at* without changing what the
297
+ adapter returns.
298
+
299
+ Args:
300
+ features: The flat list returned in an ``AdapterResult.data`` from
301
+ ``list_features``. Rows without a ``component_parent`` key
302
+ (older data, or non-component rows) are treated as top-level.
303
+
304
+ Returns:
305
+ dict[str, Any]: ``{"features": [...], "components": {name: {"path":
306
+ ..., "features": [...], "components": {...nested...}}}}``. For a
307
+ Part document (no rows carry a ``component``), this is just
308
+ ``{"features": [...all rows...], "components": {}}``.
309
+ """
310
+ rows = list(features or [])
311
+
312
+ own_features = [dict(r) for r in rows if r.get("component") is None]
313
+ root: dict[str, Any] = {"features": own_features, "components": {}}
314
+
315
+ nodes: dict[str, dict[str, Any]] = {}
316
+ parent_of: dict[str, str | None] = {}
317
+
318
+ for row in rows:
319
+ component = row.get("component")
320
+ if component is None:
321
+ continue
322
+ node = nodes.setdefault(
323
+ component,
324
+ {"path": row.get("component_path"), "features": [], "components": {}},
325
+ )
326
+ if row.get("type") not in ("UnresolvedComponent", "Component"):
327
+ node["features"].append(dict(row))
328
+ if row.get("component_path") and not node.get("path"):
329
+ node["path"] = row["component_path"]
330
+ parent = row.get("component_parent")
331
+ if parent is not None or component not in parent_of:
332
+ parent_of[component] = parent
333
+
334
+ for name, node in nodes.items():
335
+ parent = parent_of.get(name)
336
+ parent_node = nodes.get(parent) if parent else None
337
+ target = (
338
+ parent_node["components"] if parent_node is not None else root["components"]
339
+ )
340
+ target[name] = node
341
+
342
+ return root
@@ -0,0 +1,76 @@
1
+ """Logging configuration for SolidWorks MCP Server."""
2
+
3
+ import sys
4
+ from pathlib import Path
5
+ from typing import Any
6
+
7
+ from loguru import logger
8
+
9
+ from ..config import SolidWorksMCPConfig
10
+
11
+
12
+ def setup_logging(config: SolidWorksMCPConfig) -> None:
13
+ """Configure application and audit logging sinks.
14
+
15
+ Args:
16
+ config (SolidWorksMCPConfig): Configuration values for the operation.
17
+
18
+ Returns:
19
+ None: None.
20
+ """
21
+ # Remove default handler
22
+ logger.remove()
23
+
24
+ # Console logging
25
+ logger.add(
26
+ sys.stderr,
27
+ level=config.log_level,
28
+ format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | "
29
+ "<level>{level: <8}</level> | "
30
+ "<cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> | "
31
+ "<level>{message}</level>",
32
+ colorize=True,
33
+ )
34
+
35
+ # File logging
36
+ if config.log_file:
37
+ # Ensure log directory exists
38
+ config.log_file.parent.mkdir(parents=True, exist_ok=True)
39
+
40
+ logger.add(
41
+ config.log_file,
42
+ level=config.log_level,
43
+ format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {name}:{function}:{line} | {message}",
44
+ rotation="10 MB",
45
+ retention="1 week",
46
+ )
47
+
48
+ # Audit logging for security
49
+ if config.enable_audit_logging:
50
+ audit_log = (
51
+ config.log_file.parent / "audit.log"
52
+ if config.log_file
53
+ else Path("audit.log")
54
+ )
55
+ audit_log.parent.mkdir(parents=True, exist_ok=True)
56
+
57
+ logger.add(
58
+ audit_log,
59
+ level="INFO",
60
+ format="{time:YYYY-MM-DD HH:mm:ss} | AUDIT | {extra[audit_type]} | {message}",
61
+ filter=lambda record: "audit" in record["extra"],
62
+ rotation="1 day",
63
+ retention="30 days",
64
+ compression="gz",
65
+ )
66
+
67
+ logger.info("Logging configured")
68
+
69
+
70
+ def get_audit_logger() -> Any:
71
+ """Create a logger bound to audit metadata.
72
+
73
+ Returns:
74
+ Any: The result produced by the operation.
75
+ """
76
+ return logger.bind(audit=True)
@@ -0,0 +1,77 @@
1
+ """Environment validation for SolidWorks MCP Server."""
2
+
3
+ import platform
4
+ import shutil
5
+
6
+ from loguru import logger
7
+
8
+ from ..config import SolidWorksMCPConfig
9
+ from ..exceptions import SolidWorksMCPError
10
+
11
+
12
+ async def validate_environment(config: SolidWorksMCPConfig) -> None:
13
+ """Validate runtime prerequisites for the server.
14
+
15
+ Args:
16
+ config (SolidWorksMCPConfig): Configuration values for the operation.
17
+
18
+ Returns:
19
+ None: None.
20
+
21
+ Raises:
22
+ SolidWorksMCPError: If the operation cannot be completed.
23
+ """
24
+ logger.info("Validating environment...")
25
+
26
+ # Check platform
27
+ if not config.can_use_solidworks and not config.mock_solidworks:
28
+ if platform.system() != "Windows":
29
+ logger.warning("SolidWorks requires Windows platform. Using mock adapter.")
30
+ else:
31
+ logger.warning("SolidWorks not available. Using mock adapter.")
32
+
33
+ # Check SolidWorks installation if on Windows
34
+ if (
35
+ config.enable_windows_validation
36
+ and platform.system() == "Windows"
37
+ and not config.mock_solidworks
38
+ ):
39
+ await _validate_solidworks_installation(config)
40
+
41
+ # Check Python version
42
+ import sys
43
+
44
+ python_version = sys.version_info
45
+ if python_version < (3, 13):
46
+ raise SolidWorksMCPError(
47
+ f"Python 3.13+ required, but running {python_version.major}.{python_version.minor}"
48
+ )
49
+
50
+ logger.info("Environment validation complete")
51
+
52
+
53
+ async def _validate_solidworks_installation(config: SolidWorksMCPConfig) -> None:
54
+ """Validate SolidWorks availability on Windows hosts.
55
+
56
+ Args:
57
+ config (SolidWorksMCPConfig): Configuration values for the operation.
58
+
59
+ Returns:
60
+ None: None.
61
+ """
62
+ # Check if SolidWorks executable exists
63
+ if config.solidworks_path:
64
+ if not shutil.which(config.solidworks_path):
65
+ logger.warning(
66
+ f"SolidWorks executable not found at: {config.solidworks_path}"
67
+ )
68
+
69
+ # Check COM registration only. Resolving the ProgID reads the registry;
70
+ # creating the object (Dispatch) would start SolidWorks.
71
+ try:
72
+ import pywintypes
73
+
74
+ pywintypes.IID("SldWorks.Application")
75
+ logger.info("SolidWorks COM interface is available")
76
+ except Exception as e:
77
+ logger.warning(f"SolidWorks COM interface issue: {e}")
@@ -0,0 +1,8 @@
1
+ """Version information for SolidWorks MCP Server."""
2
+
3
+ __version__ = "1.5.0"
4
+ __author__ = "Andrew Bartels"
5
+ __email__ = "andrewbartels1@gmail.com"
6
+ __description__ = "SolidWorks MCP Server with FastMCP and PydanticAI"
7
+ __original_author__ = "Vinnie Esposito"
8
+ __license__ = "MIT"