Skip to content

solidworks_mcp.adapters.pywin32_adapter

solidworks_mcp.adapters.pywin32_adapter

PyWin32 SolidWorks adapter for Windows COM integration.

This adapter uses pywin32 to communicate with SolidWorks via COM, providing real SolidWorks automation capabilities on Windows platforms.

Attributes

PYWIN32_AVAILABLE module-attribute

PYWIN32_AVAILABLE = True

T module-attribute

T = TypeVar('T')

Classes

AdapterHealth

Bases: BaseModel

Health status information for adapters.

Attributes:

Name Type Description
average_response_time float

The average response time value.

connection_status str

The connection status value.

error_count int

The error count value.

healthy bool

The healthy value.

last_check datetime

The last check value.

metrics dict[str, Any] | None

The metrics value.

success_count int

The success count value.

Functions
__contains__
__contains__(key: str) -> bool

Build internal contains.

Parameters:

Name Type Description Default
key str

The key value.

required

Returns:

Name Type Description
bool bool

True if contains, otherwise False.

Source code in src/solidworks_mcp/adapters/base.py
def __contains__(self, key: str) -> bool:
    """Build internal contains.

    Args:
        key (str): The key value.

    Returns:
        bool: True if contains, otherwise False.
    """
    legacy_keys = {"status", "connected", "adapter_type", "version", "uptime"}
    if key in legacy_keys:
        return True
    return key in self.model_dump()
__getitem__
__getitem__(key: str) -> Any

Build internal getitem.

Parameters:

Name Type Description Default
key str

The key value.

required

Returns:

Name Type Description
Any Any

The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
def __getitem__(self, key: str) -> Any:
    """Build internal getitem.

    Args:
        key (str): The key value.

    Returns:
        Any: The result produced by the operation.
    """
    if key == "status":
        return "healthy" if self.healthy else "unhealthy"
    if key == "connected":
        return self.connection_status == "connected"
    if key == "adapter_type":
        return (self.metrics or {}).get("adapter_type")
    if key == "version":
        return (self.metrics or {}).get("version", "mock-1.0")
    if key == "uptime":
        return (self.metrics or {}).get("uptime", 0.0)
    return self.model_dump().get(key)

AdapterResult dataclass

AdapterResult(status: AdapterResultStatus, data: T | None = None, error: str | None = None, execution_time: float | None = None, metadata: dict[str, Any] | None = None)

Bases: Generic[T]

Result wrapper for adapter operations.

Attributes:

Name Type Description
data T | None

The data value.

error str | None

The error value.

execution_time float | None

The execution time value.

metadata dict[str, Any] | None

The metadata value.

status AdapterResultStatus

The status value.

Attributes
is_error property
is_error: bool

Check if operation had an error.

Returns:

Name Type Description
bool bool

True if error, otherwise False.

is_success property
is_success: bool

Check if operation was successful.

Returns:

Name Type Description
bool bool

True if success, otherwise False.

AdapterResultStatus

Bases: StrEnum

Result status for adapter operations.

Attributes:

Name Type Description
ERROR Any

The error value.

SUCCESS Any

The success value.

TIMEOUT Any

The timeout value.

WARNING Any

The warning value.

PyWin32Adapter

PyWin32Adapter(config: dict[str, Any] | None = None)

Bases: SolidWorksSketchMixin, SolidWorksFeaturesMixin, SolidWorksIOMixin, SolidWorksSelectionMixin, SolidWorksAdapter

SolidWorks adapter using pywin32 COM integration.

This adapter provides direct COM integration with SolidWorks using pywin32, enabling real-time automation and control of SolidWorks applications on Windows.

Parameters:

Name Type Description Default
config dict[str, Any] | None

Configuration values for the operation. Defaults to None.

None

Raises:

Type Description
SolidWorksMCPError

PyWin32Adapter requires Windows platform.

Attributes:

Name Type Description
constants Any

The constants value.

Example
adapter = PyWin32Adapter({'timeout': 30})
result = await adapter.connect()
if result.status == AdapterResultStatus.SUCCESS:
    print("Connected to SolidWorks successfully")

Initialize PyWin32Adapter with configuration.

Parameters:

Name Type Description Default
config dict[str, Any] | None

Configuration values for the operation. Defaults to None.

None

Returns:

Name Type Description
None None

None.

Raises:

Type Description
SolidWorksMCPError

PyWin32Adapter requires Windows platform.

Example
config = {
    "timeout": 30,
    "auto_connect": True,
    "startup_timeout": 60
}
adapter = PyWin32Adapter(config)
Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
def __init__(self, config: dict[str, Any] | None = None) -> None:
    """Initialize PyWin32Adapter with configuration.

    Args:
        config (dict[str, Any] | None): Configuration values for the operation. Defaults to
                                        None.

    Returns:
        None: None.

    Raises:
        SolidWorksMCPError: PyWin32Adapter requires Windows platform.

    Example:
                        ```python
                        config = {
                            "timeout": 30,
                            "auto_connect": True,
                            "startup_timeout": 60
                        }
                        adapter = PyWin32Adapter(config)
                        ```
    """
    if not PYWIN32_AVAILABLE:  # pragma: no cover
        raise SolidWorksMCPError(
            "pywin32 is not available. Install with: pip install pywin32"
        )

    if platform.system() != "Windows":  # pragma: no cover
        raise SolidWorksMCPError("PyWin32Adapter requires Windows platform")

    super().__init__(config)

    self.swApp: Any | None = None
    self.currentModel: Any | None = None
    self.currentSketch: Any | None = None
    self.currentSketchManager: Any | None = None
    self._last_sketch_name: str | None = None
    self._sketch_count: int = 0  # incremented each time a sketch is created
    self._sketch_entities: dict[str, Any] = {}
    # Cached (center_x_mm, center_y_mm) for entities whose center can't be
    # recovered via ``GetCenterPoint`` — currently polygons, which register
    # as a SAFEARRAY of segment handles (no single dispatch to read from).
    # ``sketch_circular_pattern`` reads this to derive the seed-to-axis
    # offset for polygon seeds.
    self._sketch_entity_centers: dict[str, tuple[float, float]] = {}
    self._sketch_entity_counter = 0
    self._com_initialized = False

    # COM constants (equivalent to SolidWorks API constants)
    self.constants = {
        # Document types
        "swDocPART": 1,
        "swDocASSEMBLY": 2,
        "swDocDRAWING": 3,
        # Selection types
        "swSelFACES": 1,
        "swSelEDGES": 2,
        "swSelVERTICES": 3,
        "swSelSKETCHSEGS": 4,
        "swSelSKETCHPOINTS": 5,
        "swSelDATUMPLANES": 6,
        # Feature end conditions
        "swEndCondBlind": 0,
        "swEndCondThroughAll": 1,
        "swEndCondUpToNext": 2,
        "swEndCondUpToSurface": 3,
        "swEndCondOffset": 4,
        "swEndCondUpToVertex": 5,
        "swEndCondMidPlane": 6,
        # Dimension preferences / directions
        "swInputDimValOnCreate": 10,
        "swSketchAcceptNumericInput": 372,
        "swSketchCreateDimensionOnlyWhenEntered": 520,
        "swScaleSketchOnFirstDimension": 642,
        "swSmartDimensionDirectionRight": 0,
        "swSmartDimensionDirectionUp": 1,
        "swSmartDimensionDirectionLeft": 2,
        "swSmartDimensionDirectionDown": 3,
    }

    self._session_coordinator = _ComSessionCoordinator(self)
    self._sketch_geometry = _SketchGeometryService(self)
    self._document_routing = _DocumentRoutingService(self)
    self._feature_selector = _FeatureSelectionService(self)
Functions
connect async
connect() -> None

Connect to SolidWorks COM and prepare automation-safe session state.

Raises:

Type Description
SolidWorksMCPError

If connection or readiness checks fail.

Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
async def connect(self) -> None:
    """Connect to SolidWorks COM and prepare automation-safe session state.

    Raises:
        SolidWorksMCPError: If connection or readiness checks fail.
    """
    await self._session_coordinator.connect()
disconnect async
disconnect() -> None

Disconnect from SolidWorks application.

Properly disconnects from SolidWorks COM interface and cleans up resources. This method should always be called when finished to prevent memory leaks.

Note: - Clears references to current model and application - Uninitialize COM apartment - Does not close SolidWorks application itself

Returns:

Name Type Description
None None

None.

Example
try:
    await adapter.connect()
    # ... do work ...
finally:
    await adapter.disconnect()
Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
async def disconnect(self) -> None:
    """Disconnect from SolidWorks application.

    Properly disconnects from SolidWorks COM interface and cleans up resources. This method
    should always be called when finished to prevent memory leaks.

    Note: - Clears references to current model and application - Uninitialize COM apartment
    - Does not close SolidWorks application itself

    Returns:
        None: None.

    Example:
                        ```python
                        try:
                            await adapter.connect()
                            # ... do work ...
                        finally:
                            await adapter.disconnect()
                        ```
    """
    await self._session_coordinator.disconnect()
execute_macro async
execute_macro(params: dict[str, Any]) -> AdapterResult[dict[str, Any]]

Provide execute macro support for the py win32 adapter.

Parameters:

Name Type Description Default
params dict[str, Any]

The params value.

required

Returns:

Type Description
AdapterResult[dict[str, Any]]

AdapterResult[dict[str, Any]]: The result produced by the operation.

Raises:

Type Description
SolidWorksMCPError

If the operation cannot be completed.

Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
async def execute_macro(
    self, params: dict[str, Any]
) -> AdapterResult[dict[str, Any]]:
    """Provide execute macro support for the py win32 adapter.

    Args:
        params (dict[str, Any]): The params value.

    Returns:
        AdapterResult[dict[str, Any]]: The result produced by the operation.

    Raises:
        SolidWorksMCPError: If the operation cannot be completed.
    """
    macro_path = params.get("macro_path") or params.get("macro_file") or ""
    if not macro_path:
        return AdapterResult(
            status=AdapterResultStatus.ERROR, error="No macro_path provided"
        )
    if not os.path.isfile(macro_path):
        return AdapterResult(
            status=AdapterResultStatus.ERROR,
            error=f"Macro file not found: {macro_path}",
        )

    def _run() -> dict[str, Any]:
        """Resolve module/proc names and delegate to _invoke_run_macro2.

        Returns:
            dict[str, Any]: A dictionary containing the resulting values.

        Raises:
            SolidWorksMCPError: If the operation cannot be completed.
        """
        module_name = _parse_vb_module_name(macro_path)
        proc_name = params.get("proc_name", "main")
        return self._invoke_run_macro2(macro_path, module_name, proc_name)

    return self._handle_com_operation("execute_macro", _run)
export_file async
export_file(file_path: str, format_type: str) -> AdapterResult[None]

Export the current model to a file.

Parameters:

Name Type Description Default
file_path str

Path to the target file.

required
format_type str

The format type value.

required

Returns:

Type Description
AdapterResult[None]

AdapterResult[None]: The result produced by the operation.

Raises:

Type Description
Exception

If the operation cannot be completed.

RuntimeError

No active SolidWorks document for export.

Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
async def export_file(
    self, file_path: str, format_type: str
) -> AdapterResult[None]:
    """Export the current model to a file.

    Args:
        file_path (str): Path to the target file.
        format_type (str): The format type value.

    Returns:
        AdapterResult[None]: The result produced by the operation.

    Raises:
        Exception: If the operation cannot be completed.
        RuntimeError: No active SolidWorks document for export.
    """
    if not self.currentModel:
        return AdapterResult(
            status=AdapterResultStatus.ERROR, error="No active model"
        )

    def _export_operation() -> None:
        """Build internal export operation.

        Returns:
            None: None.

        Raises:
            Exception: If the operation cannot be completed.
            RuntimeError: No active SolidWorks document for export.
        """
        format_map = {
            "step": 0,  # swSaveAsSTEP
            "iges": 1,  # swSaveAsIGS
            "stl": 2,  # swSaveAsSTL
            "pdf": 3,  # swSaveAsPDF
            "dwg": 4,  # swSaveAsDWG
            "jpg": 5,  # swSaveAsJPEG
            "glb": 41,  # swSaveAsGLTF (binary GLTF, SW 2023+)
            "gltf": 41,  # same enum value, text GLTF
        }

        format_lower = format_type.lower()
        if format_lower not in format_map:
            raise Exception(f"Unsupported export format: {format_type}")

        resolved_path = os.path.abspath(file_path)
        os.makedirs(os.path.dirname(resolved_path), exist_ok=True)

        if os.path.exists(resolved_path):
            self._attempt(lambda: os.remove(resolved_path))

        # Prefer swApp.ActiveDoc — more reliably typed than the late-bound
        # IDispatch reference stored in self.currentModel after OpenDoc6.
        # Use getattr so tests can pass a SimpleNamespace without ActiveDoc.
        target_doc = (
            getattr(self.swApp, "ActiveDoc", None) if self.swApp else None
        ) or self.currentModel

        # ----------------------------------------------------------------
        # STL export: use Extension.SaveAs2 + ISTLExportData
        # for both parts AND assemblies.  SaveAs3 with format=2 works for
        # parts but is unreliable for assemblies (only exports first body).
        # ----------------------------------------------------------------
        if format_lower == "stl":
            # For assemblies, resolve lightweight components first so all
            # geometry is available for the mesh export.
            self._attempt(lambda: target_doc.ResolveAllLightweightComponents(True))

            ext = getattr(target_doc, "Extension", None)
            if ext is None:
                raise RuntimeError("No Extension object available for STL export")

            stl_data = self._prepare_stl_export_data()
            if not self._save_stl_with_extension(ext, stl_data, resolved_path):
                # SaveAs2 didn't produce file — try SaveAs3 fallback
                self._save_stl_with_fallback(target_doc, resolved_path)

            return None

        # ----------------------------------------------------------------
        # All other formats — classic SaveAs3 path.
        # SaveAs3 signature: SaveAs3(FileName, Version, Options)
        # Version = 0 means "current version" (swSaveAsCurrentVersion).
        # SolidWorks infers the export format from the file extension, so
        # we must NOT pass the format-enum value as the Version argument.
        # ----------------------------------------------------------------
        _ = format_map[format_lower]  # validate format is known; value unused
        logger.debug(
            "[pywin32.export_file] SaveAs3 {} (version=0, options=Silent)",
            resolved_path,
        )
        success = target_doc.SaveAs3(
            resolved_path,
            0,  # swSaveAsCurrentVersion — format inferred from file extension
            2,  # swSaveAsOptions_Silent
        )

        if not success and not os.path.exists(resolved_path):
            raise Exception(
                f"SaveAs3 returned False and no file produced: {resolved_path}"
            )

        return None

    return self._handle_com_operation("export_file", _export_operation)
export_image async
export_image(payload: dict) -> AdapterResult[dict]

Export a screenshot of the current model to a PNG/JPG file.

Payload keys (matching ExportImageInput): file_path (str): Output path including extension. format_type (str): "png" or "jpg". Default "png". width (int): Pixel width. Default 1280. height (int): Pixel height. Default 720. view_orientation (str): "front" | "top" | "right" | "isometric" | "current".

Parameters:

Name Type Description Default
payload dict

The payload value.

required

Returns:

Type Description
AdapterResult[dict]

AdapterResult[dict]: The result produced by the operation.

Raises:

Type Description
RuntimeError

If the operation cannot be completed.

Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
async def export_image(self, payload: dict) -> AdapterResult[dict]:
    """Export a screenshot of the current model to a PNG/JPG file.

    Payload keys (matching ExportImageInput): file_path (str): Output path including
    extension. format_type (str): "png" or "jpg". Default "png". width (int): Pixel width.
    Default 1280. height (int): Pixel height. Default 720. view_orientation (str): "front" |
    "top" | "right" | "isometric" | "current".

    Args:
        payload (dict): The payload value.

    Returns:
        AdapterResult[dict]: The result produced by the operation.

    Raises:
        RuntimeError: If the operation cannot be completed.
    """
    if not self.currentModel:
        return AdapterResult(
            status=AdapterResultStatus.ERROR, error="No active model"
        )
    if not self.swApp:
        return AdapterResult(
            status=AdapterResultStatus.ERROR, error="SolidWorks not connected"
        )

    orientation = str(payload.get("view_orientation", "current")).lower()
    file_path = payload.get("file_path", "")
    width = int(payload.get("width", 1280))
    height = int(payload.get("height", 720))

    # Map orientation names to SolidWorks swStandardViews_e constants
    _VIEW_CONSTANTS = {
        "front": 1,  # swFrontView
        "back": 2,  # swBackView
        "left": 3,  # swLeftView
        "right": 4,  # swRightView
        "top": 5,  # swTopView
        "bottom": 6,  # swBottomView
        "isometric": 7,  # swIsometricView
        "dimetric": 8,  # swDimetricView
        "trimetric": 9,  # swTriMetricView
    }

    def _screenshot_operation() -> dict:
        """Build internal screenshot operation.

        Returns:
            dict: A dictionary containing the resulting values.

        Raises:
            RuntimeError: If the operation cannot be completed.
        """

        import os as _os

        resolved = _os.path.abspath(file_path)
        _os.makedirs(_os.path.dirname(resolved), exist_ok=True)

        target_doc = self._resolve_export_target_doc()

        # Ensure SolidWorks window is focused so the viewport is rendered.
        # Required for both view changes and bitmap capture.
        self._attempt(lambda: self.swApp.Frame.SetFocus())

        # Set view orientation if requested
        if orientation != "current" and orientation in _VIEW_CONSTANTS:
            view_const = _VIEW_CONSTANTS[orientation]
            self._set_view_orientation(target_doc, orientation, view_const)

        # Zoom to fit so the model fills the viewport before capture
        self._zoom_to_fit(target_doc)

        # Try screenshot methods in order: ModelView → TargetDoc → SaveAs3
        saved = self._save_screenshot_with_modelview(
            target_doc, resolved, width, height
        )
        if not saved:
            saved = self._save_screenshot_with_targetdoc(
                target_doc, resolved, width, height
            )
        if not saved:
            self._save_screenshot_with_saveas3(target_doc, resolved)
            saved = _os.path.exists(resolved)

        if not saved:
            raise RuntimeError(
                f"All screenshot methods produced no output for {resolved}"
            )

        return {
            "file_path": resolved,
            "format": _os.path.splitext(resolved)[1].lstrip(".").upper() or "PNG",
            "dimensions": f"{width}x{height}",
            "view": orientation,
        }

    return self._handle_com_operation("export_image", _screenshot_operation)
