solidworks-mcp-server
Version: 
Clean Architecture SolidWorks MCP Server - Production-ready with SOLID principles
517 lines • 19 kB
JavaScript
// @ts-ignore
import winax from 'winax';
import { logger } from '../utils/logger.js';
export class SolidWorksAPI {
    swApp;
    currentModel;
    constructor() {
        this.swApp = null;
        this.currentModel = null;
    }
    connect() {
        try {
            // Create or get running instance of SolidWorks
            // @ts-ignore
            this.swApp = new winax.Object('SldWorks.Application');
            this.swApp.Visible = true;
            logger.info('Connected to SolidWorks');
        }
        catch (error) {
            // Try alternative connection method
            try {
                // @ts-ignore
                this.swApp = winax.Object('SldWorks.Application');
                this.swApp.Visible = true;
                logger.info('Connected to SolidWorks (alternative method)');
            }
            catch (error2) {
                logger.error('Failed to connect to SolidWorks', error2);
                throw new Error(`Failed to connect to SolidWorks: ${error2}`);
            }
        }
    }
    disconnect() {
        if (this.currentModel) {
            this.currentModel = null;
        }
        if (this.swApp) {
            // Don't close SolidWorks, just disconnect
            this.swApp = null;
        }
    }
    isConnected() {
        return this.swApp !== null;
    }
    // Model operations
    openModel(filePath) {
        if (!this.swApp)
            throw new Error('Not connected to SolidWorks');
        const errors = { value: 0 };
        const warnings = { value: 0 };
        // Determine file type from extension
        const ext = filePath.toLowerCase().split('.').pop();
        let docType = 1; // swDocPART
        if (ext === 'sldasm')
            docType = 2; // swDocASSEMBLY
        if (ext === 'slddrw')
            docType = 3; // swDocDRAWING
        this.currentModel = this.swApp.OpenDoc6(filePath, docType, 1, // swOpenDocOptions_Silent
        '', errors, warnings);
        if (!this.currentModel) {
            throw new Error(`Failed to open model: ${filePath}`);
        }
        return {
            path: filePath,
            name: this.currentModel.GetTitle,
            type: ['Part', 'Assembly', 'Drawing'][docType - 1],
            isActive: true,
        };
    }
    closeModel(save = false) {
        if (!this.currentModel)
            return;
        let modelTitle = '';
        try {
            // Safely get the title
            if ('GetTitle' in this.currentModel) {
                modelTitle = this.currentModel.GetTitle;
            }
            else if ('GetPathName' in this.currentModel) {
                modelTitle = this.currentModel.GetPathName;
            }
        }
        catch (e) {
            // If we can't get the title, continue anyway
            modelTitle = 'Unknown';
        }
        if (save) {
            try {
                this.currentModel.Save3(1, 0, 0); // swSaveAsOptions_Silent
            }
            catch (e) {
                // Save might fail if document is new and has no path
                try {
                    // Try Save instead
                    this.currentModel.Save();
                }
                catch (e2) {
                    // Continue even if save fails
                }
            }
        }
        // Close using app method if title is available
        if (modelTitle && modelTitle !== 'Unknown' && this.swApp) {
            try {
                this.swApp.CloseDoc(modelTitle);
            }
            catch (e) {
                // Fallback: just clear the reference
            }
        }
        this.currentModel = null;
    }
    createPart() {
        if (!this.swApp)
            throw new Error('Not connected to SolidWorks');
        // Create new part document - use NewPart() which works better
        this.currentModel = this.swApp.NewPart();
        if (!this.currentModel) {
            // Fallback to NewDocument if NewPart fails
            const template = this.swApp.GetUserPreferenceStringValue(8) || '';
            if (template) {
                this.currentModel = this.swApp.NewDocument(template, 0, 0, 0);
            }
            else {
                throw new Error('Failed to create new part - no template available');
            }
        }
        return {
            path: '',
            name: this.currentModel.GetTitle,
            type: 'Part',
            isActive: true,
        };
    }
    // Macro support methods
    createSketch(params) {
        if (!this.currentModel)
            throw new Error('No active model');
        const { plane = 'Front' } = params;
        const planeRef = this.currentModel.FeatureManager.GetPlane(plane);
        if (planeRef) {
            this.currentModel.SketchManager.InsertSketch(true);
            const sketchName = this.currentModel.SketchManager.ActiveSketch.Name;
            return { success: true, sketchId: sketchName };
        }
        return { success: false, error: 'Failed to create sketch' };
    }
    addLine(params) {
        if (!this.currentModel)
            throw new Error('No active model');
        const { x1 = 0, y1 = 0, z1 = 0, x2 = 100, y2 = 0, z2 = 0 } = params;
        const line = this.currentModel.SketchManager.CreateLine(x1 / 1000, y1 / 1000, z1 / 1000, // Convert mm to m
        x2 / 1000, y2 / 1000, z2 / 1000);
        if (line) {
            return { success: true, lineId: `line_${Date.now()}` };
        }
        return { success: false, error: 'Failed to create line' };
    }
    extrude(params) {
        if (!this.currentModel)
            throw new Error('No active model');
        const { depth = 25, reverse = false, draft = 0 } = params;
        const feature = this.createExtrude(depth, draft, reverse);
        if (feature) {
            return { success: true, featureId: feature.name };
        }
        return { success: false, error: 'Failed to create extrusion' };
    }
    // Feature operations
    createExtrude(depth, draft = 0, reverse = false) {
        if (!this.currentModel)
            throw new Error('No model open');
        try {
            // Get the feature manager
            const featureMgr = this.currentModel.FeatureManager;
            if (!featureMgr) {
                throw new Error('Cannot access FeatureManager');
            }
            // Try different extrusion methods based on what's available
            let feature = null;
            try {
                // Method 1: Try FeatureExtrusion3 with all parameters
                feature = featureMgr.FeatureExtrusion3(true, // SingleEndedFeature
                reverse, // ReverseDirection
                false, // UseDirection2
                0, // EndCondition1 (0 = blind)
                0, // EndCondition2 
                depth / 1000, // Depth1 (convert mm to m)
                0.01, // Depth2
                false, // RevOffset1
                false, // RevOffset2
                false, // ThinFeature
                draft * Math.PI / 180, // DraftAngle1 (convert to radians)
                0, // DraftAngle2
                false, // DraftOutward1
                false, // DraftOutward2
                false, // DraftWhileDrag1
                false, // DraftWhileDrag2
                false, // ReverseOffset1Dir
                true, // TranslateSurface1
                false, // NormalToCurve
                0, // StartCondition
                0, // SketchPlane
                false // FlipStartDirection
                );
            }
            catch (e) {
                // Method 2: Try FeatureExtrusion2 with fewer parameters
                try {
                    feature = featureMgr.FeatureExtrusion2(true, // SingleEndedFeature
                    reverse, // ReverseDirection
                    false, // UseDirection2
                    0, // EndCondition1
                    0, // EndCondition2
                    depth / 1000, // Depth1
                    0.01, // Depth2
                    false, // RevOffset1
                    false, // RevOffset2
                    false, // ThinFeature
                    draft * Math.PI / 180, // DraftAngle1
                    0, // DraftAngle2
                    false, // DraftOutward1
                    false // DraftOutward2
                    );
                }
                catch (e2) {
                    // Method 3: Try the simplest FeatureExtrusion
                    feature = featureMgr.FeatureExtrusion(true, reverse, 0, depth / 1000, 0, 0, true, false, false, draft * Math.PI / 180, 0, false, false);
                }
            }
            if (!feature) {
                throw new Error('Failed to create extrusion - ensure a sketch is selected');
            }
            return {
                name: feature.Name,
                type: 'Extrusion',
                suppressed: false,
            };
        }
        catch (error) {
            throw new Error(`Extrusion failed: ${error}`);
        }
    }
    // Dimension operations
    getDimension(name) {
        if (!this.currentModel)
            throw new Error('No model open');
        const dimension = this.currentModel.Parameter(name);
        if (!dimension) {
            throw new Error(`Dimension "${name}" not found`);
        }
        return dimension.SystemValue * 1000; // Convert m to mm
    }
    setDimension(name, value) {
        if (!this.currentModel)
            throw new Error('No model open');
        const dimension = this.currentModel.Parameter(name);
        if (!dimension) {
            throw new Error(`Dimension "${name}" not found`);
        }
        dimension.SystemValue = value / 1000; // Convert mm to m
        this.currentModel.EditRebuild3();
    }
    // Export operations
    exportFile(filePath, format) {
        if (!this.currentModel)
            throw new Error('No model open');
        try {
            // Ensure the model is saved first
            const currentPath = this.currentModel.GetPathName;
            if (!currentPath || currentPath === '') {
                // Save the model first if it hasn't been saved
                const docType = this.currentModel.GetType;
                const ext = docType === 1 ? '.SLDPRT' : docType === 2 ? '.SLDASM' : '.SLDDRW';
                const tempPath = filePath.replace(/\.[^.]+$/, ext);
                this.currentModel.SaveAs3(tempPath, 0, 1);
            }
            const ext = format.toLowerCase();
            let success = false;
            // Try to get export data
            let exportData = null;
            try {
                exportData = this.swApp.GetExportFileData(1); // 1 = current config only
            }
            catch (e) {
                // Export data might not be available for all formats
            }
            switch (ext) {
                case 'step':
                case 'stp':
                    if (exportData) {
                        try {
                            exportData.SetStep203(true); // Use STEP AP203
                        }
                        catch (e) {
                            // Method might not exist
                        }
                    }
                    // Try Extension.SaveAs first
                    try {
                        success = this.currentModel.Extension.SaveAs(filePath, 0, // version
                        1, // options
                        exportData, 0, // errors
                        0 // warnings
                        );
                    }
                    catch (e) {
                        // Fall back to SaveAs3
                        success = this.currentModel.SaveAs3(filePath, 0, 1);
                    }
                    break;
                case 'iges':
                case 'igs':
                    success = this.currentModel.SaveAs3(filePath, 0, 1);
                    break;
                case 'stl':
                    // STL specific - try SaveAs4 for STL options
                    try {
                        success = this.currentModel.SaveAs4(filePath, 0, // Version
                        1, // Options
                        0, // Errors
                        0 // Warnings
                        );
                    }
                    catch (e) {
                        success = this.currentModel.SaveAs3(filePath, 0, 1);
                    }
                    break;
                case 'pdf':
                    // PDF export requires drawing
                    const docType = this.currentModel.GetType();
                    if (docType !== 3) { // 3 = swDocDRAWING
                        throw new Error('PDF export requires a drawing document');
                    }
                    // Try ExportPdfData if available
                    try {
                        const pdfData = this.swApp.GetExportFileData(1);
                        success = this.currentModel.SaveAs3(filePath, 0, 1);
                    }
                    catch (e) {
                        success = this.currentModel.SaveAs3(filePath, 0, 1);
                    }
                    break;
                case 'dxf':
                case 'dwg':
                    // DXF/DWG export
                    success = this.currentModel.SaveAs3(filePath, 0, 1);
                    break;
                default:
                    // Try generic export
                    success = this.currentModel.SaveAs3(filePath, 0, 1);
            }
            if (!success) {
                // Try one more time with SaveAs2
                try {
                    success = this.currentModel.SaveAs2(filePath, 0, true, false);
                }
                catch (e) {
                    throw new Error(`Failed to export to ${format}`);
                }
            }
            if (!success) {
                throw new Error(`Failed to export to ${format}`);
            }
        }
        catch (error) {
            throw new Error(`Export failed: ${error}`);
        }
    }
    // VBA operations
    runMacro(macroPath, moduleName, procedureName, args = []) {
        if (!this.swApp)
            throw new Error('Not connected to SolidWorks');
        const result = this.swApp.RunMacro2(macroPath, moduleName, procedureName, 1, // swRunMacroOption
        0 // error
        );
        return result;
    }
    // Mass properties
    getMassProperties() {
        this.ensureCurrentModel();
        if (!this.currentModel)
            throw new Error('No model open');
        // Check document type - mass properties only work for parts and assemblies
        const docType = this.currentModel.GetType;
        if (docType !== 1 && docType !== 2) { // 1=Part, 2=Assembly
            throw new Error('Mass properties only available for parts and assemblies');
        }
        try {
            // Get the modeler extension
            const modeler = this.currentModel.Extension;
            if (!modeler) {
                throw new Error('Cannot access model extension');
            }
            // Create mass property object
            let massProps = null;
            try {
                // Method 1: Try CreateMassProperty
                massProps = modeler.CreateMassProperty();
            }
            catch (e) {
                // Method 2: Try CreateMassProperty2
                try {
                    massProps = modeler.CreateMassProperty2();
                }
                catch (e2) {
                    // Method 3: Try getting it from the model directly
                    massProps = this.currentModel.GetMassProperties();
                }
            }
            if (!massProps) {
                throw new Error('Failed to create mass property object');
            }
            // Update mass properties if method exists
            try {
                if (massProps.Update) {
                    const success = massProps.Update();
                    if (!success) {
                        // Try recalculate
                        if (massProps.Recalculate) {
                            massProps.Recalculate();
                        }
                    }
                }
            }
            catch (e) {
                // Update might not be needed
            }
            // Get the values with error handling
            const result = {};
            try {
                result.mass = massProps.Mass;
            }
            catch (e) {
                result.mass = 0;
            }
            try {
                result.volume = massProps.Volume;
            }
            catch (e) {
                result.volume = 0;
            }
            try {
                result.surfaceArea = massProps.SurfaceArea;
            }
            catch (e) {
                result.surfaceArea = 0;
            }
            try {
                const com = massProps.CenterOfMass;
                if (com && Array.isArray(com) && com.length >= 3) {
                    result.centerOfMass = {
                        x: com[0] * 1000, // Convert to mm
                        y: com[1] * 1000,
                        z: com[2] * 1000,
                    };
                }
                else {
                    result.centerOfMass = { x: 0, y: 0, z: 0 };
                }
            }
            catch (e) {
                result.centerOfMass = { x: 0, y: 0, z: 0 };
            }
            try {
                result.density = massProps.Density;
            }
            catch (e) {
                result.density = 0;
            }
            try {
                const moi = massProps.MomentOfInertia;
                if (moi && Array.isArray(moi) && moi.length >= 9) {
                    result.momentsOfInertia = {
                        Ixx: moi[0],
                        Ixy: moi[1],
                        Ixz: moi[2],
                        Iyx: moi[3],
                        Iyy: moi[4],
                        Iyz: moi[5],
                        Izx: moi[6],
                        Izy: moi[7],
                        Izz: moi[8]
                    };
                }
            }
            catch (e) {
                // Moments of inertia might not be available
            }
            return result;
        }
        catch (error) {
            throw new Error(`Failed to get mass properties: ${error}`);
        }
    }
    // Helper to ensure current model is set
    ensureCurrentModel() {
        if (!this.currentModel && this.swApp) {
            // Try to get the active document
            try {
                this.currentModel = this.swApp.ActiveDoc;
            }
            catch (e) {
                // ActiveDoc might not be available
            }
        }
    }
    // Helper to get current model
    getCurrentModel() {
        return this.currentModel;
    }
    // Helper to get SolidWorks app
    getApp() {
        return this.swApp;
    }
}
//# sourceMappingURL=api.js.map