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,777 @@
1
+ """Main SolidWorks MCP Server implementation using FastMCP and PydanticAI.
2
+
3
+ This server provides 154 tools for comprehensive SolidWorks automation with configurable
4
+ deployment (local/remote) and security options.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import asyncio
10
+ import inspect
11
+ import json
12
+ import os
13
+ import platform
14
+ import sys
15
+ import uuid
16
+ from pathlib import Path
17
+ from typing import Any
18
+
19
+ import typer
20
+ from fastmcp import FastMCP
21
+ from loguru import logger
22
+ from pydantic import BaseModel
23
+ from pydantic_ai import Agent
24
+
25
+ from . import adapters, security, tools, utils
26
+ from .adapters.base import AdapterResult
27
+ from .adapters.complexity_analyzer import ComplexityAnalyzer
28
+ from .adapters.intelligent_router import IntelligentRouter
29
+ from .adapters.vba_adapter import VbaGeneratorAdapter
30
+ from .agents.history_db import insert_tool_event
31
+ from .cache.response_cache import CachePolicy, ResponseCache
32
+ from .config import DeploymentMode, SolidWorksMCPConfig, load_config
33
+ from .exceptions import SolidWorksMCPError
34
+ from .version import __version__
35
+
36
+ AGENT_SYSTEM_PROMPT = (
37
+ "You are a SolidWorks automation expert. You have access to comprehensive "
38
+ "SolidWorks tools for CAD automation, modeling, drawing creation, analysis, "
39
+ "and file management. Always prioritize safety, accuracy, and user intent. "
40
+ "For complex operations, break them down into manageable steps."
41
+ )
42
+
43
+
44
+ class MCPServerState(BaseModel):
45
+ """Server state management - serializable fields only.
46
+
47
+ Attributes:
48
+ adapter (Any | None): The adapter value.
49
+ agent (Any | None): The agent value.
50
+ config (SolidWorksMCPConfig): The config value.
51
+ is_connected (bool): The is connected value.
52
+ startup_time (str | None): The startup time value.
53
+ tool_count (int): The tool count value.
54
+ """
55
+
56
+ config: SolidWorksMCPConfig
57
+ adapter: Any | None = None
58
+ agent: Any | None = None
59
+ is_connected: bool = False
60
+ startup_time: str | None = None
61
+ tool_count: int = 0
62
+
63
+
64
+ class SolidWorksMCPServer:
65
+ """Main SolidWorks MCP Server class.
66
+
67
+ Args:
68
+ config (SolidWorksMCPConfig): Configuration values for the operation.
69
+
70
+ Attributes:
71
+ _db_logging_enabled (Any): The db logging enabled value.
72
+ _db_path (Any): The db path value.
73
+ _db_run_id (Any): The db run id value.
74
+ _setup_complete (Any): The setup complete value.
75
+ config (Any): The config value.
76
+ mcp (Any): The mcp value.
77
+ server (Any): The server value.
78
+ state (Any): The state value.
79
+ """
80
+
81
+ def __init__(self, config: SolidWorksMCPConfig):
82
+ """Initialize the solid works mcpserver.
83
+
84
+ Args:
85
+ config (SolidWorksMCPConfig): Configuration values for the operation.
86
+ """
87
+ self.config = config
88
+ self.state = MCPServerState(config=config)
89
+ self.mcp = FastMCP("SolidWorks MCP Server", version=__version__)
90
+ self.server: FastMCP | None = None
91
+ self._setup_complete = False
92
+ self._db_logging_enabled = self._env_truthy(
93
+ os.getenv("SOLIDWORKS_MCP_DB_LOGGING", "0")
94
+ )
95
+ self._db_run_id = os.getenv("SOLIDWORKS_MCP_CONVERSATION_ID") or str(
96
+ uuid.uuid4()
97
+ )
98
+ self._db_path = (
99
+ os.getenv("SOLIDWORKS_MCP_DB_PATH")
100
+ if os.getenv("SOLIDWORKS_MCP_DB_PATH")
101
+ else None
102
+ )
103
+
104
+ # Runtime objects (not serializable)
105
+ self.adapter: Any | None = None
106
+ self.agent: Any | None = None
107
+ self._router: IntelligentRouter | None = None
108
+ self._vba_adapter: VbaGeneratorAdapter | None = None
109
+
110
+ @staticmethod
111
+ def _env_truthy(value: str | None) -> bool:
112
+ """Build internal env truthy.
113
+
114
+ Args:
115
+ value (str | None): The value value.
116
+
117
+ Returns:
118
+ bool: True if env truthy, otherwise False.
119
+ """
120
+
121
+ return str(value or "").strip().lower() in {"1", "true", "yes", "on"}
122
+
123
+ def _log_tool_event(
124
+ self,
125
+ *,
126
+ tool_name: str,
127
+ phase: str,
128
+ payload: dict[str, Any] | None,
129
+ ) -> None:
130
+ """Build internal log tool event.
131
+
132
+ Args:
133
+ tool_name (str): The tool name value.
134
+ phase (str): The phase value.
135
+ payload (dict[str, Any] | None): The payload value.
136
+
137
+ Returns:
138
+ None: None.
139
+ """
140
+
141
+ if not self._db_logging_enabled:
142
+ return
143
+ try:
144
+ insert_tool_event(
145
+ run_id=self._db_run_id,
146
+ tool_name=tool_name,
147
+ phase=phase,
148
+ payload_json=json.dumps(payload, ensure_ascii=True)
149
+ if payload is not None
150
+ else None,
151
+ db_path=(
152
+ Path(os.path.abspath(self._db_path))
153
+ if isinstance(self._db_path, str)
154
+ else None
155
+ ),
156
+ )
157
+ except Exception as exc:
158
+ logger.debug("Tool event logging skipped due to error: {}", exc)
159
+
160
+ def _configure_runtime_services(self) -> None:
161
+ """Initialize router and cache services and instrument adapter methods.
162
+
163
+ Returns:
164
+ None: None.
165
+ """
166
+ if self.adapter is None:
167
+ return
168
+
169
+ analyzer = ComplexityAnalyzer(
170
+ parameter_threshold=self.config.complexity_parameter_threshold,
171
+ score_threshold=self.config.complexity_score_threshold,
172
+ )
173
+ cache = ResponseCache(
174
+ CachePolicy(
175
+ enabled=self.config.enable_response_cache,
176
+ default_ttl_seconds=self.config.response_cache_ttl_seconds,
177
+ max_entries=self.config.response_cache_max_entries,
178
+ )
179
+ )
180
+ self._router = IntelligentRouter(analyzer=analyzer, cache=cache)
181
+ self._vba_adapter = VbaGeneratorAdapter(backing_adapter=self.adapter)
182
+
183
+ if self.config.enable_intelligent_routing:
184
+ self._instrument_adapter_methods()
185
+
186
+ def _instrument_adapter_methods(self) -> None:
187
+ """Route selected adapter methods through intelligent router.
188
+
189
+ Returns:
190
+ None: None.
191
+ """
192
+ if self.adapter is None or self._router is None:
193
+ return
194
+
195
+ routed_operations = {
196
+ "create_extrusion",
197
+ "create_revolve",
198
+ "create_sweep",
199
+ "create_loft",
200
+ "get_model_info",
201
+ "list_features",
202
+ "list_configurations",
203
+ "get_mass_properties",
204
+ # Additional analysis operations
205
+ "calculate_mass_properties",
206
+ "get_material_properties",
207
+ "analyze_geometry",
208
+ "check_interference",
209
+ # Drawing analysis operations
210
+ "analyze_drawing_comprehensive",
211
+ "analyze_drawing_dimensions",
212
+ "analyze_drawing_views",
213
+ "analyze_drawing_annotations",
214
+ "check_drawing_compliance",
215
+ "check_drawing_standards",
216
+ "compare_drawing_versions",
217
+ # Modeling operations that benefit from routing
218
+ "create_assembly",
219
+ "create_part",
220
+ "create_drawing",
221
+ "insert_component",
222
+ "add_mate",
223
+ # Sketching operations
224
+ "create_sketch",
225
+ "add_circle",
226
+ "add_rectangle",
227
+ "add_line",
228
+ "add_arc",
229
+ "add_spline",
230
+ "add_polygon",
231
+ "add_sketch_constraint",
232
+ "add_sketch_dimension",
233
+ # Drawing operations
234
+ "create_drawing_view",
235
+ "add_drawing_annotation",
236
+ "add_dimension",
237
+ # File and metadata operations
238
+ "get_file_properties",
239
+ "get_dimension",
240
+ "classify_feature_tree",
241
+ "discover_solidworks_docs",
242
+ }
243
+
244
+ for operation_name in routed_operations:
245
+ original_operation = getattr(self.adapter, operation_name, None)
246
+ if original_operation is None or not callable(original_operation):
247
+ continue
248
+
249
+ vba_operation = None
250
+ if self._vba_adapter is not None:
251
+ candidate = getattr(self._vba_adapter, operation_name, None)
252
+ if callable(candidate):
253
+ vba_operation = candidate
254
+
255
+ async def _routed_call(
256
+ *call_args: Any,
257
+ _operation_name: str = operation_name,
258
+ _com_callable: Any = original_operation,
259
+ _vba_callable: Any = vba_operation,
260
+ **call_kwargs: Any,
261
+ ) -> AdapterResult[Any]:
262
+ """Build internal routed call.
263
+
264
+ Args:
265
+ *call_args (Any): Additional positional arguments forwarded to the call.
266
+ _operation_name (str): The operation name value. Defaults to operation_name.
267
+ _com_callable (Any): The com callable value. Defaults to original_operation.
268
+ _vba_callable (Any): The vba callable value. Defaults to vba_operation.
269
+ **call_kwargs (Any): Additional keyword arguments forwarded to the call.
270
+
271
+ Returns:
272
+ AdapterResult[Any]: The result produced by the operation.
273
+ """
274
+ payload: Any
275
+ if call_kwargs:
276
+ payload = {
277
+ "args": call_args,
278
+ "kwargs": call_kwargs,
279
+ }
280
+ elif len(call_args) == 1:
281
+ payload = call_args[0]
282
+ elif call_args:
283
+ payload = {"args": call_args}
284
+ else:
285
+ payload = None
286
+
287
+ if self._router is None:
288
+ return await _com_callable(*call_args, **call_kwargs) # type: ignore[no-any-return]
289
+
290
+ result, _ = await self._router.execute(
291
+ operation=_operation_name,
292
+ payload=payload,
293
+ call_args=call_args,
294
+ call_kwargs=call_kwargs,
295
+ com_operation=_com_callable,
296
+ vba_operation=_vba_callable,
297
+ cache_ttl_seconds=self.config.response_cache_ttl_seconds,
298
+ )
299
+ return result
300
+
301
+ setattr(self.adapter, operation_name, _routed_call)
302
+
303
+ async def setup(self) -> None:
304
+ """Initialize the server components.
305
+
306
+ Returns:
307
+ None: None.
308
+ """
309
+ if self._setup_complete:
310
+ return
311
+
312
+ logger.info("Setting up SolidWorks MCP Server...")
313
+
314
+ # Validate environment
315
+ await utils.validate_environment(self.config)
316
+
317
+ # Setup security
318
+ await security.setup_security(self.mcp, self.config)
319
+
320
+ # Create SolidWorks adapter
321
+ self.adapter = await adapters.create_adapter(self.config)
322
+ self._configure_runtime_services()
323
+ self.state.adapter = self.adapter
324
+
325
+ # Register tools and derive canonical count from FastMCP runtime
326
+ await tools.register_tools(self.mcp, self.adapter, self.config)
327
+ self.state.tool_count = len(await self.mcp.list_tools())
328
+ self.server = self.mcp
329
+
330
+ # Setup PydanticAI agent after tools are registered so the agent can bind
331
+ # directly to the in-process FastMCP server without a transport hop.
332
+ await self._setup_agent()
333
+ self.state.agent = self.agent
334
+
335
+ self._setup_complete = True
336
+ logger.info(f"Server setup complete with {self.state.tool_count} tools")
337
+
338
+ async def _setup_agent(self) -> None:
339
+ """Setup PydanticAI agent for enhanced LLM integration.
340
+
341
+ Returns:
342
+ None: None.
343
+ """
344
+ if self.config.testing or self.config.mock_solidworks:
345
+ self.agent = None
346
+ return
347
+
348
+ if not os.getenv("OPENAI_API_KEY"):
349
+ logger.warning(
350
+ "Skipping PydanticAI agent setup because OPENAI_API_KEY is not configured"
351
+ )
352
+ self.agent = None
353
+ return
354
+
355
+ self.agent = Agent(
356
+ model="openai:gpt-4",
357
+ system_prompt=AGENT_SYSTEM_PROMPT,
358
+ )
359
+
360
+ logger.info("PydanticAI agent configured")
361
+
362
+ async def _run_local_stdio(self) -> None:
363
+ """Start local MCP stdio transport using the available FastMCP API.
364
+
365
+ Returns:
366
+ None: None.
367
+
368
+ Raises:
369
+ SolidWorksMCPError: FastMCP server does not expose a stdio runner.
370
+ """
371
+ if self.server is None:
372
+ self.server = self.mcp
373
+
374
+ stdin_is_readable = False
375
+ try:
376
+ stdin_is_readable = (
377
+ bool(sys.stdin) and not sys.stdin.closed and sys.stdin.readable()
378
+ )
379
+ except Exception:
380
+ stdin_is_readable = False
381
+
382
+ if self.config.mock_solidworks and not stdin_is_readable:
383
+ logger.warning(
384
+ "Skipping FastMCP stdio transport in mock mode because stdin is unavailable"
385
+ )
386
+ return
387
+
388
+ run_stdio = getattr(self.server, "run_stdio", None)
389
+ if callable(run_stdio):
390
+ result = run_stdio()
391
+ if inspect.isawaitable(result):
392
+ await result
393
+ return
394
+
395
+ run_stdio_async = getattr(self.server, "run_stdio_async", None)
396
+ if callable(run_stdio_async):
397
+ await run_stdio_async()
398
+ return
399
+
400
+ raise SolidWorksMCPError("FastMCP server does not expose a stdio runner")
401
+
402
+ async def start(self) -> None:
403
+ """Start the MCP server.
404
+
405
+ Returns:
406
+ None: None.
407
+ """
408
+ await self.setup()
409
+
410
+ if self.adapter:
411
+ try:
412
+ await self.adapter.connect()
413
+ self.state.is_connected = True
414
+ logger.info("Connected to SolidWorks")
415
+ except Exception as e:
416
+ logger.warning(f"Could not connect to SolidWorks: {e}")
417
+ if not self.config.mock_solidworks:
418
+ logger.warning("Continuing with mock adapter for testing")
419
+
420
+ # Record startup time
421
+ from datetime import datetime
422
+
423
+ self.state.startup_time = datetime.now().isoformat()
424
+
425
+ if self.config.deployment_mode == DeploymentMode.LOCAL:
426
+ # Local stdio mode for MCP
427
+ logger.info("Starting in local MCP mode (stdio)")
428
+ await self._run_local_stdio()
429
+ else:
430
+ # Remote HTTP mode
431
+ logger.info(
432
+ f"Starting in remote mode on {self.config.host}:{self.config.port}"
433
+ )
434
+ await self._start_http_server()
435
+
436
+ async def _start_http_server(self) -> None:
437
+ """Start HTTP server for remote access.
438
+
439
+ Returns:
440
+ None: None.
441
+ """
442
+ run_result = self.mcp.run( # type: ignore[func-returns-value]
443
+ transport="http", host=self.config.host, port=self.config.port
444
+ )
445
+ if inspect.isawaitable(run_result):
446
+ await run_result # type: ignore[unreachable]
447
+
448
+ async def stop(self) -> None:
449
+ """Gracefully stop the server.
450
+
451
+ Returns:
452
+ None: None.
453
+ """
454
+ logger.info("Stopping SolidWorks MCP Server...")
455
+
456
+ if self.adapter:
457
+ await self.adapter.disconnect()
458
+ self.state.is_connected = False
459
+
460
+ self._setup_complete = False
461
+ self.server = None
462
+ logger.info("Server stopped")
463
+
464
+ async def health_check(self) -> dict[str, Any]:
465
+ """Get server health status.
466
+
467
+ Returns:
468
+ dict[str, Any]: A dictionary containing the resulting values.
469
+ """
470
+ adapter_health = None
471
+ if self.adapter:
472
+ adapter_health = await self.adapter.health_check()
473
+
474
+ return {
475
+ "status": "healthy" if self.state.is_connected else "warning",
476
+ "config": {
477
+ "deployment_mode": self.config.deployment_mode,
478
+ "adapter_type": self.config.adapter_type,
479
+ "security_level": self.config.security_level,
480
+ "platform": platform.system(),
481
+ },
482
+ "state": {
483
+ "connected": self.state.is_connected,
484
+ "startup_time": self.state.startup_time,
485
+ "tool_count": self.state.tool_count,
486
+ },
487
+ "adapter": adapter_health,
488
+ }
489
+
490
+
491
+ async def server_status() -> dict[str, Any]:
492
+ """Get comprehensive server status information.
493
+
494
+ Returns:
495
+ dict[str, Any]: A dictionary containing the resulting values.
496
+ """
497
+ # This will be properly implemented when the server instance is available
498
+ return {
499
+ "status": "Server status endpoint - to be implemented with server state",
500
+ "message": "Use the main server health_check method for detailed status",
501
+ }
502
+
503
+
504
+ async def list_capabilities() -> dict[str, list[str]]:
505
+ """List all available SolidWorks capabilities and tool categories.
506
+
507
+ Returns:
508
+ dict[str, list[str]]: A dictionary containing the resulting values.
509
+ """
510
+ return {
511
+ "modeling": [
512
+ "create_part",
513
+ "create_assembly",
514
+ "create_drawing",
515
+ "create_extrusion",
516
+ "create_revolve",
517
+ "create_sweep",
518
+ "create_loft",
519
+ "create_cut",
520
+ "create_fillet",
521
+ "create_chamfer",
522
+ ],
523
+ "sketching": [
524
+ "create_sketch",
525
+ "add_line",
526
+ "add_circle",
527
+ "add_rectangle",
528
+ "add_arc",
529
+ "add_spline",
530
+ "add_dimension",
531
+ "add_relation",
532
+ ],
533
+ "drawing": [
534
+ "create_drawing_view",
535
+ "add_section_view",
536
+ "add_detail_view",
537
+ "add_dimension_to_view",
538
+ "add_annotation",
539
+ "create_drawing_template",
540
+ ],
541
+ "analysis": [
542
+ "get_mass_properties",
543
+ "perform_fea_analysis",
544
+ "check_interference",
545
+ "analyze_geometry",
546
+ "get_material_properties",
547
+ ],
548
+ "export": [
549
+ "export_step",
550
+ "export_iges",
551
+ "export_stl",
552
+ "export_pdf",
553
+ "export_dwg",
554
+ "export_images",
555
+ "batch_export",
556
+ ],
557
+ "automation": [
558
+ "generate_vba_macro",
559
+ "record_macro",
560
+ "batch_process",
561
+ "create_design_table",
562
+ "manage_configurations",
563
+ ],
564
+ "file_management": [
565
+ "open_file",
566
+ "save_file",
567
+ "save_as",
568
+ "close_file",
569
+ "get_file_properties",
570
+ "manage_references",
571
+ ],
572
+ }
573
+
574
+
575
+ def create_server(config: SolidWorksMCPConfig | None = None) -> SolidWorksMCPServer:
576
+ """Create a SolidWorks MCP Server instance.
577
+
578
+ Args:
579
+ config (SolidWorksMCPConfig | None): Configuration values for the operation.
580
+ Defaults to None.
581
+
582
+ Returns:
583
+ SolidWorksMCPServer: The result produced by the operation.
584
+ """
585
+ if config is None:
586
+ config = load_config()
587
+
588
+ return SolidWorksMCPServer(config)
589
+
590
+
591
+ async def _run_server(server: SolidWorksMCPServer) -> None:
592
+ """Run server lifecycle with graceful shutdown.
593
+
594
+ Args:
595
+ server (SolidWorksMCPServer): The server value.
596
+
597
+ Returns:
598
+ None: None.
599
+ """
600
+ try:
601
+ await server.start()
602
+ except KeyboardInterrupt:
603
+ logger.info("Received interrupt signal")
604
+ except Exception as e:
605
+ logger.error(f"Server error: {e}")
606
+ raise
607
+ finally:
608
+ await server.stop()
609
+
610
+
611
+ async def _run_with_config(config: SolidWorksMCPConfig) -> None:
612
+ """Run the server from a fully prepared config object.
613
+
614
+ Args:
615
+ config (SolidWorksMCPConfig): Configuration values for the operation.
616
+
617
+ Returns:
618
+ None: None.
619
+ """
620
+ utils.setup_logging(config)
621
+
622
+ logger.info("Starting SolidWorks MCP Server...")
623
+ logger.info(f"Platform: {platform.system()}")
624
+ logger.info(f"Python version: {sys.version}")
625
+ logger.info(f"Deployment mode: {config.deployment_mode}")
626
+ logger.info(f"Security level: {config.security_level}")
627
+
628
+ server = SolidWorksMCPServer(config)
629
+ await _run_server(server)
630
+
631
+
632
+ def cli(
633
+ config: str | None = typer.Option(
634
+ None,
635
+ "--config",
636
+ help="Configuration file path",
637
+ ),
638
+ mode: str | None = typer.Option(
639
+ None,
640
+ "--mode",
641
+ help="Deployment mode (local/remote/hybrid)",
642
+ ),
643
+ host: str = typer.Option(
644
+ "localhost",
645
+ "--host",
646
+ help="Server host for remote mode",
647
+ ),
648
+ port: int = typer.Option(
649
+ 8000,
650
+ "--port",
651
+ help="Server port for remote mode",
652
+ ),
653
+ debug: bool = typer.Option(
654
+ False,
655
+ "--debug",
656
+ help="Enable debug mode",
657
+ ),
658
+ mock: bool = typer.Option(
659
+ False,
660
+ "--mock",
661
+ help="Use mock SolidWorks for testing",
662
+ ),
663
+ ) -> None:
664
+ """Start the SolidWorks MCP server on stdio.
665
+
666
+ Run "solidworks-mcp-python setup" to connect your MCP clients to it.
667
+
668
+ \f
669
+ Everything after the form feed above is left out of ``--help``.
670
+
671
+ Args:
672
+ config: Path to a configuration file.
673
+ mode: Deployment mode: local, remote or hybrid.
674
+ host: Server host for remote mode.
675
+ port: Server port for remote mode.
676
+ debug: Log at DEBUG level.
677
+ mock: Answer from the mock adapter, without SolidWorks.
678
+ """
679
+ loaded_config = load_config(config)
680
+
681
+ if mode:
682
+ loaded_config.deployment_mode = DeploymentMode(mode)
683
+ if host:
684
+ loaded_config.host = host
685
+ if port:
686
+ loaded_config.port = port
687
+ if debug:
688
+ loaded_config.debug = True
689
+ loaded_config.log_level = "DEBUG"
690
+ if mock:
691
+ loaded_config.mock_solidworks = True
692
+
693
+ asyncio.run(_run_with_config(loaded_config))
694
+
695
+
696
+ async def main() -> None:
697
+ """Legacy async entry point retained for tests and internal callers.
698
+
699
+ Returns:
700
+ None: None.
701
+ """
702
+ import argparse
703
+
704
+ parser = argparse.ArgumentParser(description="SolidWorks MCP Server")
705
+ parser.add_argument(
706
+ "--config", help="Configuration file path", type=str, default=None
707
+ )
708
+ parser.add_argument(
709
+ "--mode",
710
+ help="Deployment mode (local/remote/hybrid)",
711
+ choices=["local", "remote", "hybrid"],
712
+ default=None,
713
+ )
714
+ parser.add_argument(
715
+ "--host", help="Server host for remote mode", default="localhost"
716
+ )
717
+ parser.add_argument(
718
+ "--port", help="Server port for remote mode", type=int, default=8000
719
+ )
720
+ parser.add_argument("--debug", help="Enable debug mode", action="store_true")
721
+ parser.add_argument(
722
+ "--mock", help="Use mock SolidWorks for testing", action="store_true"
723
+ )
724
+
725
+ args = parser.parse_args()
726
+
727
+ config = load_config(args.config)
728
+
729
+ if args.mode:
730
+ config.deployment_mode = DeploymentMode(args.mode)
731
+ if args.host:
732
+ config.host = args.host
733
+ if args.port:
734
+ config.port = args.port
735
+ if args.debug:
736
+ config.debug = True
737
+ config.log_level = "DEBUG"
738
+ if args.mock:
739
+ config.mock_solidworks = True
740
+
741
+ await _run_with_config(config)
742
+
743
+
744
+ def cli_main() -> None:
745
+ """Console script entry point using Typer CLI.
746
+
747
+ ``solidworks-mcp setup ...`` runs the guided client setup; anything else
748
+ starts the server.
749
+
750
+ Returns:
751
+ None: None.
752
+ """
753
+ if sys.argv[1:2] == ["setup"]:
754
+ from .setup.cli import app
755
+
756
+ app(args=sys.argv[2:], prog_name="solidworks-mcp setup")
757
+ return
758
+ typer.run(cli)
759
+
760
+
761
+ def run_server() -> None:
762
+ """Synchronous entry point for the server.
763
+
764
+ Returns:
765
+ None: None.
766
+ """
767
+ try:
768
+ asyncio.run(main())
769
+ except KeyboardInterrupt:
770
+ logger.info("Server stopped by user")
771
+ except Exception as e:
772
+ logger.error(f"Fatal error: {e}")
773
+ sys.exit(1)
774
+
775
+
776
+ if __name__ == "__main__":
777
+ cli_main()