health_check async
health_check() -> AdapterHealth

Get adapter health status.

Performs comprehensive health check including connection status, operation metrics, and SolidWorks application responsiveness.

Returns:

Name Type Description
AdapterHealth AdapterHealth

The result produced by the operation.

Example
health = await adapter.health_check()
if health.healthy:
    print(f"Adapter healthy, {health.success_count} operations completed")
else:
    print(f"Adapter unhealthy: {health.error_count} errors")
Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
async def health_check(self) -> AdapterHealth:
    """Get adapter health status.

    Performs comprehensive health check including connection status, operation metrics, and
    SolidWorks application responsiveness.

    Returns:
        AdapterHealth: The result produced by the operation.

    Example:
                        ```python
                        health = await adapter.health_check()
                        if health.healthy:
                            print(f"Adapter healthy, {health.success_count} operations completed")
                        else:
                            print(f"Adapter unhealthy: {health.error_count} errors")
                        ```
    """
    healthy = self.is_connected()

    # Support both callable COM method and property-style RevisionNumber.
    sw_version: str | None = None
    if self.swApp:
        sw_version = self._attempt(
            lambda: self._get_attr_or_call(self.swApp, "RevisionNumber")
        )

    # Try a simple operation to verify connection
    if healthy:
        healthy = sw_version is not None

    return AdapterHealth(
        healthy=healthy,
        last_check=datetime.now(),
        error_count=int(self._metrics["errors_count"]),
        success_count=int(
            self._metrics["operations_count"] - self._metrics["errors_count"]
        ),
        average_response_time=self._metrics["average_response_time"],
        connection_status="connected" if healthy else "disconnected",
        metrics={
            "adapter_type": "pywin32",
            "sw_version": sw_version or "Unknown",
            "current_model": self.currentModel.GetTitle()
            if self.currentModel
            else None,
        },
    )
is_connected
is_connected() -> bool

Check if connected to SolidWorks.

Returns:

Name Type Description
bool bool

True if connected, otherwise False.

Example
if adapter.is_connected():
    print("Ready to automate SolidWorks")
else:
    await adapter.connect()
Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
def is_connected(self) -> bool:
    """Check if connected to SolidWorks.

    Returns:
        bool: True if connected, otherwise False.

    Example:
                        ```python
                        if adapter.is_connected():
                            print("Ready to automate SolidWorks")
                        else:
                            await adapter.connect()
                        ```
    """
    return self.swApp is not None

SolidWorksAdapter

SolidWorksAdapter(config: object | None = None)

Bases: ABC

Base adapter interface for SolidWorks integration.

Parameters:

Name Type Description Default
config object | None

Configuration values for the operation. Defaults to None.

None

Attributes:

Name Type Description
_metrics Any

The metrics value.

config Any

The config value.

config_dict Any

The config dict value.

Initialize adapter with configuration.

Parameters:

Name Type Description Default
config object | None

Configuration values for the operation. Defaults to None.

None
Source code in src/solidworks_mcp/adapters/base.py
def __init__(self, config: object | None = None):
    """Initialize adapter with configuration.

    Args:
        config (object | None): Configuration values for the operation. Defaults to None.
    """
    if config is None:
        normalized_config: dict[str, Any] = {}
    elif isinstance(config, Mapping):
        normalized_config = dict(config)
    elif hasattr(config, "model_dump"):
        normalized_config = dict(config.model_dump())
    else:
        normalized_config = {}

    # Preserve original config object for compatibility with tests and
    # call sites that compare object identity/equality.
    self.config = config
    # Keep a normalized mapping for adapter internals.
    self.config_dict = normalized_config
    self._metrics = {
        "operations_count": 0,
        "errors_count": 0,
        "average_response_time": 0.0,
    }
Functions
add_arc async
add_arc(center_x: float, center_y: float, start_x: float, start_y: float, end_x: float, end_y: float) -> AdapterResult[str]

Add an arc to the current sketch.

Parameters:

Name Type Description Default
center_x float

The center x value.

required
center_y float

The center y value.

required
start_x float

The start x value.

required
start_y float

The start y value.

required
end_x float

The end x value.

required
end_y float

The end y value.

required

Returns:

Type Description
AdapterResult[str]

AdapterResult[str]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
async def add_arc(
    self,
    center_x: float,
    center_y: float,
    start_x: float,
    start_y: float,
    end_x: float,
    end_y: float,
) -> AdapterResult[str]:
    """Add an arc to the current sketch.

    Args:
        center_x (float): The center x value.
        center_y (float): The center y value.
        start_x (float): The start x value.
        start_y (float): The start y value.
        end_x (float): The end x value.
        end_y (float): The end y value.

    Returns:
        AdapterResult[str]: The result produced by the operation.
    """
    return AdapterResult(
        status=AdapterResultStatus.ERROR,
        error="add_arc is not implemented by this adapter",
    )
add_centerline async
add_centerline(x1: float, y1: float, x2: float, y2: float) -> AdapterResult[str]

Add a centerline to the current sketch.

Parameters:

Name Type Description Default
x1 float

The x1 value.

required
y1 float

The y1 value.

required
x2 float

The x2 value.

required
y2 float

The y2 value.

required

Returns:

Type Description
AdapterResult[str]

AdapterResult[str]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
async def add_centerline(
    self, x1: float, y1: float, x2: float, y2: float
) -> AdapterResult[str]:
    """Add a centerline to the current sketch.

    Args:
        x1 (float): The x1 value.
        y1 (float): The y1 value.
        x2 (float): The x2 value.
        y2 (float): The y2 value.

    Returns:
        AdapterResult[str]: The result produced by the operation.
    """
    return AdapterResult(
        status=AdapterResultStatus.ERROR,
        error="add_centerline is not implemented by this adapter",
    )
add_circle abstractmethod async
add_circle(center_x: float, center_y: float, radius: float) -> AdapterResult[str]

Add a circle to the current sketch.

Parameters:

Name Type Description Default
center_x float

The center x value.

required
center_y float

The center y value.

required
radius float

The radius value.

required

Returns:

Type Description
AdapterResult[str]

AdapterResult[str]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
@abstractmethod
async def add_circle(
    self, center_x: float, center_y: float, radius: float
) -> AdapterResult[str]:
    """Add a circle to the current sketch.

    Args:
        center_x (float): The center x value.
        center_y (float): The center y value.
        radius (float): The radius value.

    Returns:
        AdapterResult[str]: The result produced by the operation.
    """
    pass
add_ellipse async
add_ellipse(center_x: float, center_y: float, major_axis: float, minor_axis: float) -> AdapterResult[str]

Add an ellipse to the current sketch.

Parameters:

Name Type Description Default
center_x float

The center x value.

required
center_y float

The center y value.

required
major_axis float

The major axis value.

required
minor_axis float

The minor axis value.

required

Returns:

Type Description
AdapterResult[str]

AdapterResult[str]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
async def add_ellipse(
    self,
    center_x: float,
    center_y: float,
    major_axis: float,
    minor_axis: float,
) -> AdapterResult[str]:
    """Add an ellipse to the current sketch.

    Args:
        center_x (float): The center x value.
        center_y (float): The center y value.
        major_axis (float): The major axis value.
        minor_axis (float): The minor axis value.

    Returns:
        AdapterResult[str]: The result produced by the operation.
    """
    return AdapterResult(
        status=AdapterResultStatus.ERROR,
        error="add_ellipse is not implemented by this adapter",
    )
add_fillet async
add_fillet(radius: float, edge_names: list[str]) -> 'AdapterResult[Any]'

Add a fillet feature to selected edges.

Rounds the selected edges of the current solid body with the given radius.

Parameters:

Name Type Description Default
radius float

Fillet radius in millimeters.

required
edge_names list[str]

List of edge names to fillet.

required

Returns:

Name Type Description
AdapterResult 'AdapterResult[Any]'

Feature result or error.

Source code in src/solidworks_mcp/adapters/base.py
async def add_fillet(
    self, radius: float, edge_names: list[str]
) -> "AdapterResult[Any]":
    """Add a fillet feature to selected edges.

    Rounds the selected edges of the current solid body with the given radius.

    Args:
        radius (float): Fillet radius in millimeters.
        edge_names (list[str]): List of edge names to fillet.

    Returns:
        AdapterResult: Feature result or error.
    """
    return AdapterResult(
        status=AdapterResultStatus.ERROR,
        error="add_fillet is not implemented by this adapter",
    )
add_line abstractmethod async
add_line(x1: float, y1: float, x2: float, y2: float) -> AdapterResult[str]

Add a line to the current sketch.

Parameters:

Name Type Description Default
x1 float

The x1 value.

required
y1 float

The y1 value.

required
x2 float

The x2 value.

required
y2 float

The y2 value.

required

Returns:

Type Description
AdapterResult[str]

AdapterResult[str]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
@abstractmethod
async def add_line(
    self, x1: float, y1: float, x2: float, y2: float
) -> AdapterResult[str]:
    """Add a line to the current sketch.

    Args:
        x1 (float): The x1 value.
        y1 (float): The y1 value.
        x2 (float): The x2 value.
        y2 (float): The y2 value.

    Returns:
        AdapterResult[str]: The result produced by the operation.
    """
    pass
add_polygon async
add_polygon(center_x: float, center_y: float, radius: float, sides: int) -> AdapterResult[str]

Add a regular polygon to the current sketch.

Parameters:

Name Type Description Default
center_x float

The center x value.

required
center_y float

The center y value.

required
radius float

The radius value.

required
sides int

The sides value.

required

Returns:

Type Description
AdapterResult[str]

AdapterResult[str]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
async def add_polygon(
    self, center_x: float, center_y: float, radius: float, sides: int
) -> AdapterResult[str]:
    """Add a regular polygon to the current sketch.

    Args:
        center_x (float): The center x value.
        center_y (float): The center y value.
        radius (float): The radius value.
        sides (int): The sides value.

    Returns:
        AdapterResult[str]: The result produced by the operation.
    """
    return AdapterResult(
        status=AdapterResultStatus.ERROR,
        error="add_polygon is not implemented by this adapter",
    )
add_rectangle abstractmethod async
add_rectangle(x1: float, y1: float, x2: float, y2: float) -> AdapterResult[str]

Add a rectangle to the current sketch.

Parameters:

Name Type Description Default
x1 float

The x1 value.

required
y1 float

The y1 value.

required
x2 float

The x2 value.

required
y2 float

The y2 value.

required

Returns:

Type Description
AdapterResult[str]

AdapterResult[str]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
@abstractmethod
async def add_rectangle(
    self, x1: float, y1: float, x2: float, y2: float
) -> AdapterResult[str]:
    """Add a rectangle to the current sketch.

    Args:
        x1 (float): The x1 value.
        y1 (float): The y1 value.
        x2 (float): The x2 value.
        y2 (float): The y2 value.

    Returns:
        AdapterResult[str]: The result produced by the operation.
    """
    pass
add_sketch_circle async
add_sketch_circle(center_x: float, center_y: float, radius: float, construction: bool = False) -> AdapterResult[str]

Alias for add_circle used by some tool flows.

Parameters:

Name Type Description Default
center_x float

The center x value.

required
center_y float

The center y value.

required
radius float

The radius value.

required
construction bool

The construction value. Defaults to False.

False

Returns:

Type Description
AdapterResult[str]

AdapterResult[str]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
async def add_sketch_circle(
    self,
    center_x: float,
    center_y: float,
    radius: float,
    construction: bool = False,
) -> AdapterResult[str]:
    """Alias for add_circle used by some tool flows.

    Args:
        center_x (float): The center x value.
        center_y (float): The center y value.
        radius (float): The radius value.
        construction (bool): The construction value. Defaults to False.

    Returns:
        AdapterResult[str]: The result produced by the operation.
    """
    return await self.add_circle(center_x, center_y, radius)
add_sketch_constraint async
add_sketch_constraint(entity1: str, entity2: str | None, relation_type: str, entity3: str | None = None) -> AdapterResult[str]

Apply a geometric constraint between sketch entities.

Parameters:

Name Type Description Default
entity1 str

The entity1 value.

required
entity2 str | None

The entity2 value.

required
relation_type str

The relation type value.

required
entity3 str | None

Third entity ID — only used by the symmetric relation (the centerline of symmetry). All other relation types reject a non-null entity3.

None

Returns:

Type Description
AdapterResult[str]

AdapterResult[str]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
async def add_sketch_constraint(
    self,
    entity1: str,
    entity2: str | None,
    relation_type: str,
    entity3: str | None = None,
) -> AdapterResult[str]:
    """Apply a geometric constraint between sketch entities.

    Args:
        entity1 (str): The entity1 value.
        entity2 (str | None): The entity2 value.
        relation_type (str): The relation type value.
        entity3 (str | None): Third entity ID — only used by the
            ``symmetric`` relation (the centerline of symmetry). All
            other relation types reject a non-null ``entity3``.

    Returns:
        AdapterResult[str]: The result produced by the operation.
    """
    return AdapterResult(
        status=AdapterResultStatus.ERROR,
        error="add_sketch_constraint is not implemented by this adapter",
    )
add_sketch_dimension async
add_sketch_dimension(entity1: str, entity2: str | None, dimension_type: str, value: float) -> AdapterResult[str]

Add a sketch dimension.

Parameters:

Name Type Description Default
entity1 str

The entity1 value.

required
entity2 str | None

The entity2 value.

required
dimension_type str

The dimension type value.

required
value float

The value value.

required

Returns:

Type Description
AdapterResult[str]

AdapterResult[str]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
async def add_sketch_dimension(
    self,
    entity1: str,
    entity2: str | None,
    dimension_type: str,
    value: float,
) -> AdapterResult[str]:
    """Add a sketch dimension.

    Args:
        entity1 (str): The entity1 value.
        entity2 (str | None): The entity2 value.
        dimension_type (str): The dimension type value.
        value (float): The value value.

    Returns:
        AdapterResult[str]: The result produced by the operation.
    """
    return AdapterResult(
        status=AdapterResultStatus.ERROR,
        error="add_sketch_dimension is not implemented by this adapter",
    )
add_spline async
add_spline(points: list[dict[str, float]]) -> AdapterResult[str]

Add a spline through the provided points.

Parameters:

Name Type Description Default
points list[dict[str, float]]

The points value.

required

Returns:

Type Description
AdapterResult[str]

AdapterResult[str]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
async def add_spline(self, points: list[dict[str, float]]) -> AdapterResult[str]:
    """Add a spline through the provided points.

    Args:
        points (list[dict[str, float]]): The points value.

    Returns:
        AdapterResult[str]: The result produced by the operation.
    """
    return AdapterResult(
        status=AdapterResultStatus.ERROR,
        error="add_spline is not implemented by this adapter",
    )
check_sketch_fully_defined async
check_sketch_fully_defined(sketch_name: str | None = None) -> AdapterResult[dict[str, Any]]

Check whether a sketch is fully defined.

Parameters:

Name Type Description Default
sketch_name str | None

Optional sketch name to inspect. Defaults to None.

None

Returns:

Type Description
AdapterResult[dict[str, Any]]

AdapterResult[dict[str, Any]]: Definition status payload.

Source code in src/solidworks_mcp/adapters/base.py
async def check_sketch_fully_defined(
    self, sketch_name: str | None = None
) -> AdapterResult[dict[str, Any]]:
    """Check whether a sketch is fully defined.

    Args:
        sketch_name (str | None): Optional sketch name to inspect. Defaults to None.

    Returns:
        AdapterResult[dict[str, Any]]: Definition status payload.
    """
    return AdapterResult(
        status=AdapterResultStatus.ERROR,
        error="check_sketch_fully_defined is not implemented by this adapter",
    )
