Skip to content

solidworks_mcp.adapters.solidworks.io

solidworks_mcp.adapters.solidworks.io

Model I/O mixin for PyWin32 SolidWorks operations.

Classes

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.

MassProperties

Bases: BaseModel

Mass properties information.

Attributes:

Name Type Description
center_of_mass list[float]

The center of mass value.

mass float

The mass value.

moments_of_inertia dict[str, float]

The moments of inertia value.

principal_axes dict[str, list[float]] | None

The principal axes value.

surface_area float

The surface area value.

volume float

The volume value.

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),
    )

SolidWorksModel

Bases: BaseModel

SolidWorks model information.

Attributes:

Name Type Description
configuration str | None

The configuration value.

is_active bool

The is active value.

name str

The name value.

path str

The path value.

properties dict[str, Any] | None

The properties value.

type str

The type value.

Functions
__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 == "title":
        return self.name
    if key == "units":
        return (self.properties or {}).get("units")
    return self.model_dump().get(key)