close_model abstractmethod async
close_model(save: bool = False) -> AdapterResult[None]

Close the current model.

Parameters:

Name Type Description Default
save bool

The save value. Defaults to False.

False

Returns:

Type Description
AdapterResult[None]

AdapterResult[None]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
@abstractmethod
async def close_model(self, save: bool = False) -> AdapterResult[None]:
    """Close the current model.

    Args:
        save (bool): The save value. Defaults to False.

    Returns:
        AdapterResult[None]: The result produced by the operation.
    """
    pass
connect abstractmethod async
connect() -> None

Connect to SolidWorks application.

Returns:

Name Type Description
None None

None.

Source code in src/solidworks_mcp/adapters/base.py
@abstractmethod
async def connect(self) -> None:
    """Connect to SolidWorks application.

    Returns:
        None: None.
    """
    pass
create_assembly abstractmethod async
create_assembly(name: str | None = None) -> AdapterResult[SolidWorksModel]

Create a new assembly document.

Parameters:

Name Type Description Default
name str | None

The name value. Defaults to None.

None

Returns:

Type Description
AdapterResult[SolidWorksModel]

AdapterResult[SolidWorksModel]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
@abstractmethod
async def create_assembly(
    self, name: str | None = None
) -> AdapterResult[SolidWorksModel]:
    """Create a new assembly document.

    Args:
        name (str | None): The name value. Defaults to None.

    Returns:
        AdapterResult[SolidWorksModel]: The result produced by the operation.
    """
    pass
create_cut async
create_cut(sketch_name: str, depth: float) -> AdapterResult[str]

Create a cut feature from an existing sketch.

Parameters:

Name Type Description Default
sketch_name str

The sketch name value.

required
depth float

The depth value.

required

Returns:

Type Description
AdapterResult[str]

AdapterResult[str]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
async def create_cut(self, sketch_name: str, depth: float) -> AdapterResult[str]:
    """Create a cut feature from an existing sketch.

    Args:
        sketch_name (str): The sketch name value.
        depth (float): The depth value.

    Returns:
        AdapterResult[str]: The result produced by the operation.
    """
    return AdapterResult(
        status=AdapterResultStatus.ERROR,
        error="create_cut is not implemented by this adapter",
    )
create_cut_extrude async
create_cut_extrude(params: 'ExtrusionParameters') -> 'AdapterResult[Any]'

Create a cut-extrude feature from the active sketch.

Cuts material from the current solid body using the active sketch profile. Equivalent to SolidWorks Insert > Cut > Extrude.

Parameters:

Name Type Description Default
params ExtrusionParameters

Depth and direction parameters.

required

Returns:

Name Type Description
AdapterResult 'AdapterResult[Any]'

Feature result or error.

Source code in src/solidworks_mcp/adapters/base.py
async def create_cut_extrude(
    self, params: "ExtrusionParameters"
) -> "AdapterResult[Any]":
    """Create a cut-extrude feature from the active sketch.

    Cuts material from the current solid body using the active sketch profile.
    Equivalent to SolidWorks Insert > Cut > Extrude.

    Args:
        params (ExtrusionParameters): Depth and direction parameters.

    Returns:
        AdapterResult: Feature result or error.
    """
    return AdapterResult(
        status=AdapterResultStatus.ERROR,
        error="create_cut_extrude is not implemented by this adapter",
    )
create_drawing abstractmethod async
create_drawing(name: str | None = None) -> AdapterResult[SolidWorksModel]

Create a new drawing document.

Parameters:

Name Type Description Default
name str | None

The name value. Defaults to None.

None

Returns:

Type Description
AdapterResult[SolidWorksModel]

AdapterResult[SolidWorksModel]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
@abstractmethod
async def create_drawing(
    self, name: str | None = None
) -> AdapterResult[SolidWorksModel]:
    """Create a new drawing document.

    Args:
        name (str | None): The name value. Defaults to None.

    Returns:
        AdapterResult[SolidWorksModel]: The result produced by the operation.
    """
    pass
create_extrusion abstractmethod async
create_extrusion(params: ExtrusionParameters) -> AdapterResult[SolidWorksFeature]

Create an extrusion feature.

Parameters:

Name Type Description Default
params ExtrusionParameters

The params value.

required

Returns:

Type Description
AdapterResult[SolidWorksFeature]

AdapterResult[SolidWorksFeature]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
@abstractmethod
async def create_extrusion(
    self, params: ExtrusionParameters
) -> AdapterResult[SolidWorksFeature]:
    """Create an extrusion feature.

    Args:
        params (ExtrusionParameters): The params value.

    Returns:
        AdapterResult[SolidWorksFeature]: The result produced by the operation.
    """
    pass
create_loft abstractmethod async
create_loft(params: LoftParameters) -> AdapterResult[SolidWorksFeature]

Create a loft feature.

Parameters:

Name Type Description Default
params LoftParameters

The params value.

required

Returns:

Type Description
AdapterResult[SolidWorksFeature]

AdapterResult[SolidWorksFeature]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
@abstractmethod
async def create_loft(
    self, params: LoftParameters
) -> AdapterResult[SolidWorksFeature]:
    """Create a loft feature.

    Args:
        params (LoftParameters): The params value.

    Returns:
        AdapterResult[SolidWorksFeature]: The result produced by the operation.
    """
    pass
create_part abstractmethod async
create_part(name: str | None = None, units: str | None = None) -> AdapterResult[SolidWorksModel]

Create a new part document.

Parameters:

Name Type Description Default
name str | None

The name value. Defaults to None.

None
units str | None

The units value. Defaults to None.

None

Returns:

Type Description
AdapterResult[SolidWorksModel]

AdapterResult[SolidWorksModel]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
@abstractmethod
async def create_part(
    self, name: str | None = None, units: str | None = None
) -> AdapterResult[SolidWorksModel]:
    """Create a new part document.

    Args:
        name (str | None): The name value. Defaults to None.
        units (str | None): The units value. Defaults to None.

    Returns:
        AdapterResult[SolidWorksModel]: The result produced by the operation.
    """
    pass
create_revolve abstractmethod async
create_revolve(params: RevolveParameters) -> AdapterResult[SolidWorksFeature]

Create a revolve feature.

Parameters:

Name Type Description Default
params RevolveParameters

The params value.

required

Returns:

Type Description
AdapterResult[SolidWorksFeature]

AdapterResult[SolidWorksFeature]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
@abstractmethod
async def create_revolve(
    self, params: RevolveParameters
) -> AdapterResult[SolidWorksFeature]:
    """Create a revolve feature.

    Args:
        params (RevolveParameters): The params value.

    Returns:
        AdapterResult[SolidWorksFeature]: The result produced by the operation.
    """
    pass
create_sketch abstractmethod async
create_sketch(plane: str) -> AdapterResult[str]

Create a new sketch on the specified plane.

Parameters:

Name Type Description Default
plane str

The plane value.

required

Returns:

Type Description
AdapterResult[str]

AdapterResult[str]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
@abstractmethod
async def create_sketch(self, plane: str) -> AdapterResult[str]:
    """Create a new sketch on the specified plane.

    Args:
        plane (str): The plane value.

    Returns:
        AdapterResult[str]: The result produced by the operation.
    """
    pass
create_sweep abstractmethod async
create_sweep(params: SweepParameters) -> AdapterResult[SolidWorksFeature]

Create a sweep feature.

Parameters:

Name Type Description Default
params SweepParameters

The params value.

required

Returns:

Type Description
AdapterResult[SolidWorksFeature]

AdapterResult[SolidWorksFeature]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
@abstractmethod
async def create_sweep(
    self, params: SweepParameters
) -> AdapterResult[SolidWorksFeature]:
    """Create a sweep feature.

    Args:
        params (SweepParameters): The params value.

    Returns:
        AdapterResult[SolidWorksFeature]: The result produced by the operation.
    """
    pass
disconnect abstractmethod async
disconnect() -> None

Disconnect from SolidWorks application.

Returns:

Name Type Description
None None

None.

Source code in src/solidworks_mcp/adapters/base.py
@abstractmethod
async def disconnect(self) -> None:
    """Disconnect from SolidWorks application.

    Returns:
        None: None.
    """
    pass
exit_sketch abstractmethod async
exit_sketch() -> AdapterResult[None]

Exit sketch editing mode.

Returns:

Type Description
AdapterResult[None]

AdapterResult[None]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
@abstractmethod
async def exit_sketch(self) -> AdapterResult[None]:
    """Exit sketch editing mode.

    Returns:
        AdapterResult[None]: The result produced by the operation.
    """
    pass
export_file abstractmethod async
export_file(file_path: str, format_type: str) -> AdapterResult[None]

Export the current model to a file.

Parameters:

Name Type Description Default
file_path str

Path to the target file.

required
format_type str

The format type value.

required

Returns:

Type Description
AdapterResult[None]

AdapterResult[None]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
@abstractmethod
async def export_file(
    self, file_path: str, format_type: str
) -> AdapterResult[None]:
    """Export the current model to a file.

    Args:
        file_path (str): Path to the target file.
        format_type (str): The format type value.

    Returns:
        AdapterResult[None]: The result produced by the operation.
    """
    pass
export_image abstractmethod async
export_image(payload: dict) -> AdapterResult[dict]

Export a viewport screenshot (PNG/JPG) of the current model.

Payload keys: file_path (str): Absolute output path. width (int): Image width in pixels. height (int): Image height in pixels. view_orientation (str): One of "isometric", "front", "top", "right", "back", "bottom", "current".

Parameters:

Name Type Description Default
payload dict

The payload value.

required

Returns:

Type Description
AdapterResult[dict]

AdapterResult[dict]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
@abstractmethod
async def export_image(self, payload: dict) -> AdapterResult[dict]:
    """Export a viewport screenshot (PNG/JPG) of the current model.

    Payload keys: file_path (str): Absolute output path. width (int): Image width in pixels.
    height (int): Image height in pixels. view_orientation (str): One of "isometric",
    "front", "top", "right", "back", "bottom", "current".

    Args:
        payload (dict): The payload value.

    Returns:
        AdapterResult[dict]: The result produced by the operation.
    """
    pass
get_dimension abstractmethod async
get_dimension(name: str) -> AdapterResult[float]

Get the value of a dimension.

Parameters:

Name Type Description Default
name str

The name value.

required

Returns:

Type Description
AdapterResult[float]

AdapterResult[float]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
@abstractmethod
async def get_dimension(self, name: str) -> AdapterResult[float]:
    """Get the value of a dimension.

    Args:
        name (str): The name value.

    Returns:
        AdapterResult[float]: The result produced by the operation.
    """
    pass
get_mass_properties abstractmethod async
get_mass_properties() -> AdapterResult[MassProperties]

Get mass properties of the current model.

Returns:

Type Description
AdapterResult[MassProperties]

AdapterResult[MassProperties]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
@abstractmethod
async def get_mass_properties(self) -> AdapterResult[MassProperties]:
    """Get mass properties of the current model.

    Returns:
        AdapterResult[MassProperties]: The result produced by the operation.
    """
    pass
get_metrics
get_metrics() -> dict[str, Any]

Get adapter metrics.

Returns:

Type Description
dict[str, Any]

dict[str, Any]: A dictionary containing the resulting values.

Source code in src/solidworks_mcp/adapters/base.py
def get_metrics(self) -> dict[str, Any]:
    """Get adapter metrics.

    Returns:
        dict[str, Any]: A dictionary containing the resulting values.
    """
    return self._metrics.copy()
get_model_info abstractmethod async
get_model_info() -> AdapterResult[dict[str, Any]]

Get metadata for the active model.

Returns:

Type Description
AdapterResult[dict[str, Any]]

AdapterResult[dict[str, Any]]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
@abstractmethod
async def get_model_info(self) -> AdapterResult[dict[str, Any]]:
    """Get metadata for the active model.

    Returns:
        AdapterResult[dict[str, Any]]: The result produced by the operation.
    """
    pass
health_check abstractmethod async
health_check() -> AdapterHealth

Get adapter health status.

Returns:

Name Type Description
AdapterHealth AdapterHealth

The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
@abstractmethod
async def health_check(self) -> AdapterHealth:
    """Get adapter health status.

    Returns:
        AdapterHealth: The result produced by the operation.
    """
    pass
is_connected abstractmethod
is_connected() -> bool

Check if connected to SolidWorks.

Returns:

Name Type Description
bool bool

True if connected, otherwise False.

Source code in src/solidworks_mcp/adapters/base.py
@abstractmethod
def is_connected(self) -> bool:
    """Check if connected to SolidWorks.

    Returns:
        bool: True if connected, otherwise False.
    """
    pass
list_configurations abstractmethod async
list_configurations() -> AdapterResult[list[str]]

List configuration names for the active model.

Returns:

Type Description
AdapterResult[list[str]]

AdapterResult[list[str]]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
@abstractmethod
async def list_configurations(self) -> AdapterResult[list[str]]:
    """List configuration names for the active model.

    Returns:
        AdapterResult[list[str]]: The result produced by the operation.
    """
    pass
list_features abstractmethod async
list_features(include_suppressed: bool = False) -> AdapterResult[list[dict[str, Any]]]

List model features from the feature tree.

Parameters:

Name Type Description Default
include_suppressed bool

The include suppressed value. Defaults to False.

False

Returns:

Type Description
AdapterResult[list[dict[str, Any]]]

AdapterResult[list[dict[str, Any]]]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
@abstractmethod
async def list_features(
    self, include_suppressed: bool = False
) -> AdapterResult[list[dict[str, Any]]]:
    """List model features from the feature tree.

    Args:
        include_suppressed (bool): The include suppressed value. Defaults to False.

    Returns:
        AdapterResult[list[dict[str, Any]]]: The result produced by the operation.
    """
    pass
open_model abstractmethod async
open_model(file_path: str) -> AdapterResult[SolidWorksModel]

Open a SolidWorks model (part, assembly, or drawing).

Parameters:

Name Type Description Default
file_path str

Path to the target file.

required

Returns:

Type Description
AdapterResult[SolidWorksModel]

AdapterResult[SolidWorksModel]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
@abstractmethod
async def open_model(self, file_path: str) -> AdapterResult[SolidWorksModel]:
    """Open a SolidWorks model (part, assembly, or drawing).

    Args:
        file_path (str): Path to the target file.

    Returns:
        AdapterResult[SolidWorksModel]: The result produced by the operation.
    """
    pass
save_file async
save_file(file_path: str | None = None) -> AdapterResult[Any]

Save the active model to the existing path or the provided path.

Parameters:

Name Type Description Default
file_path str | None

Path to the target file. Defaults to None.

None

Returns:

Type Description
AdapterResult[Any]

AdapterResult[Any]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
async def save_file(self, file_path: str | None = None) -> AdapterResult[Any]:
    """Save the active model to the existing path or the provided path.

    Args:
        file_path (str | None): Path to the target file. Defaults to None.

    Returns:
        AdapterResult[Any]: The result produced by the operation.
    """
    return AdapterResult(
        status=AdapterResultStatus.ERROR,
        error="save_file is not implemented by this adapter",
    )
set_dimension abstractmethod async
set_dimension(name: str, value: float) -> AdapterResult[None]

Set the value of a dimension.

Parameters:

Name Type Description Default
name str

The name value.

required
value float

The value value.

required

Returns:

Type Description
AdapterResult[None]

AdapterResult[None]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
@abstractmethod
async def set_dimension(self, name: str, value: float) -> AdapterResult[None]:
    """Set the value of a dimension.

    Args:
        name (str): The name value.
        value (float): The value value.

    Returns:
        AdapterResult[None]: The result produced by the operation.
    """
    pass
sketch_circular_pattern async
sketch_circular_pattern(entities: list[str], angle: float, count: int) -> AdapterResult[str]

Create a circular pattern of sketch entities around the sketch origin.

The rotation axis is always the sketch origin — SW's CreateCircularSketchStepAndRepeat has no pattern-centre parameter and derives the axis from the seed's geometry. Place the seed entity at the desired radius from the origin.

Parameters:

Name Type Description Default
entities list[str]

The entities value.

required
angle float

The angle value.

required
count int

The count value.

required

Returns:

Type Description
AdapterResult[str]

AdapterResult[str]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
async def sketch_circular_pattern(
    self,
    entities: list[str],
    angle: float,
    count: int,
) -> AdapterResult[str]:
    """Create a circular pattern of sketch entities around the sketch origin.

    The rotation axis is always the sketch origin — SW's
    ``CreateCircularSketchStepAndRepeat`` has no pattern-centre
    parameter and derives the axis from the seed's geometry. Place
    the seed entity at the desired radius from the origin.

    Args:
        entities (list[str]): The entities value.
        angle (float): The angle value.
        count (int): The count value.

    Returns:
        AdapterResult[str]: The result produced by the operation.
    """
    return AdapterResult(
        status=AdapterResultStatus.ERROR,
        error="sketch_circular_pattern is not implemented by this adapter",
    )
sketch_linear_pattern async
sketch_linear_pattern(entities: list[str], direction_x: float, direction_y: float, spacing: float, count: int) -> AdapterResult[str]

Create a linear pattern of sketch entities.

Parameters:

Name Type Description Default
entities list[str]

The entities value.

required
direction_x float

The direction x value.

required
direction_y float

The direction y value.

required
spacing float

The spacing value.

required
count int

The count value.

required

Returns:

Type Description
AdapterResult[str]

AdapterResult[str]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
async def sketch_linear_pattern(
    self,
    entities: list[str],
    direction_x: float,
    direction_y: float,
    spacing: float,
    count: int,
) -> AdapterResult[str]:
    """Create a linear pattern of sketch entities.

    Args:
        entities (list[str]): The entities value.
        direction_x (float): The direction x value.
        direction_y (float): The direction y value.
        spacing (float): The spacing value.
        count (int): The count value.

    Returns:
        AdapterResult[str]: The result produced by the operation.
    """
    return AdapterResult(
        status=AdapterResultStatus.ERROR,
        error="sketch_linear_pattern is not implemented by this adapter",
    )
sketch_mirror async
sketch_mirror(entities: list[str], mirror_line: str) -> AdapterResult[str]

Mirror sketch entities about a mirror line.

Parameters:

Name Type Description Default
entities list[str]

The entities value.

required
mirror_line str

The mirror line value.

required

Returns:

Type Description
AdapterResult[str]

AdapterResult[str]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
async def sketch_mirror(
    self, entities: list[str], mirror_line: str
) -> AdapterResult[str]:
    """Mirror sketch entities about a mirror line.

    Args:
        entities (list[str]): The entities value.
        mirror_line (str): The mirror line value.

    Returns:
        AdapterResult[str]: The result produced by the operation.
    """
    return AdapterResult(
        status=AdapterResultStatus.ERROR,
        error="sketch_mirror is not implemented by this adapter",
    )
sketch_offset async
sketch_offset(entities: list[str], offset_distance: float, reverse_direction: bool) -> AdapterResult[str]

Offset sketch entities.

Parameters:

Name Type Description Default
entities list[str]

The entities value.

required
offset_distance float

The offset distance value.

required
reverse_direction bool

The reverse direction value.

required

Returns:

Type Description
AdapterResult[str]

AdapterResult[str]: The result produced by the operation.

Source code in src/solidworks_mcp/adapters/base.py
async def sketch_offset(
    self,
    entities: list[str],
    offset_distance: float,
    reverse_direction: bool,
) -> AdapterResult[str]:
    """Offset sketch entities.

    Args:
        entities (list[str]): The entities value.
        offset_distance (float): The offset distance value.
        reverse_direction (bool): The reverse direction value.

    Returns:
        AdapterResult[str]: The result produced by the operation.
    """
    return AdapterResult(
        status=AdapterResultStatus.ERROR,
        error="sketch_offset is not implemented by this adapter",
    )
update_metrics
update_metrics(operation_time: float, success: bool) -> None

Update adapter metrics.

Parameters:

Name Type Description Default
operation_time float

The operation time value.

required
success bool

The success value.

required

Returns:

Name Type Description
None None

None.

Source code in src/solidworks_mcp/adapters/base.py
def update_metrics(self, operation_time: float, success: bool) -> None:
    """Update adapter metrics.

    Args:
        operation_time (float): The operation time value.
        success (bool): The success value.

    Returns:
        None: None.
    """
    self._metrics["operations_count"] += 1
    if not success:
        self._metrics["errors_count"] += 1

    # Update average response time
    current_avg = self._metrics["average_response_time"]
    count = self._metrics["operations_count"]
    self._metrics["average_response_time"] = (
        current_avg * (count - 1) + operation_time
    ) / count

SolidWorksFeaturesMixin

Expose SolidWorks feature methods via mixin-local implementation helpers.

SolidWorksIOMixin

Expose model open/save/create/configuration methods through a mixin.

Functions
close_model async
close_model(save: bool = False) -> AdapterResult[None]

Close the current SolidWorks model and optionally save first.

Parameters:

Name Type Description Default
save bool

When True, calls Save before closing.

False

Returns:

Type Description
AdapterResult[None]

AdapterResult[None]: Result of the close operation.

Source code in src/solidworks_mcp/adapters/solidworks/io.py
async def close_model(self, save: bool = False) -> AdapterResult[None]:
    """Close the current SolidWorks model and optionally save first.

    Args:
        save: When ``True``, calls ``Save`` before closing.

    Returns:
        AdapterResult[None]: Result of the close operation.
    """
    adapter = self._adapter(self)
    if not adapter.currentModel:
        return AdapterResult(
            status=AdapterResultStatus.WARNING, error="No active model to close"
        )
    model = adapter.currentModel
    app = adapter.swApp
    if model is None or app is None:
        return AdapterResult(
            status=AdapterResultStatus.ERROR,
            error="SolidWorks application is not connected",
        )

    def _close() -> None:
        """Close the model document."""
        if save:
            model.Save()
        app.CloseDoc(model.GetTitle())
        adapter.currentModel = None

    return cast(
        AdapterResult[None],
        adapter._handle_com_operation("close_model", _close),
    )
create_assembly async
create_assembly(name: str | None = None) -> AdapterResult[SolidWorksModel]

Create a new assembly document and set it as active.

Parameters:

Name Type Description Default
name str | None

Reserved for future naming policy.

None

Returns:

Type Description
AdapterResult[SolidWorksModel]

AdapterResult[SolidWorksModel]: Metadata for the new assembly document.

Source code in src/solidworks_mcp/adapters/solidworks/io.py
async def create_assembly(
    self, name: str | None = None
) -> AdapterResult[SolidWorksModel]:
    """Create a new assembly document and set it as active.

    Args:
        name: Reserved for future naming policy.

    Returns:
        AdapterResult[SolidWorksModel]: Metadata for the new assembly document.
    """
    adapter = self._adapter(self)
    if not adapter.is_connected():
        return AdapterResult(
            status=AdapterResultStatus.ERROR, error="Not connected to SolidWorks"
        )

    def _create() -> SolidWorksModel:
        """Create a new assembly."""
        _ = name
        model = None
        app = adapter.swApp
        if app is None:
            raise Exception("SolidWorks application is not connected")

        new_assembly = getattr(app, "NewAssembly", None)
        if callable(new_assembly):
            model = adapter._attempt(new_assembly)

        if not model:
            asm_template = self._resolve_template_path([9, 2, 3, 1, 0], ".asmdot")
            if not asm_template:
                raise Exception("No assembly template configured in SolidWorks")
            model = app.NewDocument(asm_template, 0, 0, 0)

        if not model:
            raise Exception("Failed to create new assembly")

        adapter._attempt(lambda: _sw_type_info.flag_doc(model, 2), default=0)
        adapter.currentModel = model
        title = self._read_model_title(model)
        return SolidWorksModel(
            path="",
            name=title,
            type="Assembly",
            is_active=True,
            configuration="Default",
            properties={"created": datetime.now().isoformat()},
        )

    return cast(
        AdapterResult[SolidWorksModel],
        adapter._handle_com_operation("create_assembly", _create),
    )
create_drawing async
create_drawing(name: str | None = None) -> AdapterResult[SolidWorksModel]

Create a new drawing document and set it as active.

Parameters:

Name Type Description Default
name str | None

Reserved for future naming policy.

None

Returns:

Type Description
AdapterResult[SolidWorksModel]

AdapterResult[SolidWorksModel]: Metadata for the new drawing document.

Source code in src/solidworks_mcp/adapters/solidworks/io.py
async def create_drawing(
    self, name: str | None = None
) -> AdapterResult[SolidWorksModel]:
    """Create a new drawing document and set it as active.

    Args:
        name: Reserved for future naming policy.

    Returns:
        AdapterResult[SolidWorksModel]: Metadata for the new drawing document.
    """
    adapter = self._adapter(self)
    if not adapter.is_connected():
        return AdapterResult(
            status=AdapterResultStatus.ERROR, error="Not connected to SolidWorks"
        )

    def _create() -> SolidWorksModel:
        """Create a new drawing."""
        _ = name
        app = adapter.swApp
        if app is None:
            raise Exception("SolidWorks application is not connected")

        drw_template = app.GetUserPreferenceStringValue(1)
        if not drw_template:
            drw_template = app.GetUserPreferenceStringValue(0).replace(
                "Part", "Drawing"
            )

        model = app.NewDocument(drw_template, 12, 0.2794, 0.2159)
        if not model:
            raise Exception("Failed to create new drawing")

        adapter._attempt(lambda: _sw_type_info.flag_doc(model, 3), default=0)
        adapter.currentModel = model
        title = self._read_model_title(model)
        return SolidWorksModel(
            path="",
            name=title,
            type="Drawing",
            is_active=True,
            configuration="Default",
            properties={"created": datetime.now().isoformat()},
        )

    return cast(
        AdapterResult[SolidWorksModel],
        adapter._handle_com_operation("create_drawing", _create),
    )
create_part async
create_part(name: str | None = None, units: str | None = None) -> AdapterResult[SolidWorksModel]

Create a new part document and set it as active.

Parameters:

Name Type Description Default
name str | None

Reserved for future naming policy.

None
units str | None

Reserved for future units policy.

None

Returns:

Type Description
AdapterResult[SolidWorksModel]

AdapterResult[SolidWorksModel]: Metadata for the new part document.

Source code in src/solidworks_mcp/adapters/solidworks/io.py
async def create_part(
    self, name: str | None = None, units: str | None = None
) -> AdapterResult[SolidWorksModel]:
    """Create a new part document and set it as active.

    Args:
        name: Reserved for future naming policy.
        units: Reserved for future units policy.

    Returns:
        AdapterResult[SolidWorksModel]: Metadata for the new part document.
    """
    adapter = self._adapter(self)
    if not adapter.is_connected():
        return AdapterResult(
            status=AdapterResultStatus.ERROR, error="Not connected to SolidWorks"
        )

    def _create() -> SolidWorksModel:
        """Create a new part."""
        _ = name, units
        model = None
        app = adapter.swApp
        if app is None:
            raise Exception("SolidWorks application is not connected")

        new_part = getattr(app, "NewPart", None)
        if callable(new_part):
            model = adapter._attempt(new_part)

        if not model:
            part_template = self._resolve_template_path([8, 0, 1, 2, 3], ".prtdot")
            if not part_template:
                raise Exception("No part template configured in SolidWorks")
            model = app.NewDocument(part_template, 0, 0, 0)

        if not model:
            raise Exception("Failed to create new part")

        adapter._attempt(lambda: _sw_type_info.flag_doc(model, 1), default=0)
        adapter.currentModel = model
        title = self._read_model_title(model)
        return SolidWorksModel(
            path="",
            name=title,
            type="Part",
            is_active=True,
            configuration="Default",
            properties={"created": datetime.now().isoformat()},
        )

    return cast(
        AdapterResult[SolidWorksModel],
        adapter._handle_com_operation("create_part", _create),
    )
get_dimension async
get_dimension(name: str) -> AdapterResult[float]

Read a named model dimension in millimetres.

Parameters:

Name Type Description Default
name str

Fully-qualified dimension name.

required

Returns:

Type Description
AdapterResult[float]

AdapterResult[float]: Dimension value in millimetres.

Source code in src/solidworks_mcp/adapters/solidworks/io.py
async def get_dimension(self, name: str) -> AdapterResult[float]:
    """Read a named model dimension in millimetres.

    Args:
        name: Fully-qualified dimension name.

    Returns:
        AdapterResult[float]: Dimension value in millimetres.
    """
    adapter = self._adapter(self)
    if not adapter.currentModel:
        return AdapterResult(
            status=AdapterResultStatus.ERROR, error="No active model"
        )

    def _get() -> float:
        """Get the dimension value."""
        dimension = adapter.currentModel.Parameter(name)
        if not dimension:
            raise Exception(f"Dimension '{name}' not found")
        value = dimension.GetValue3(8, None)
        return cast(float, value * 1000)

    return cast(
        AdapterResult[float],
        adapter._handle_com_operation("get_dimension", _get),
    )
get_mass_properties async
get_mass_properties() -> AdapterResult[MassProperties]

Get mass properties for the active model.

Returns:

Type Description
AdapterResult[MassProperties]

AdapterResult[MassProperties]: Computed mass, volume, area, COM, and inertia.

Source code in src/solidworks_mcp/adapters/solidworks/io.py
async def get_mass_properties(self) -> AdapterResult[MassProperties]:
    """Get mass properties for the active model.

    Returns:
        AdapterResult[MassProperties]: Computed mass, volume, area, COM, and inertia.
    """
    adapter = self._adapter(self)
    if not adapter.currentModel:
        return AdapterResult(
            status=AdapterResultStatus.ERROR, error="No active model"
        )

    def _get() -> MassProperties:
        """Get mass properties."""
        adapter._attempt(
            lambda: adapter.currentModel.ForceRebuild3(False), default=None
        )
        mass_props = adapter._attempt(
            lambda: adapter.currentModel.Extension.CreateMassProperty(),
            default=None,
        )

        if mass_props:
            volume = mass_props.Volume * 1e9
            surface_area = mass_props.SurfaceArea * 1e6
            mass = mass_props.Mass

            center_of_mass = [0.0, 0.0, 0.0]
            com = adapter._attempt(lambda: mass_props.CenterOfMass, default=None)
            if isinstance(com, (list, tuple)) and len(com) >= 3:
                center_of_mass = [com[0] * 1000, com[1] * 1000, com[2] * 1000]

            moi = adapter._attempt(
                lambda: mass_props.GetMomentOfInertia(0), default=None
            )
            if not isinstance(moi, (list, tuple)) or len(moi) < 9:
                moi = [0.0] * 9
        else:
            raw = adapter._attempt(
                lambda: adapter.currentModel.GetMassProperties, default=None
            )
            if not isinstance(raw, (list, tuple)) or len(raw) < 6:
                raise Exception("Failed to get mass properties")

            center_of_mass = [
                raw[0] * 1000.0,
                raw[1] * 1000.0,
                raw[2] * 1000.0,
            ]
            volume = raw[3] * 1e9
            surface_area = raw[4] * 1e6
            mass = raw[5]

            moi = [0.0] * 9
            if len(raw) >= 12:
                moi[0] = raw[6]
                moi[4] = raw[7]
                moi[8] = raw[8]
                moi[1] = raw[9]
                moi[5] = raw[10]
                moi[2] = raw[11]

        return MassProperties(
            volume=volume,
            surface_area=surface_area,
            mass=mass,
            center_of_mass=center_of_mass,
            moments_of_inertia={
                "Ixx": moi[0],
                "Iyy": moi[4],
                "Izz": moi[8],
                "Ixy": moi[1],
                "Ixz": moi[2],
                "Iyz": moi[5],
            },
        )

    return cast(
        AdapterResult[MassProperties],
        adapter._handle_com_operation("get_mass_properties", _get),
    )
get_model_info async
get_model_info() -> AdapterResult[dict[str, Any]]

Collect summary metadata about the active model.

Returns:

Type Description
AdapterResult[dict[str, Any]]

AdapterResult[dict[str, Any]]: Model information payload.

Source code in src/solidworks_mcp/adapters/solidworks/io.py
async def get_model_info(self) -> AdapterResult[dict[str, Any]]:
    """Collect summary metadata about the active model.

    Returns:
        AdapterResult[dict[str, Any]]: Model information payload.
    """
    adapter = self._adapter(self)
    if not adapter.currentModel:
        return AdapterResult(
            status=AdapterResultStatus.ERROR, error="No active model"
        )

    def _get_info() -> dict[str, Any]:
        """Get model information."""
        active_config = adapter.currentModel.GetActiveConfiguration()
        return {
            "title": adapter.currentModel.GetTitle(),
            "path": adapter.currentModel.GetPathName(),
            "type": adapter._get_document_type(),
            "configuration": active_config.GetName()
            if active_config
            else "Default",
            "is_dirty": adapter.currentModel.GetSaveFlag(),
            "feature_count": adapter.currentModel.FeatureManager.GetFeatureCount(
                True
            ),
            "rebuild_status": adapter.currentModel.GetRebuildStatus(),
        }

    return cast(
        AdapterResult[dict[str, Any]],
        adapter._handle_com_operation("get_model_info", _get_info),
    )
list_configurations async
list_configurations() -> AdapterResult[list[str]]

List all configuration names on the active model.

Returns:

Type Description
AdapterResult[list[str]]

AdapterResult[list[str]]: Configuration names, or empty list when unavailable.

Source code in src/solidworks_mcp/adapters/solidworks/io.py
async def list_configurations(self) -> AdapterResult[list[str]]:
    """List all configuration names on the active model.

    Returns:
        AdapterResult[list[str]]: Configuration names, or empty list when unavailable.
    """
    adapter = self._adapter(self)
    if not adapter.currentModel:
        return AdapterResult(
            status=AdapterResultStatus.ERROR,
            error="No active model",
        )

    def _list() -> list[str]:
        """List configurations."""
        raw_names = getattr(adapter.currentModel, "GetConfigurationNames", None)
        names = raw_names() if callable(raw_names) else raw_names
        if names is None:
            names = []
        if isinstance(names, str):
            return [names]

        normalized_names = [str(name) for name in names]
        if normalized_names:
            return normalized_names

        active_config = adapter._attempt(
            lambda: adapter.currentModel.GetActiveConfiguration(), default=None
        )
        active_name = adapter._attempt(
            lambda: active_config.GetName(), default=None
        )
        if active_name:
            return [str(active_name)]
        return []

    return cast(
        AdapterResult[list[str]],
        adapter._handle_com_operation("list_configurations", _list),
    )
open_model async
open_model(file_path: str) -> AdapterResult[SolidWorksModel]

Open a SolidWorks model file and set it as active on the adapter.

Parameters:

Name Type Description Default
file_path str

Path to a .sldprt, .sldasm, or .slddrw file.

required

Returns:

Type Description
AdapterResult[SolidWorksModel]

AdapterResult[SolidWorksModel]: Model metadata for the opened document.

Source code in src/solidworks_mcp/adapters/solidworks/io.py
async def open_model(self, file_path: str) -> AdapterResult[SolidWorksModel]:
    """Open a SolidWorks model file and set it as active on the adapter.

    Args:
        file_path: Path to a ``.sldprt``, ``.sldasm``, or ``.slddrw`` file.

    Returns:
        AdapterResult[SolidWorksModel]: Model metadata for the opened document.
    """
    adapter = self._adapter(self)
    if not adapter.is_connected():
        return AdapterResult(
            status=AdapterResultStatus.ERROR, error="Not connected to SolidWorks"
        )

    def _open() -> SolidWorksModel:
        """Open the model document."""
        resolved_path = os.path.abspath(file_path)
        file_path_lower = resolved_path.lower()
        if file_path_lower.endswith(".sldprt"):
            doc_type = adapter.constants["swDocPART"]
            model_type = "Part"
        elif file_path_lower.endswith(".sldasm"):
            doc_type = adapter.constants["swDocASSEMBLY"]
            model_type = "Assembly"
        elif file_path_lower.endswith(".slddrw"):
            doc_type = adapter.constants["swDocDRAWING"]
            model_type = "Drawing"
        else:
            raise ValueError(f"Unsupported file type: {resolved_path}")

        app = adapter.swApp
        variant_ctor = getattr(getattr(win32com, "client", None), "VARIANT", None)
        vt_byref = int(getattr(pythoncom, "VT_BYREF", 0))
        vt_i4 = int(getattr(pythoncom, "VT_I4", 0))
        if callable(variant_ctor):
            errors = variant_ctor(vt_byref | vt_i4, 0)
            warnings = variant_ctor(vt_byref | vt_i4, 0)
        else:
            errors = 0
            warnings = 0
        model = app.OpenDoc6(resolved_path, doc_type, 1, "", errors, warnings)
        if not model:
            raise Exception(f"Failed to open model: {resolved_path}")

        adapter._attempt(
            lambda: _sw_type_info.flag_doc(model, int(doc_type)), default=0
        )

        adapter.currentModel = model
        title = self._read_model_title(model)
        active_config = adapter._attempt(lambda: model.GetActiveConfiguration())
        config = (
            adapter._attempt(lambda: active_config.GetName(), default="Default")
            if active_config
            else "Default"
        )

        return SolidWorksModel(
            path=resolved_path,
            name=title,
            type=model_type,
            is_active=True,
            configuration=config,
            properties={
                "last_modified": (
                    model.GetSaveTime()
                    if callable(getattr(model, "GetSaveTime", None))
                    else None
                ),
            },
        )

    return cast(
        AdapterResult[SolidWorksModel],
        adapter._handle_com_operation("open_model", _open),
    )
rebuild_model async
rebuild_model() -> AdapterResult[None]

Force a model rebuild.

Returns:

Type Description
AdapterResult[None]

AdapterResult[None]: Result of the rebuild operation.

Source code in src/solidworks_mcp/adapters/solidworks/io.py
async def rebuild_model(self) -> AdapterResult[None]:
    """Force a model rebuild.

    Returns:
        AdapterResult[None]: Result of the rebuild operation.
    """
    adapter = self._adapter(self)
    if not adapter.currentModel:
        return AdapterResult(
            status=AdapterResultStatus.ERROR, error="No active model"
        )

    def _rebuild() -> None:
        """Rebuild the model."""
        success = adapter.currentModel.ForceRebuild3(False)
        if not success:
            raise Exception("Failed to rebuild model")

    return cast(
        AdapterResult[None],
        adapter._handle_com_operation("rebuild_model", _rebuild),
    )
save_file async
save_file(file_path: str | None = None) -> AdapterResult[None]

Save the active model to its current path or to a new file path.

Parameters:

Name Type Description Default
file_path str | None

Optional target path for Save As.

None

Returns:

Type Description
AdapterResult[None]

AdapterResult[None]: Result of the save operation.

Source code in src/solidworks_mcp/adapters/solidworks/io.py
async def save_file(self, file_path: str | None = None) -> AdapterResult[None]:
    """Save the active model to its current path or to a new file path.

    Args:
        file_path: Optional target path for Save As.

    Returns:
        AdapterResult[None]: Result of the save operation.
    """
    adapter = self._adapter(self)
    if not adapter.currentModel:
        return AdapterResult(
            status=AdapterResultStatus.ERROR, error="No active model"
        )

    def _save() -> None:
        """Save the model."""
        if file_path:
            resolved_path = os.path.abspath(file_path)
            os.makedirs(os.path.dirname(resolved_path), exist_ok=True)

            if adapter.swApp:
                adapter._attempt(lambda: adapter.swApp.CloseDoc(resolved_path))

            if os.path.exists(resolved_path):
                adapter._attempt(lambda: os.remove(resolved_path))

            save_as3_result = adapter.currentModel.SaveAs3(resolved_path, 0, 0)
            if not self._is_success(save_as3_result):
                save_as = getattr(adapter.currentModel, "SaveAs", None)
                if callable(save_as):
                    fallback_result = save_as(resolved_path)
                    if not self._is_success(fallback_result):
                        raise Exception(f"Failed to save as: {resolved_path}")
                else:
                    raise Exception(f"Failed to save as: {resolved_path}")

            if not os.path.exists(resolved_path):
                raise Exception(f"File not written after save: {resolved_path}")
            return

        save_result = adapter._attempt(
            lambda: adapter.currentModel.Save3(1, None, None)
        )
        if save_result is None:
            save_fn = getattr(adapter.currentModel, "Save", None)
            if callable(save_fn):
                save_result = save_fn()
            else:
                raise Exception("Failed to save file")

        if self._is_success(save_result):
            return

        path_attr = getattr(adapter.currentModel, "GetPathName", "")
        model_path = path_attr() if callable(path_attr) else path_attr
        if model_path and os.path.exists(model_path):
            return
        raise Exception("Failed to save file")

    return cast(
        AdapterResult[None],
        adapter._handle_com_operation("save_file", _save),
    )
set_dimension async
set_dimension(name: str, value: float) -> AdapterResult[None]

Set a named model dimension in millimetres and rebuild.

Parameters:

Name Type Description Default
name str

Fully-qualified dimension name.

required
value float

New value in millimetres.

required

Returns:

Type Description
AdapterResult[None]

AdapterResult[None]: Result of the set operation.

Source code in src/solidworks_mcp/adapters/solidworks/io.py
async def set_dimension(self, name: str, value: float) -> AdapterResult[None]:
    """Set a named model dimension in millimetres and rebuild.

    Args:
        name: Fully-qualified dimension name.
        value: New value in millimetres.

    Returns:
        AdapterResult[None]: Result of the set operation.
    """
    adapter = self._adapter(self)
    if not adapter.currentModel:
        return AdapterResult(
            status=AdapterResultStatus.ERROR, error="No active model"
        )

    def _set() -> None:
        """Set the dimension value."""
        dimension = adapter.currentModel.Parameter(name)
        if not dimension:
            raise Exception(f"Dimension '{name}' not found")

        success = dimension.SetValue3(value / 1000.0, 8, None)
        if not success:
            raise Exception(f"Failed to set dimension '{name}'")

        adapter.currentModel.ForceRebuild3(False)

    return cast(
        AdapterResult[None],
        adapter._handle_com_operation("set_dimension", _set),
    )

SolidWorksMCPError

Bases: Exception

Base exception for SolidWorks MCP Server errors.

SolidWorksSelectionMixin

Expose feature-selection and feature-list methods through a mixin.

SolidWorksSketchMixin

Expose sketch creation and editing methods via mixin-local implementation.

_ComSessionCoordinator

_ComSessionCoordinator(adapter: PyWin32Adapter)

Coordinate COM apartment initialisation and SolidWorks application lifecycle.

This collaborator is responsible for the low-level mechanics of connecting to the SolidWorks COM server: initialising the COM apartment, acquiring the SldWorks.Application object (with retries), waiting for the server to become ready, toggling automation preferences, and tearing everything down cleanly on disconnect.

It is instantiated once inside PyWin32Adapter.__init__ and accessed via self._com_coordinator.

Attributes:

Name Type Description
_adapter

Back-reference to the owning PyWin32Adapter instance.

Store a back-reference to the owning adapter.

Parameters:

Name Type Description Default
adapter PyWin32Adapter

The PyWin32Adapter instance that created this coordinator. Must remain alive for the full lifetime of the coordinator.

required
Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
def __init__(self, adapter: "PyWin32Adapter") -> None:
    """Store a back-reference to the owning adapter.

    Args:
        adapter: The ``PyWin32Adapter`` instance that created this
            coordinator.  Must remain alive for the full lifetime of the
            coordinator.
    """
    self._adapter = adapter
Functions
acquire_solidworks_application async
acquire_solidworks_application() -> Any

Acquire a live SolidWorks COM application object with retries.

Attempts up to 8 connect-cycles. Each cycle first tries win32com.client.GetActiveObject("SldWorks.Application") to bind to a running instance, then falls back to win32com.client.Dispatch("SldWorks.Application") to start one. Between cycles the coroutine sleeps 1 second so that a slow SolidWorks launch has time to register its COM class.

Returns:

Name Type Description
Any Any

The live SldWorks.Application COM object.

Raises:

Type Description
SolidWorksMCPError

After all retries are exhausted, wraps the last pywintypes.com_error or raises a generic message when the returned object is None.

Side Effects

Sets adapter.swApp to the acquired COM object.

Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
async def acquire_solidworks_application(self) -> Any:
    """Acquire a live SolidWorks COM application object with retries.

    Attempts up to 8 connect-cycles.  Each cycle first tries
    ``win32com.client.GetActiveObject("SldWorks.Application")`` to bind to
    a running instance, then falls back to
    ``win32com.client.Dispatch("SldWorks.Application")`` to start one.
    Between cycles the coroutine sleeps 1 second so that a slow
    SolidWorks launch has time to register its COM class.

    Returns:
        Any: The live ``SldWorks.Application`` COM object.

    Raises:
        SolidWorksMCPError: After all retries are exhausted, wraps the
            last ``pywintypes.com_error`` or raises a generic message
            when the returned object is ``None``.

    Side Effects:
        Sets ``adapter.swApp`` to the acquired COM object.
    """
    self._adapter.swApp = None
    last_error: Exception | None = None
    # Force late binding (dynamic.Dispatch) — the gen_py wrapper provides
    # method-name lookup for flag_methods but early-bound dispatches
    # reject VARIANT pass-by-ref params used by OpenDoc6 and friends.
    for _ in range(8):
        try:
            raw = win32com.client.GetActiveObject("SldWorks.Application")
            app = _dynamic_dispatch(raw) if raw is not None else None
            if app is not None:
                self._adapter.swApp = app
                return app
        except pywintypes.com_error as active_error:
            last_error = active_error

        try:
            app = _dynamic_dispatch("SldWorks.Application")
            if app is not None:
                self._adapter.swApp = app
                return app
        except pywintypes.com_error as dispatch_error:
            last_error = dispatch_error

        await asyncio.sleep(1.0)

    if last_error is not None:
        raise SolidWorksMCPError(str(last_error))
    raise SolidWorksMCPError("SolidWorks COM application instance is None")
connect async
connect() -> None

Orchestrate the full SolidWorks connection sequence.

Performs in order:

  1. Initialise the COM apartment.
  2. Acquire the SldWorks.Application COM object (with retries).
  3. Wait for the server to become ready.
  4. Make the application window visible.
  5. Suppress interactive dialogs for automation.

On any failure the adapter state is cleaned up (swApp set to None, COM apartment uninitialised) before re-raising.

Raises:

Type Description
SolidWorksMCPError

Wraps any underlying COM or timeout error.

Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
async def connect(self) -> None:
    """Orchestrate the full SolidWorks connection sequence.

    Performs in order:

    1. Initialise the COM apartment.
    2. Acquire the ``SldWorks.Application`` COM object (with retries).
    3. Wait for the server to become ready.
    4. Make the application window visible.
    5. Suppress interactive dialogs for automation.

    On any failure the adapter state is cleaned up (``swApp`` set to
    ``None``, COM apartment uninitialised) before re-raising.

    Raises:
        SolidWorksMCPError: Wraps any underlying COM or timeout error.
    """
    try:
        self.initialize_com_apartment()
        app = await self.acquire_solidworks_application()
        self._adapter._attempt(
            lambda: sw_type_info.flag_methods(app, "ISldWorks"), default=0
        )
        await self.wait_for_server_ready(app)
        app.Visible = True
        self.set_automation_preferences(app, interactive=False)
    except Exception as exc:
        self._adapter.swApp = None
        self.uninitialize_com_apartment()
        raise SolidWorksMCPError(f"Failed to connect to SolidWorks: {exc}") from exc
disconnect async
disconnect() -> None

Clear session state and release the COM apartment.

Resets all adapter model/sketch references to None and always uninitialises the COM apartment via finally so the apartment is freed even if the SolidWorks process is already unstable.

Disconnect deliberately avoids additional UI preference COM calls. Real SolidWorks sessions can hit RPC teardown failures when toggles are restored during shutdown, so automation-safe preferences are applied on connect and left untouched during disconnect.

Side Effects

Sets adapter.currentModel, adapter.currentSketch, adapter.currentSketchManager, and adapter.swApp to None. Clears the sketch entity registry. Calls CoUninitialize.

Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
async def disconnect(self) -> None:
    """Clear session state and release the COM apartment.

    Resets all adapter model/sketch references to ``None`` and always
    uninitialises the COM apartment via ``finally`` so the apartment is
    freed even if the SolidWorks process is already unstable.

    Disconnect deliberately avoids additional UI preference COM calls.
    Real SolidWorks sessions can hit RPC teardown failures when toggles are
    restored during shutdown, so automation-safe preferences are applied on
    connect and left untouched during disconnect.

    Side Effects:
        Sets ``adapter.currentModel``, ``adapter.currentSketch``,
        ``adapter.currentSketchManager``, and ``adapter.swApp`` to
        ``None``.  Clears the sketch entity registry.  Calls
        ``CoUninitialize``.
    """
    try:
        self._adapter.currentModel = None
        self._adapter.currentSketch = None
        self._adapter.currentSketchManager = None
        self._adapter._reset_sketch_entity_registry()
        self._adapter.swApp = None
    finally:
        self.uninitialize_com_apartment()
initialize_com_apartment
initialize_com_apartment() -> None

Initialise the COM apartment via pythoncom.CoInitialize.

Safe to call multiple times; subsequent calls are no-ops if the apartment is already initialised (tracked via adapter._com_initialized).

Side Effects

Sets adapter._com_initialized to True on first call.

Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
def initialize_com_apartment(self) -> None:
    """Initialise the COM apartment via ``pythoncom.CoInitialize``.

    Safe to call multiple times; subsequent calls are no-ops if the
    apartment is already initialised (tracked via
    ``adapter._com_initialized``).

    Side Effects:
        Sets ``adapter._com_initialized`` to ``True`` on first call.
    """
    if self._adapter._com_initialized:
        return
    pythoncom.CoInitialize()
    self._adapter._com_initialized = True
set_automation_preferences staticmethod
set_automation_preferences(app: Any, *, interactive: bool) -> None

Toggle the SolidWorks warning and question dialog preferences.

Sets user preference toggles 150 and 149 to suppress (or restore) popup dialogs during automated workflows. Also manages the sketch-dimension input toggles so sketch dimensions do not require the interactive Modify confirmation while automation is active.

Verified against the SolidWorks 2026 constants type library, the relevant sketch-dimension toggles are:

  • swInputDimValOnCreate = 10
  • swSketchAcceptNumericInput = 372
  • swSketchCreateDimensionOnlyWhenEntered = 520
  • swScaleSketchOnFirstDimension = 642

These stay disabled for the full automation session instead of being toggled around individual dimension calls, because once SolidWorks enters the modal approval flow, extra COM cleanup chatter tends to make recovery less reliable.

Should be called with interactive=False immediately after connecting and interactive=True before disconnecting.

Parameters:

Name Type Description Default
app Any

The live SldWorks.Application COM object.

required
interactive bool

When False, dialogs are suppressed for unattended operation. When True, normal interactive behaviour is restored.

required
Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
@staticmethod
def set_automation_preferences(app: Any, *, interactive: bool) -> None:
    """Toggle the SolidWorks warning and question dialog preferences.

    Sets user preference toggles 150 and 149 to suppress (or restore)
    popup dialogs during automated workflows. Also manages the
    sketch-dimension input toggles so sketch dimensions do not require the
    interactive Modify confirmation while automation is active.

    Verified against the SolidWorks 2026 constants type library, the
    relevant sketch-dimension toggles are:

    * ``swInputDimValOnCreate`` = 10
    * ``swSketchAcceptNumericInput`` = 372
    * ``swSketchCreateDimensionOnlyWhenEntered`` = 520
    * ``swScaleSketchOnFirstDimension`` = 642

    These stay disabled for the full automation session instead of being
    toggled around individual dimension calls, because once SolidWorks
    enters the modal approval flow, extra COM cleanup chatter tends to make
    recovery less reliable.

    Should be called with ``interactive=False`` immediately after
    connecting and ``interactive=True`` before disconnecting.

    Args:
        app: The live ``SldWorks.Application`` COM object.
        interactive: When ``False``, dialogs are suppressed for
            unattended operation.  When ``True``, normal interactive
            behaviour is restored.
    """
    app.SetUserPreferenceToggle(150, interactive)
    app.SetUserPreferenceToggle(149, interactive)
    if not interactive:
        app.SetUserPreferenceToggle(10, False)
        app.SetUserPreferenceToggle(372, False)
        app.SetUserPreferenceToggle(520, False)
        app.SetUserPreferenceToggle(642, False)
uninitialize_com_apartment
uninitialize_com_apartment() -> None

Release the COM apartment via pythoncom.CoUninitialize.

Only called when this coordinator was the one that initialised the apartment (adapter._com_initialized is True). Resets the flag afterwards so reconnect attempts work correctly.

Side Effects

Sets adapter._com_initialized to False.

Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
def uninitialize_com_apartment(self) -> None:
    """Release the COM apartment via ``pythoncom.CoUninitialize``.

    Only called when this coordinator was the one that initialised the
    apartment (``adapter._com_initialized`` is ``True``).  Resets the
    flag afterwards so reconnect attempts work correctly.

    Side Effects:
        Sets ``adapter._com_initialized`` to ``False``.
    """
    if not self._adapter._com_initialized:
        return
    pythoncom.CoUninitialize()
    self._adapter._com_initialized = False
wait_for_server_ready async
wait_for_server_ready(app: Any) -> None

Poll until the SolidWorks COM server is responsive.

Reads app.RevisionNumber up to 10 times with 0.5-second pauses between attempts. This guards against race conditions when SolidWorks is still loading after the COM object is first obtained.

Parameters:

Name Type Description Default
app Any

The SldWorks.Application COM object returned by :meth:acquire_solidworks_application.

required

Raises:

Type Description
SolidWorksMCPError

If the server does not respond within 10 × 0.5 s = 5 seconds.

Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
async def wait_for_server_ready(self, app: Any) -> None:
    """Poll until the SolidWorks COM server is responsive.

    Reads ``app.RevisionNumber`` up to 10 times with 0.5-second pauses
    between attempts.  This guards against race conditions when SolidWorks
    is still loading after the COM object is first obtained.

    Args:
        app: The ``SldWorks.Application`` COM object returned by
            :meth:`acquire_solidworks_application`.

    Raises:
        SolidWorksMCPError: If the server does not respond within
            10 × 0.5 s = 5 seconds.
    """
    if not hasattr(app, "RevisionNumber"):
        return

    for _ in range(10):
        revision = self._adapter._attempt(
            lambda: self._adapter._get_attr_or_call(app, "RevisionNumber"),
            default=None,
        )
        if revision is not None:
            return
        await asyncio.sleep(0.5)

    raise SolidWorksMCPError(
        "SolidWorks COM server did not become ready in time. "
        "Confirm SolidWorks is fully launched and dismiss any startup dialogs."
    )

_DocumentRoutingService

_DocumentRoutingService(adapter: PyWin32Adapter)

Resolve document identity and select the export-target document.

Provides two helpers that isolate the policy for identifying which COM document object to use during export operations. The service prefers the SolidWorks ActiveDoc when it matches the adapter's current model, and falls back gracefully when path or title data is unavailable.

Attributes:

Name Type Description
_adapter

Back-reference to the owning PyWin32Adapter instance.

Store a back-reference to the owning adapter.

Parameters:

Name Type Description Default
adapter PyWin32Adapter

The PyWin32Adapter instance that created this service.

required
Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
def __init__(self, adapter: "PyWin32Adapter") -> None:
    """Store a back-reference to the owning adapter.

    Args:
        adapter: The ``PyWin32Adapter`` instance that created this
            service.
    """
    self._adapter = adapter
Functions
document_identity
document_identity(document: Any) -> tuple[str | None, str | None]

Return the normalised absolute path and display title for a COM document.

Tries document.GetPathName() first; falls back to getattr(document, 'GetPathName', None) for COM objects that expose the path as a property rather than a method. Applies the same two-step pattern for GetTitle.

Parameters:

Name Type Description Default
document Any

A SolidWorks IModelDoc2 COM object, or None.

required

Returns:

Type Description
str | None

tuple[str | None, str | None]: (absolute_path, title) where

str | None

absolute_path is os.path.abspath normalised and

tuple[str | None, str | None]

title is the raw display title. Either element is None

tuple[str | None, str | None]

when the corresponding attribute is absent or empty.

Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
def document_identity(self, document: Any) -> tuple[str | None, str | None]:
    """Return the normalised absolute path and display title for a COM document.

    Tries ``document.GetPathName()`` first; falls back to
    ``getattr(document, 'GetPathName', None)`` for COM objects that expose
    the path as a property rather than a method.  Applies the same
    two-step pattern for ``GetTitle``.

    Args:
        document: A SolidWorks ``IModelDoc2`` COM object, or ``None``.

    Returns:
        tuple[str | None, str | None]: ``(absolute_path, title)`` where
        ``absolute_path`` is ``os.path.abspath`` normalised and
        ``title`` is the raw display title.  Either element is ``None``
        when the corresponding attribute is absent or empty.
    """
    if document is None:
        return None, None

    raw_path = self._adapter._attempt(lambda: document.GetPathName(), default=None)
    if raw_path is None:
        raw_path = self._adapter._attempt(
            lambda: getattr(document, "GetPathName", None), default=None
        )
    path_value = str(raw_path).strip() if raw_path else ""
    normalized_path = os.path.abspath(path_value) if path_value else None

    raw_title = self._adapter._attempt(lambda: document.GetTitle(), default=None)
    if raw_title is None:
        raw_title = self._adapter._attempt(
            lambda: getattr(document, "GetTitle", None), default=None
        )
    title_value = str(raw_title).strip() if raw_title else ""

    return normalized_path, title_value or None
resolve_export_target_doc
resolve_export_target_doc() -> Any

Resolve the safest document to use for export operations.

Policy (in order):

  1. If adapter.currentModel is None, use swApp.ActiveDoc.
  2. If swApp.ActiveDoc is None, use adapter.currentModel.
  3. If both have path strings and the paths match, prefer swApp.ActiveDoc (it may have a more up-to-date state).
  4. If both have title strings that match, prefer swApp.ActiveDoc.
  5. Otherwise fall back to adapter.currentModel.

Returns:

Name Type Description
Any Any

The SolidWorks IModelDoc2 COM object to use for export,

Any

or None when neither swApp nor currentModel is set.

Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
def resolve_export_target_doc(self) -> Any:
    """Resolve the safest document to use for export operations.

    Policy (in order):

    1. If ``adapter.currentModel`` is ``None``, use ``swApp.ActiveDoc``.
    2. If ``swApp.ActiveDoc`` is ``None``, use ``adapter.currentModel``.
    3. If both have path strings and the paths match, prefer
       ``swApp.ActiveDoc`` (it may have a more up-to-date state).
    4. If both have title strings that match, prefer ``swApp.ActiveDoc``.
    5. Otherwise fall back to ``adapter.currentModel``.

    Returns:
        Any: The SolidWorks ``IModelDoc2`` COM object to use for export,
        or ``None`` when neither ``swApp`` nor ``currentModel`` is set.
    """
    active_doc = (
        getattr(self._adapter.swApp, "ActiveDoc", None)
        if self._adapter.swApp
        else None
    )
    if self._adapter.currentModel is None:
        return active_doc
    if active_doc is None:
        return self._adapter.currentModel

    current_path, current_title = self.document_identity(self._adapter.currentModel)
    active_path, active_title = self.document_identity(active_doc)

    if current_path and active_path:
        return (
            active_doc
            if current_path == active_path
            else self._adapter.currentModel
        )
    if current_title and active_title and current_title == active_title:
        return active_doc
    return self._adapter.currentModel

_FeatureSelectionService

_FeatureSelectionService(adapter: PyWin32Adapter)

Encapsulate feature-selection strategies and name-candidate expansion.

SolidWorks allows features to be selected by bare name or by the <name>@<document> qualified syntax. Several selection APIs also exist with different levels of support across SolidWorks versions. This service centralises all of that complexity so the main adapter methods stay thin.

Attributes:

Name Type Description
_adapter

Back-reference to the owning PyWin32Adapter instance.

Store a back-reference to the owning adapter.

Parameters:

Name Type Description Default
adapter PyWin32Adapter

The PyWin32Adapter instance that created this service.

required
Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
def __init__(self, adapter: "PyWin32Adapter") -> None:
    """Store a back-reference to the owning adapter.

    Args:
        adapter: The ``PyWin32Adapter`` instance that created this
            service.
    """
    self._adapter = adapter
Functions
build_feature_candidate_names
build_feature_candidate_names(feature_name: str, target_doc: Any) -> list[str]

Build a list of bare and document-qualified selection candidates.

SolidWorks requires the "<name>@<document>" syntax for SelectByID2 on assembly contexts. This method tries to read the document title and produces both bare and qualified variants so that callers do not need to duplicate that logic.

Parameters:

Name Type Description Default
feature_name str

The bare feature name as supplied by the caller (e.g. "Boss-Extrude1").

required
target_doc Any

SolidWorks IModelDoc2 COM object whose title is used to form the qualified name. Errors reading the title are silently swallowed.

required

Returns:

Type Description
list[str]

list[str]: Candidate list, always including feature_name as

list[str]

the first element. Qualified variants are appended when a non-

list[str]

empty title is available. Example::

["Boss-Extrude1", "Boss-Extrude1@Part1", "Boss-Extrude1@Part1.SLDPRT"]

Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
def build_feature_candidate_names(
    self, feature_name: str, target_doc: Any
) -> list[str]:
    """Build a list of bare and document-qualified selection candidates.

    SolidWorks requires the ``"<name>@<document>"`` syntax for
    ``SelectByID2`` on assembly contexts.  This method tries to read the
    document title and produces both bare and qualified variants so that
    callers do not need to duplicate that logic.

    Args:
        feature_name: The bare feature name as supplied by the caller
            (e.g. ``"Boss-Extrude1"``).
        target_doc: SolidWorks ``IModelDoc2`` COM object whose title is
            used to form the qualified name.  Errors reading the title
            are silently swallowed.

    Returns:
        list[str]: Candidate list, always including ``feature_name`` as
        the first element.  Qualified variants are appended when a non-
        empty title is available.  Example::

            ["Boss-Extrude1", "Boss-Extrude1@Part1", "Boss-Extrude1@Part1.SLDPRT"]
    """
    doc_title = ""
    doc_stem = ""
    try:
        raw_title = str(target_doc.GetTitle() or "").strip()
        if raw_title:
            doc_title = raw_title
            doc_stem = raw_title.rsplit(".", 1)[0]
    except Exception:
        pass

    candidates: list[str] = [feature_name]
    if doc_stem:
        candidates.append(f"{feature_name}@{doc_stem}")
    if doc_title and doc_title != doc_stem:
        candidates.append(f"{feature_name}@{doc_title}")
    return candidates
list_features
list_features(include_suppressed: bool = False) -> list[dict[str, Any]]

Enumerate model features using primary and fallback traversal paths.

Parameters:

Name Type Description Default
include_suppressed bool

Include suppressed features when True.

False

Returns:

Type Description
list[dict[str, Any]]

list[dict[str, Any]]: Ordered feature descriptors.

Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
def list_features(self, include_suppressed: bool = False) -> list[dict[str, Any]]:
    """Enumerate model features using primary and fallback traversal paths.

    Args:
        include_suppressed: Include suppressed features when ``True``.

    Returns:
        list[dict[str, Any]]: Ordered feature descriptors.
    """
    features: list[dict[str, Any]] = []
    seen: set[tuple[str, str]] = set()

    feature = self._adapter._attempt(
        lambda: self._adapter.currentModel.FirstFeature()
    )
    pos = 0
    guard = 0
    while feature and guard < 10000:
        self._append_feature_to(features, seen, feature, pos, include_suppressed)
        pos += 1
        guard += 1
        next_feature = self._adapter._attempt(
            lambda current_feature=feature: current_feature.GetNextFeature()
        )
        if next_feature is None:
            break
        feature = next_feature

    if features:
        return features

    feature_manager = getattr(self._adapter.currentModel, "FeatureManager", None)
    count = self._adapter._attempt(
        lambda: int(feature_manager.GetFeatureCount(True) or 0), default=0
    )
    for reverse_pos in range(1, count + 1):
        feature = self._adapter._attempt(
            lambda pos=reverse_pos: (
                self._adapter.currentModel.FeatureByPositionReverse(pos)
            )
        )
        if feature is None:
            continue
        self._append_feature_to(
            features,
            seen,
            feature,
            count - reverse_pos,
            include_suppressed,
        )

    return features
normalize_feature_name staticmethod
normalize_feature_name(raw_name: str | None) -> str

Normalise a feature name for case-insensitive comparison.

Strips surrounding whitespace and quotes then converts to casefold-lowercase so that mixed-case names such as 'Boss-Extrude1', " boss-extrude1 " and '"Boss-Extrude1"' all compare equal.

Parameters:

Name Type Description Default
raw_name str | None

Raw feature name string, or None.

required

Returns:

Name Type Description
str str

Normalised name. Empty string when raw_name is

str

None or blank.

Example::

svc.normalize_feature_name('"Boss-Extrude1"') == 'boss-extrude1'
Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
@staticmethod
def normalize_feature_name(raw_name: str | None) -> str:
    """Normalise a feature name for case-insensitive comparison.

    Strips surrounding whitespace and quotes then converts to
    ``casefold``-lowercase so that mixed-case names such as
    ``'Boss-Extrude1'``, ``" boss-extrude1 "`` and ``'"Boss-Extrude1"'``
    all compare equal.

    Args:
        raw_name: Raw feature name string, or ``None``.

    Returns:
        str: Normalised name.  Empty string when ``raw_name`` is
        ``None`` or blank.

    Example::

        svc.normalize_feature_name('"Boss-Extrude1"') == 'boss-extrude1'
    """
    return str(raw_name or "").strip().strip('"').casefold()
select_feature
select_feature(feature_name: str) -> dict[str, Any]

Run all feature-selection strategies and return best-effort payload.

Parameters:

Name Type Description Default
feature_name str

Feature name requested by caller.

required

Returns:

Type Description
dict[str, Any]

dict[str, Any]: Selection result payload.

Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
def select_feature(self, feature_name: str) -> dict[str, Any]:
    """Run all feature-selection strategies and return best-effort payload.

    Args:
        feature_name: Feature name requested by caller.

    Returns:
        dict[str, Any]: Selection result payload.
    """
    target_doc = self._adapter.currentModel
    candidate_names = self.build_feature_candidate_names(feature_name, target_doc)

    result = self.try_select_by_extension(target_doc, candidate_names, feature_name)
    if result:
        return result

    result = self.try_select_by_component(target_doc, candidate_names, feature_name)
    if result:
        return result

    result = self.try_select_by_feature_tree(
        target_doc, feature_name, candidate_names
    )
    if result:
        return result

    return {
        "selected": False,
        "feature_name": feature_name,
        "selected_name": feature_name,
    }
try_select_by_component
try_select_by_component(target_doc: Any, candidate_names: list[str], feature_name: str) -> dict[str, Any] | None

Attempt component selection for assembly-context features.

Calls target_doc.GetComponentByName (when available) and then tries three selector methods on the resulting component object: Select4(False, None, False), Select(False,), and Select2(False, 0).

This path handles assembly components that are not reachable through SelectByID2 alone.

Parameters:

Name Type Description Default
target_doc Any

SolidWorks IAssemblyDoc or IModelDoc2 COM object.

required
candidate_names list[str]

List of candidate name strings. Only the part before the first @ is used as the component name.

required
feature_name str

Original caller-supplied name for the result payload.

required

Returns:

Type Description
dict[str, Any] | None

dict[str, Any] | None: Success dict (same schema as

dict[str, Any] | None

meth:try_select_by_extension) or None when not applicable

dict[str, Any] | None

or all attempts fail.

Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
def try_select_by_component(
    self,
    target_doc: Any,
    candidate_names: list[str],
    feature_name: str,
) -> dict[str, Any] | None:
    """Attempt component selection for assembly-context features.

    Calls ``target_doc.GetComponentByName`` (when available) and then
    tries three selector methods on the resulting component object:
    ``Select4(False, None, False)``, ``Select(False,)``, and
    ``Select2(False, 0)``.

    This path handles assembly components that are not reachable through
    ``SelectByID2`` alone.

    Args:
        target_doc: SolidWorks ``IAssemblyDoc`` or ``IModelDoc2`` COM
            object.
        candidate_names: List of candidate name strings.  Only the part
            before the first ``@`` is used as the component name.
        feature_name: Original caller-supplied name for the result
            payload.

    Returns:
        dict[str, Any] | None: Success dict (same schema as
        :meth:`try_select_by_extension`) or ``None`` when not applicable
        or all attempts fail.
    """
    get_component_by_name = getattr(target_doc, "GetComponentByName", None)
    if not callable(get_component_by_name):
        return None

    for candidate in candidate_names:
        component_name = candidate.split("@", 1)[0]
        component = self._adapter._attempt(
            lambda name=component_name: get_component_by_name(name),
            default=None,
        )
        if component is None:
            continue
        for method_name, args in [
            ("Select4", (False, None, False)),
            ("Select", (False,)),
            ("Select2", (False, 0)),
        ]:
            selector = getattr(component, method_name, None)
            if not callable(selector):
                continue
            try:
                if bool(selector(*args)):
                    return {
                        "selected": True,
                        "feature_name": feature_name,
                        "selected_name": component_name,
                        "entity_type": f"component:{method_name}",
                    }
            except Exception:
                continue
    return None
try_select_by_extension
try_select_by_extension(target_doc: Any, candidate_names: list[str], feature_name: str) -> dict[str, Any] | None

Attempt feature selection via Extension.SelectByID2.

Iterates the Cartesian product of candidate_names × entity-type strings. Entity types tried (in order): "BODYFEATURE", "COMPONENT", "SKETCH", "PLANE", "MATE", "" (auto). Returns on the first successful selection.

Parameters:

Name Type Description Default
target_doc Any

SolidWorks IModelDoc2 COM object.

required
candidate_names list[str]

Ordered list of name strings to try (bare and qualified variants from :meth:build_feature_candidate_names).

required
feature_name str

The original caller-supplied name, included in the result payload for traceability.

required

Returns:

Type Description
dict[str, Any] | None

dict[str, Any] | None: On success, a result dict with keys

dict[str, Any] | None

selected, feature_name, selected_name,

dict[str, Any] | None

entity_type. None when all attempts fail.

Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
def try_select_by_extension(
    self,
    target_doc: Any,
    candidate_names: list[str],
    feature_name: str,
) -> dict[str, Any] | None:
    """Attempt feature selection via ``Extension.SelectByID2``.

    Iterates the Cartesian product of ``candidate_names`` × entity-type
    strings.  Entity types tried (in order): ``"BODYFEATURE"``,
    ``"COMPONENT"``, ``"SKETCH"``, ``"PLANE"``, ``"MATE"``, ``""`` (auto).
    Returns on the first successful selection.

    Args:
        target_doc: SolidWorks ``IModelDoc2`` COM object.
        candidate_names: Ordered list of name strings to try (bare and
            qualified variants from :meth:`build_feature_candidate_names`).
        feature_name: The original caller-supplied name, included in the
            result payload for traceability.

    Returns:
        dict[str, Any] | None: On success, a result dict with keys
        ``selected``, ``feature_name``, ``selected_name``,
        ``entity_type``.  ``None`` when all attempts fail.
    """
    entity_types = ["BODYFEATURE", "COMPONENT", "SKETCH", "PLANE", "MATE", ""]
    for candidate in candidate_names:
        for entity_type in entity_types:
            try:
                selected = target_doc.Extension.SelectByID2(
                    candidate, entity_type, 0, 0, 0, False, 0, None, 0
                )
                if selected:
                    return {
                        "selected": True,
                        "feature_name": feature_name,
                        "selected_name": candidate,
                        "entity_type": entity_type or "auto",
                    }
            except Exception:
                continue
    return None
try_select_by_feature_tree
try_select_by_feature_tree(target_doc: Any, feature_name: str, candidate_names: list[str]) -> dict[str, Any] | None

Walk the SolidWorks feature tree and select the first matching feature.

Iterates via FirstFeature / GetNextFeature (up to 10 000 features as a runaway guard) and compares each feature's Name attribute against the normalised candidate set. Matching is case-insensitive and also strips the @document qualifier.

This is the most expensive selection strategy and is only attempted after :meth:try_select_by_extension and :meth:try_select_by_component have both failed.

Parameters:

Name Type Description Default
target_doc Any

SolidWorks IModelDoc2 COM object.

required
feature_name str

Original caller-supplied name for the result payload.

required
candidate_names list[str]

Candidate names used to build the normalised match set.

required

Returns:

Type Description
dict[str, Any] | None

dict[str, Any] | None: Success dict (same schema as

dict[str, Any] | None

meth:try_select_by_extension) with entity_type set to

dict[str, Any] | None

"feature-tree", or None when no match is found.

Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
def try_select_by_feature_tree(
    self,
    target_doc: Any,
    feature_name: str,
    candidate_names: list[str],
) -> dict[str, Any] | None:
    """Walk the SolidWorks feature tree and select the first matching feature.

    Iterates via ``FirstFeature`` / ``GetNextFeature`` (up to 10 000
    features as a runaway guard) and compares each feature\'s ``Name``
    attribute against the normalised candidate set.  Matching is
    case-insensitive and also strips the ``@document`` qualifier.

    This is the most expensive selection strategy and is only attempted
    after :meth:`try_select_by_extension` and
    :meth:`try_select_by_component` have both failed.

    Args:
        target_doc: SolidWorks ``IModelDoc2`` COM object.
        feature_name: Original caller-supplied name for the result
            payload.
        candidate_names: Candidate names used to build the normalised
            match set.

    Returns:
        dict[str, Any] | None: Success dict (same schema as
        :meth:`try_select_by_extension`) with ``entity_type`` set to
        ``"feature-tree"``, or ``None`` when no match is found.
    """
    normalized_candidates = {
        self.normalize_feature_name(c)
        for c in candidate_names
        if self.normalize_feature_name(c)
    }
    normalized_bases = {c.split("@", 1)[0] for c in normalized_candidates if c}

    feature = self._adapter._attempt(lambda: target_doc.FirstFeature())
    guard = 0
    while feature and guard < 10000:
        guard += 1
        feature_ref = feature
        tree_name = self._adapter._attempt(
            lambda current_feature=feature_ref: str(current_feature.Name or ""),
            default="",
        )
        if self._matches_candidate_name(
            tree_name, normalized_candidates, normalized_bases
        ):
            try:
                if feature.Select2(False, 0):
                    return {
                        "selected": True,
                        "feature_name": feature_name,
                        "selected_name": tree_name or feature_name,
                        "entity_type": "feature-tree",
                    }
            except Exception:
                pass
        next_feature = self._adapter._attempt(
            lambda current_feature=feature_ref: current_feature.GetNextFeature()
        )
        if next_feature is None:
            break
        feature = next_feature
    return None

_SketchGeometryService

_SketchGeometryService(adapter: PyWin32Adapter)

Manage transient sketch-entity storage and provide geometry helpers.

Maintains a per-sketch registry that maps stable string IDs (e.g. "Line_1", "Circle_3") to live SolidWorks COM entity objects. The registry is reset each time a new sketch is opened or closed.

Also provides geometry primitives used by the sketch-dimension pipeline: coordinate extraction, segment endpoint reading, shared-vertex detection, and smart-dimension placement-point calculation.

Attributes:

Name Type Description
_adapter

Back-reference to the owning PyWin32Adapter instance.

Store a back-reference to the owning adapter.

Parameters:

Name Type Description Default
adapter PyWin32Adapter

The PyWin32Adapter instance that created this service. Provides access to _sketch_entities and _sketch_entity_counter.

required
Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
def __init__(self, adapter: "PyWin32Adapter") -> None:
    """Store a back-reference to the owning adapter.

    Args:
        adapter: The ``PyWin32Adapter`` instance that created this
            service.  Provides access to ``_sketch_entities`` and
            ``_sketch_entity_counter``.
    """
    self._adapter = adapter
Functions
angular_dimension_placement
angular_dimension_placement(entity1: Any, entity2: Any) -> tuple[float, float, float, int] | None

Compute the text-placement point for an angular dimension between two lines.

Detects the shared vertex, derives the two ray directions, bisects the angle, offsets the placement point by 15–30 mm along the bisector (clamped to 60 % of the shorter leg), and converts the bisector to a dimension-direction constant.

Parameters:

Name Type Description Default
entity1 Any

First SolidWorks sketch-line COM object.

required
entity2 Any

Second SolidWorks sketch-line COM object (must share a vertex with entity1).

required

Returns:

Type Description
tuple[float, float, float, int] | None

tuple[float, float, float, int] | None:

tuple[float, float, float, int] | None

(text_x, text_y, text_z, direction) in metres, or None

tuple[float, float, float, int] | None

when no shared vertex is found or segment data is unavailable.

Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
def angular_dimension_placement(
    self, entity1: Any, entity2: Any
) -> tuple[float, float, float, int] | None:
    """Compute the text-placement point for an angular dimension between two lines.

    Detects the shared vertex, derives the two ray directions, bisects
    the angle, offsets the placement point by 15–30 mm along the bisector
    (clamped to 60 % of the shorter leg), and converts the bisector to a
    dimension-direction constant.

    Args:
        entity1: First SolidWorks sketch-line COM object.
        entity2: Second SolidWorks sketch-line COM object (must share a
            vertex with ``entity1``).

    Returns:
        tuple[float, float, float, int] | None:
        ``(text_x, text_y, text_z, direction)`` in metres, or ``None``
        when no shared vertex is found or segment data is unavailable.
    """
    endpoints1 = self.read_segment_endpoints(entity1)
    endpoints2 = self.read_segment_endpoints(entity2)
    if endpoints1 is None or endpoints2 is None:
        return None

    pts1 = endpoints1
    pts2 = endpoints2
    tol = 1e-6
    vertex = None
    ray1 = None
    ray2 = None
    for p1 in pts1:
        for p2 in pts2:
            if (
                abs(p1[0] - p2[0]) <= tol
                and abs(p1[1] - p2[1]) <= tol
                and abs(p1[2] - p2[2]) <= tol
            ):
                vertex = p1
                ray1 = pts1[1] if pts1[0] == p1 else pts1[0]
                ray2 = pts2[1] if pts2[0] == p2 else pts2[0]
                break
        if vertex is not None:
            break

    if vertex is None or ray1 is None or ray2 is None:
        return None

    v1x = ray1[0] - vertex[0]
    v1y = ray1[1] - vertex[1]
    v2x = ray2[0] - vertex[0]
    v2y = ray2[1] - vertex[1]
    l1 = (v1x * v1x + v1y * v1y) ** 0.5
    l2 = (v2x * v2x + v2y * v2y) ** 0.5
    if l1 <= 1e-9 or l2 <= 1e-9:
        return None

    b1x = v1x / l1
    b1y = v1y / l1
    b2x = v2x / l2
    b2y = v2y / l2
    bis_x = b1x + b2x
    bis_y = b1y + b2y
    if abs(bis_x) <= 1e-9 and abs(bis_y) <= 1e-9:
        bis_x = -b1y
        bis_y = b1x

    bis_len = (bis_x * bis_x + bis_y * bis_y) ** 0.5
    bis_x /= bis_len
    bis_y /= bis_len
    offset = max(0.015, min(0.03, min(l1, l2) * 0.6))
    text_x = vertex[0] + bis_x * offset
    text_y = vertex[1] + bis_y * offset
    direction = self.smart_dimension_direction(bis_x, bis_y)
    return (text_x, text_y, vertex[2], direction)
point_xyz
point_xyz(point_obj: Any) -> tuple[float, float, float] | None

Extract the XYZ coordinates from a SolidWorks point-like COM object.

Tries two access patterns:

  1. Direct attribute access — point_obj.X, point_obj.Y, point_obj.Z (IMathPoint, IVertex).
  2. Method call — point_obj.GetCoords() returning a sequence of at least three numbers.

All values are in metres (SolidWorks internal units).

Parameters:

Name Type Description Default
point_obj Any

Any COM object that might expose XYZ coordinates. None is accepted and returns None immediately.

required

Returns:

Type Description
tuple[float, float, float] | None

tuple[float, float, float] | None: (x, y, z) in metres, or

tuple[float, float, float] | None

None when no coordinate pattern matches.

Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
def point_xyz(self, point_obj: Any) -> tuple[float, float, float] | None:
    """Extract the XYZ coordinates from a SolidWorks point-like COM object.

    Tries two access patterns:

    1. Direct attribute access — ``point_obj.X``, ``point_obj.Y``,
       ``point_obj.Z`` (``IMathPoint``, ``IVertex``).
    2. Method call — ``point_obj.GetCoords()`` returning a sequence of
       at least three numbers.

    All values are in **metres** (SolidWorks internal units).

    Args:
        point_obj: Any COM object that might expose XYZ coordinates.
            ``None`` is accepted and returns ``None`` immediately.

    Returns:
        tuple[float, float, float] | None: ``(x, y, z)`` in metres, or
        ``None`` when no coordinate pattern matches.
    """
    if point_obj is None:
        return None

    if (
        hasattr(point_obj, "X")
        and hasattr(point_obj, "Y")
        and hasattr(point_obj, "Z")
    ):
        x = self._adapter._attempt(lambda: float(point_obj.X), default=None)
        y = self._adapter._attempt(lambda: float(point_obj.Y), default=None)
        z = self._adapter._attempt(lambda: float(point_obj.Z), default=None)
        if x is not None and y is not None and z is not None:
            return (x, y, z)

    coords = self._adapter._attempt(lambda: point_obj.GetCoords(), default=None)
    if isinstance(coords, (list, tuple)) and len(coords) >= 3:
        return (float(coords[0]), float(coords[1]), float(coords[2]))

    return None
read_segment_endpoints
read_segment_endpoints(entity: Any) -> tuple[tuple[float, float, float], tuple[float, float, float]] | None

Read the start and end coordinates of a sketch line or arc segment.

Accesses entity.GetStartPoint and entity.GetEndPoint (as properties, not method calls). Both must return sequences of at least three numeric values.

Parameters:

Name Type Description Default
entity Any

SolidWorks ISketchLine or ISketchArc COM object.

required

Returns:

Type Description
tuple[tuple[float, float, float], tuple[float, float, float]] | None

tuple[tuple, tuple] | None: ((x1, y1, z1), (x2, y2, z2)) in

tuple[tuple[float, float, float], tuple[float, float, float]] | None

metres, or None when the attributes are absent or empty.

Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
def read_segment_endpoints(
    self, entity: Any
) -> tuple[tuple[float, float, float], tuple[float, float, float]] | None:
    """Read the start and end coordinates of a sketch line or arc segment.

    Accesses ``entity.GetStartPoint`` and ``entity.GetEndPoint`` (as
    properties, not method calls).  Both must return sequences of at least
    three numeric values.

    Args:
        entity: SolidWorks ``ISketchLine`` or ``ISketchArc`` COM object.

    Returns:
        tuple[tuple, tuple] | None: ``((x1, y1, z1), (x2, y2, z2))`` in
        metres, or ``None`` when the attributes are absent or empty.
    """
    start = self._adapter._attempt(lambda: entity.GetStartPoint, default=None)
    end = self._adapter._attempt(lambda: entity.GetEndPoint, default=None)
    if (
        isinstance(start, tuple)
        and len(start) >= 3
        and isinstance(end, tuple)
        and len(end) >= 3
    ):
        return (
            (float(start[0]), float(start[1]), float(start[2])),
            (float(end[0]), float(end[1]), float(end[2])),
        )
    return None
register_entity
register_entity(prefix: str, entity: Any) -> str

Store a COM entity handle and return a stable string identifier.

Increments the counter, derives an ID of the form "<prefix>_<counter>" (e.g. "Line_3"), stores the entity in adapter._sketch_entities, and returns the ID so callers can reference the entity in later dimension or constraint calls.

Parameters:

Name Type Description Default
prefix str

Descriptor for the entity type, e.g. "Line", "Circle", "Arc", "Rectangle".

required
entity Any

Live SolidWorks COM entity object returned by the SketchManager create call.

required

Returns:

Name Type Description
str str

Stable entity ID, e.g. "Circle_2".

Example::

line_id = service.register_entity("Line", sw_line_obj)
# line_id == "Line_1"
Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
def register_entity(self, prefix: str, entity: Any) -> str:
    """Store a COM entity handle and return a stable string identifier.

    Increments the counter, derives an ID of the form
    ``"<prefix>_<counter>"`` (e.g. ``"Line_3"``), stores the entity in
    ``adapter._sketch_entities``, and returns the ID so callers can
    reference the entity in later dimension or constraint calls.

    Args:
        prefix: Descriptor for the entity type, e.g. ``"Line"``,
            ``"Circle"``, ``"Arc"``, ``"Rectangle"``.
        entity: Live SolidWorks COM entity object returned by the
            ``SketchManager`` create call.

    Returns:
        str: Stable entity ID, e.g. ``"Circle_2"``.

    Example::

        line_id = service.register_entity("Line", sw_line_obj)
        # line_id == "Line_1"
    """
    self._adapter._sketch_entity_counter += 1
    entity_id = f"{prefix}_{self._adapter._sketch_entity_counter}"
    self._adapter._sketch_entities[entity_id] = entity
    return entity_id
reset_registry
reset_registry() -> None

Clear the sketch entity registry and reset the ID counter.

Should be called at the start of every new sketch (via adapter._reset_sketch_entity_registry) so that entity IDs from a previous sketch do not bleed into the current session.

Side Effects

Clears adapter._sketch_entities and sets adapter._sketch_entity_counter to 0.

Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
def reset_registry(self) -> None:
    """Clear the sketch entity registry and reset the ID counter.

    Should be called at the start of every new sketch (via
    ``adapter._reset_sketch_entity_registry``) so that entity IDs from a
    previous sketch do not bleed into the current session.

    Side Effects:
        Clears ``adapter._sketch_entities`` and sets
        ``adapter._sketch_entity_counter`` to ``0``.
    """
    self._adapter._sketch_entities.clear()
    self._adapter._sketch_entity_centers.clear()
    self._adapter._sketch_entity_counter = 0
segment_point_objects
segment_point_objects(entity: Any) -> tuple[Any | None, Any | None]

Return the COM point objects at the start and end of a segment.

Unlike :meth:read_segment_endpoints, this returns the raw COM objects (ISketchPoint) rather than coordinate tuples, so they can be used in selection calls for angular dimensioning.

Parameters:

Name Type Description Default
entity Any

SolidWorks sketch segment COM object.

required

Returns:

Type Description
Any | None

tuple[Any | None, Any | None]: (start_point_obj, end_point_obj);

Any | None

either element may be None if the attribute is absent.

Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
def segment_point_objects(self, entity: Any) -> tuple[Any | None, Any | None]:
    """Return the COM point objects at the start and end of a segment.

    Unlike :meth:`read_segment_endpoints`, this returns the raw COM
    objects (``ISketchPoint``) rather than coordinate tuples, so they can
    be used in selection calls for angular dimensioning.

    Args:
        entity: SolidWorks sketch segment COM object.

    Returns:
        tuple[Any | None, Any | None]: ``(start_point_obj, end_point_obj)``;
        either element may be ``None`` if the attribute is absent.
    """
    start = self._adapter._attempt(lambda: entity.GetStartPoint2, default=None)
    end = self._adapter._attempt(lambda: entity.GetEndPoint2, default=None)
    return (start, end)
select_entity
select_entity(entity: Any, append: bool) -> bool

Select a COM entity in the SolidWorks selection manager.

Tries three COM selection methods in decreasing API version order: Select4 (modern), Select2 (legacy), Select (oldest). The first call that returns a truthy value terminates the search.

Parameters:

Name Type Description Default
entity Any

Live SolidWorks COM sketch entity object (line, arc, circle, etc.).

required
append bool

When True, the entity is added to the existing selection set. When False, existing selections are cleared first.

required

Returns:

Name Type Description
bool bool

True if any of the three select methods succeeded;

bool

False if all failed or raised.

Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
def select_entity(self, entity: Any, append: bool) -> bool:
    """Select a COM entity in the SolidWorks selection manager.

    Tries three COM selection methods in decreasing API version order:
    ``Select4`` (modern), ``Select2`` (legacy), ``Select`` (oldest).  The
    first call that returns a truthy value terminates the search.

    Args:
        entity: Live SolidWorks COM sketch entity object (line, arc,
            circle, etc.).
        append: When ``True``, the entity is added to the existing
            selection set.  When ``False``, existing selections are
            cleared first.

    Returns:
        bool: ``True`` if any of the three select methods succeeded;
        ``False`` if all failed or raised.
    """
    selected = self._adapter._attempt(
        lambda: bool(entity.Select4(append, None)),
        default=False,
    )
    if selected:
        return True

    selected = self._adapter._attempt(
        lambda: bool(entity.Select2(append, 0)),
        default=False,
    )
    if selected:
        return True

    return bool(
        self._adapter._attempt(
            lambda: bool(entity.Select(append)),
            default=False,
        )
    )
set_display_dimension_value
set_display_dimension_value(display_dim: Any, value_mm: float) -> None

Set the numeric value of a display-dimension object.

Converts the value from millimetres to metres and tries three COM paths in order:

  1. GetDimension2(0).SetSystemValue3(value_m, 1, None) — modern.
  2. GetDimension().SetSystemValue2(value_m, 1) — legacy.
  3. Direct SystemValue property assignment — oldest.

Parameters:

Name Type Description Default
display_dim Any

SolidWorks display-dimension COM object returned by Extension.AddDimension.

required
value_mm float

Desired dimension value in millimetres. Converted to metres internally.

required
Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
def set_display_dimension_value(self, display_dim: Any, value_mm: float) -> None:
    """Set the numeric value of a display-dimension object.

    Converts the value from millimetres to metres and tries three COM
    paths in order:

    1. ``GetDimension2(0).SetSystemValue3(value_m, 1, None)`` — modern.
    2. ``GetDimension().SetSystemValue2(value_m, 1)`` — legacy.
    3. Direct ``SystemValue`` property assignment — oldest.

    Args:
        display_dim: SolidWorks display-dimension COM object returned by
            ``Extension.AddDimension``.
        value_mm: Desired dimension value in **millimetres**.  Converted
            to metres internally.
    """
    value_m = value_mm / 1000.0
    dimension_obj = self._adapter._attempt(
        lambda: display_dim.GetDimension2(0), default=None
    )
    if dimension_obj is None:
        dimension_obj = self._adapter._attempt(
            lambda: display_dim.GetDimension(), default=None
        )
    if dimension_obj is None:
        dimension_obj = display_dim

    if (
        self._adapter._attempt(
            lambda: dimension_obj.SetSystemValue3(value_m, 1, None), default=None
        )
        is not None
    ):
        return
    if (
        self._adapter._attempt(
            lambda: dimension_obj.SetSystemValue2(value_m, 1), default=None
        )
        is not None
    ):
        return

    if hasattr(dimension_obj, "SystemValue"):
        dimension_obj.SystemValue = value_m
set_point_xyz
set_point_xyz(point_obj: Any, x: float, y: float, z: float) -> bool

Set coordinates on a SolidWorks point-like COM object.

Tries SetCoords(x, y, z) first (modern API), then SetCoords2(x, y, z) (older variant). All values should be in metres.

Parameters:

Name Type Description Default
point_obj Any

COM point object to update, or None.

required
x float

New X coordinate in metres.

required
y float

New Y coordinate in metres.

required
z float

New Z coordinate in metres.

required

Returns:

Name Type Description
bool bool

True when a setter call succeeded; False otherwise

bool

(including when point_obj is None).

Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
def set_point_xyz(self, point_obj: Any, x: float, y: float, z: float) -> bool:
    """Set coordinates on a SolidWorks point-like COM object.

    Tries ``SetCoords(x, y, z)`` first (modern API), then
    ``SetCoords2(x, y, z)`` (older variant).  All values should be in
    **metres**.

    Args:
        point_obj: COM point object to update, or ``None``.
        x: New X coordinate in metres.
        y: New Y coordinate in metres.
        z: New Z coordinate in metres.

    Returns:
        bool: ``True`` when a setter call succeeded; ``False`` otherwise
        (including when ``point_obj`` is ``None``).
    """
    if point_obj is None:
        return False
    if (
        self._adapter._attempt(lambda: point_obj.SetCoords(x, y, z), default=None)
        is not None
    ):
        return True
    if (
        self._adapter._attempt(lambda: point_obj.SetCoords2(x, y, z), default=None)
        is not None
    ):
        return True
    return False
shared_segment_vertex
shared_segment_vertex(entity1: Any, entity2: Any) -> tuple[Any, Any, Any] | None

Find a vertex point shared by two sketch segments.

Compares all four endpoint-object pairs (2 from each segment) using a coordinate tolerance of 1e-6 m. Used by the angular-dimension pipeline to locate the pivot vertex between two lines.

Parameters:

Name Type Description Default
entity1 Any

First SolidWorks sketch segment COM object.

required
entity2 Any

Second SolidWorks sketch segment COM object.

required

Returns:

Type Description
tuple[Any, Any, Any] | None

tuple[Any, Any, Any] | None: ``(shared_point_obj, point1_obj,

tuple[Any, Any, Any] | None

point2_obj)whereshared_point_obj`` is the common vertex

tuple[Any, Any, Any] | None

(same object as point1_obj in current implementation), or

tuple[Any, Any, Any] | None

None when no shared vertex is found.

Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
def shared_segment_vertex(
    self, entity1: Any, entity2: Any
) -> tuple[Any, Any, Any] | None:
    """Find a vertex point shared by two sketch segments.

    Compares all four endpoint-object pairs (2 from each segment) using a
    coordinate tolerance of 1e-6 m.  Used by the angular-dimension
    pipeline to locate the pivot vertex between two lines.

    Args:
        entity1: First SolidWorks sketch segment COM object.
        entity2: Second SolidWorks sketch segment COM object.

    Returns:
        tuple[Any, Any, Any] | None: ``(shared_point_obj, point1_obj,
        point2_obj)`` where ``shared_point_obj`` is the common vertex
        (same object as ``point1_obj`` in current implementation), or
        ``None`` when no shared vertex is found.
    """
    points1 = self.segment_point_objects(entity1)
    points2 = self.segment_point_objects(entity2)
    tol = 1e-6
    for point1 in points1:
        xyz1 = self.point_xyz(point1)
        if xyz1 is None:
            continue
        for point2 in points2:
            xyz2 = self.point_xyz(point2)
            if xyz2 is None:
                continue
            if (
                abs(xyz1[0] - xyz2[0]) <= tol
                and abs(xyz1[1] - xyz2[1]) <= tol
                and abs(xyz1[2] - xyz2[2]) <= tol
            ):
                return (point1, point1, point2)
    return None
single_line_dimension_placement
single_line_dimension_placement(entity: Any) -> tuple[float, float, float, int] | None

Compute the text-placement point and direction for a linear dimension.

Reads the segment midpoint, computes the outward normal (perpendicular to the segment direction), offsets the placement point by 35 % of the segment length (clamped to 10–20 mm), and converts the normal to a SolidWorks dimension-direction constant.

Parameters:

Name Type Description Default
entity Any

SolidWorks ISketchLine or ISketchArc COM object.

required

Returns:

Type Description
tuple[float, float, float, int] | None

tuple[float, float, float, int] | None:

tuple[float, float, float, int] | None

(text_x, text_y, text_z, direction) in metres, or None

tuple[float, float, float, int] | None

when endpoint data is unavailable.

Example::

placement = service.single_line_dimension_placement(line_obj)
if placement:
    text_x, text_y, text_z, direction = placement
Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
def single_line_dimension_placement(
    self, entity: Any
) -> tuple[float, float, float, int] | None:
    """Compute the text-placement point and direction for a linear dimension.

    Reads the segment midpoint, computes the outward normal (perpendicular
    to the segment direction), offsets the placement point by 35 % of the
    segment length (clamped to 10–20 mm), and converts the normal to a
    SolidWorks dimension-direction constant.

    Args:
        entity: SolidWorks ``ISketchLine`` or ``ISketchArc`` COM object.

    Returns:
        tuple[float, float, float, int] | None:
        ``(text_x, text_y, text_z, direction)`` in metres, or ``None``
        when endpoint data is unavailable.

    Example::

        placement = service.single_line_dimension_placement(line_obj)
        if placement:
            text_x, text_y, text_z, direction = placement
    """
    endpoints = self.read_segment_endpoints(entity)
    if endpoints is None:
        return None

    (x1, y1, z1), (x2, y2, z2) = endpoints
    dx = x2 - x1
    dy = y2 - y1
    length = (dx * dx + dy * dy) ** 0.5
    if length <= 1e-9:
        return None

    mid_x = (x1 + x2) / 2.0
    mid_y = (y1 + y2) / 2.0
    mid_z = (z1 + z2) / 2.0

    normal_x = -dy / length
    normal_y = dx / length
    offset = max(0.01, min(0.02, length * 0.35))
    text_x = mid_x + normal_x * offset
    text_y = mid_y + normal_y * offset
    direction = self.smart_dimension_direction(normal_x, normal_y)
    return (text_x, text_y, mid_z, direction)
smart_dimension_direction
smart_dimension_direction(dx: float, dy: float) -> int

Map a 2-D direction vector to a SolidWorks dimension-direction constant.

The dominant axis determines horizontal vs vertical; within each axis the sign selects left/right or up/down.

Parameters:

Name Type Description Default
dx float

Horizontal component of the dimension normal vector.

required
dy float

Vertical component of the dimension normal vector.

required

Returns:

Name Type Description
int int

One of the four swSmartDimensionDirection* constants

int

from adapter.constants:

int

swSmartDimensionDirectionRight,

int

swSmartDimensionDirectionLeft,

int

swSmartDimensionDirectionUp, or

int

swSmartDimensionDirectionDown.

Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
def smart_dimension_direction(self, dx: float, dy: float) -> int:
    """Map a 2-D direction vector to a SolidWorks dimension-direction constant.

    The dominant axis determines horizontal vs vertical; within each axis
    the sign selects left/right or up/down.

    Args:
        dx: Horizontal component of the dimension normal vector.
        dy: Vertical component of the dimension normal vector.

    Returns:
        int: One of the four ``swSmartDimensionDirection*`` constants
        from ``adapter.constants``:
        ``swSmartDimensionDirectionRight``,
        ``swSmartDimensionDirectionLeft``,
        ``swSmartDimensionDirectionUp``, or
        ``swSmartDimensionDirectionDown``.
    """
    if abs(dx) >= abs(dy):
        return (
            self._adapter.constants["swSmartDimensionDirectionRight"]
            if dx >= 0.0
            else self._adapter.constants["swSmartDimensionDirectionLeft"]
        )
    return (
        self._adapter.constants["swSmartDimensionDirectionUp"]
        if dy >= 0.0
        else self._adapter.constants["swSmartDimensionDirectionDown"]
    )

Functions

_dynamic_dispatch

_dynamic_dispatch(arg: Any) -> Any

Forward to win32com.client.dynamic.Dispatch via the imported module reference. Forces late binding so VARIANT pass-by-ref params used by OpenDoc6 keep working even when the makepy gen_py wrapper is loaded.

Tests that need to stub dispatch should monkeypatch win32com.client.dynamic.Dispatch directly — the monkeypatch propagates through this module reference because Python modules are singletons.

Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
def _dynamic_dispatch(arg: Any) -> Any:
    """Forward to ``win32com.client.dynamic.Dispatch`` via the imported
    module reference. Forces late binding so VARIANT pass-by-ref params
    used by ``OpenDoc6`` keep working even when the makepy ``gen_py``
    wrapper is loaded.

    Tests that need to stub dispatch should monkeypatch
    ``win32com.client.dynamic.Dispatch`` directly — the monkeypatch
    propagates through this module reference because Python modules
    are singletons.
    """
    return _dynamic_module.Dispatch(arg)

_parse_vb_module_name

_parse_vb_module_name(macro_path: str) -> str

Read Attribute VB_Name = "..." from a SolidWorks text macro file.

Falls back to the file stem (e.g. paper_airplane for paper_airplane.swp), then to "SolidWorksMacro" which is the name used by the macro recorder.

Parameters:

Name Type Description Default
macro_path str

The macro path value.

required

Returns:

Name Type Description
str str

The resulting text value.

Source code in src/solidworks_mcp/adapters/pywin32_adapter.py
def _parse_vb_module_name(macro_path: str) -> str:
    """Read ``Attribute VB_Name = "..."`` from a SolidWorks text macro file.

    Falls back to the file stem (e.g. ``paper_airplane`` for ``paper_airplane.swp``), then
    to ``"SolidWorksMacro"`` which is the name used by the macro recorder.

    Args:
        macro_path (str): The macro path value.

    Returns:
        str: The resulting text value.
    """
    try:
        with open(macro_path, encoding="utf-8", errors="replace") as fh:
            for line in fh:
                line = line.strip()
                if line.lower().startswith("attribute vb_name"):
                    # Attribute VB_Name = "SolidWorksMacro"
                    _, _, rhs = line.partition("=")
                    return rhs.strip().strip('"').strip("'")
    except OSError:
        pass
    stem = os.path.splitext(os.path.basename(macro_path))[0]
    if stem and not stem.startswith(".") and stem.strip("."):
        return stem
    return "SolidWorksMacro"