Skip to main content
Glama

SW_MCP

Origin. SW_MCP continues solidworks-mcp by JIALE LIU (Apache License 2.0), forked at commit 6019ce0 of 2026-08-16 after upstream went quiet. On top of it: fallbacks to earlier COM method variants for older SOLIDWORKS releases (verified on 2016 SP3), sketch tooling (fully_define_sketch, entities without inferencing, origin selections, diameter dimensions, rectangles and slots from lines and arcs), list_open_documents, close_document, silent save and export, and fixes found while driving the server from an automated build pipeline. The Python package and the console script keep the names solidworks_mcp and solidworks-mcp, so existing configurations keep working. The compatibility part was offered upstream as PR #2.

An MCP server that drives a running SOLIDWORKS session over its COM API.

It does not launch SOLIDWORKS, register an add-in, execute arbitrary code, or touch the network. It attaches to a session you already have open and calls the documented API — so if a tool can't do something, neither could a macro.

123 tools: sketching with real relations and driving dimensions, the solid features you actually reach for, sheet metal with its flat pattern and DXF export, weldments from 3D sketches, reference geometry, assemblies and mates, and — importantly — a feedback channel, including screenshots returned as images so the model can see what it just built.

A sibling server, autocad-mcp, does the same for AutoCAD.


Requirements

  • Windows, with SOLIDWORKS installed and already running

  • Python 3.12

Related MCP server: solidworks-mcp

Install

git clone https://github.com/d-veloping/SW_MCP.git solidworks-mcp
cd solidworks-mcp
py -3 -m venv .venv
.venv\Scripts\python.exe -m pip install .

That puts a solidworks-mcp command in the environment, which is what the MCP host runs. uv works too, if you prefer it:

uv tool install --from git+https://github.com/d-veloping/SW_MCP solidworks-mcp

Claude Code / Claude Desktop

{
  "mcpServers": {
    "solidworks-mcp": {
      "command": "C:\\path\\to\\.venv\\Scripts\\solidworks-mcp.exe"
    }
  }
}

Codex CLI (~/.codex/config.toml)

[mcp_servers.solidworks-mcp]
command = 'C:\path\to\.venv\Scripts\solidworks-mcp.exe'

Use single-quoted TOML strings so backslashes survive. Restart the MCP host after editing its configuration.

An MCP host can also be pointed straight at a checkout, with nothing installed but the dependencies — server.py at the repository root exists for exactly that:

[mcp_servers.solidworks-mcp]
command = 'C:\path\to\.venv\Scripts\python.exe'
args = ['C:\path\to\solidworks-mcp\server.py']

Configuration

Variable

Default

Meaning

SW_MCP_OUTPUT_ROOT

~/Documents/solidworks-mcp

Every file the server writes stays under here. Paths outside it are refused.

SW_MCP_TEMPLATE_DIR

auto-discovered

Where to look for .prtdot / .asmdot / .drwdot templates if SOLIDWORKS has no default configured.

SW_MCP_DEMO_TOOLS

unset

Set to 1 to register the basketball demo tools. Off by default: a create_basketball sitting next to revolve measurably degrades tool selection.

SW_MCP_BINDING

late

How COM objects are bound: late (pywin32 dynamic dispatch, members resolved by name) or early (makepy wrappers generated from the installed sldworks.tlb, members called by dispid). Made for SOLIDWORKS Design 2026 / 3DEXPERIENCE R2026x (#26), which is still not supported. Early binding falls back to late with a warning in server.log when the type library cannot be loaded. See Supported releases.

SW_MCP_QUIET_UI

unset

Set to 1 to leave the view, the feature tree and new sketch entities undrawn for the duration of each tool call, restored and redrawn afterwards. Made for SOLIDWORKS Design R2026x, where the API crashes in slduiu.dll while sketching (#26); there it moves the crash later but does not prevent it.


The two ideas that make it usable

1. Units are explicit, always

Every length parameter ends in _mm and every angle in _deg. The COM API underneath is metres and radians; conversion happens once, at the boundary. No tool has ever silently taken metres.

2. Selection is declarative

SOLIDWORKS features read from an implicit global selection set, with per-feature "marks" deciding which selection means what. Exposing that to an agent is hopeless. Instead every tool that needs geometry takes the same selection object, and the server sets the marks:

// list_edges first, then:
{ "selection": { "edges": [4, 6, 9] } }
{ "selection": { "face_edges": [2] } }        // every edge of face 2
{ "selection": { "planes": ["front"] } }
{ "selection": { "sketch_segments": [0, 1] } }
{ "selection": { "points": [{ "x_mm": 30, "y_mm": 0, "z_mm": 20, "type": "FACE" }] } }

Indices come from list_faces / list_edges / list_vertices / list_sketch_segments and describe the current model state — re-list after any geometry change. Under the hood, selection resolves to a point that provably lies on the entity and picks by 3D coordinate, which survives the fact that late-bound Python cannot QueryInterface a Face2 to IEntity.


Tools

Session and documents

Tool

Purpose

solidworks_status

Verify the connection; report version and active document.

get_active_document_info

Title, path, type, unsaved state (dirty, null when it cannot be read).

create_new_document

New part / assembly / drawing. Without template_path from the default template set in SOLIDWORKS for the kind (Tools > Options > Default Templates), or, when none is set or it names no existing file, from one found on disk (SW_MCP_TEMPLATE_DIR first, then the usual SOLIDWORKS template folders); with template_path from exactly that template (absolute path, existing file, extension fitting the kind; anything else creates nothing). Reports the file handed to SOLIDWORKS as template and template_source (argument, preference, discovered).

open_document

Open a .sldprt / .sldasm / .slddrw and wait until it is the active document; reports the opened document and already_open (was the file open before the call).

list_open_documents / close_document

Every open document with title and path; close one without saving, with only_if_clean only if it has no unsaved changes.

activate_document

Activate the open document with exactly this title and wait until it is active; for a caller that created the document itself and lost the focus. Activates nothing for an unknown, duplicate or unreadable title.

save_document / save_active_document

Save-as under the output root (a part also as .sldlfp holding all its 2D sketches, e.g. a weldment profile) / save in place.

export_document

STEP, IGES, STL, Parasolid, 3MF, an image of the current view, or PDF of a drawing (every sheet, vector, true sheet size; an image of a drawing is only a window-sized capture).

rebuild_document

Rebuild and report failing features.

set_appearance / set_material

Display colour; real material (so mass properties mean something).

Reference geometry

list_reference_planes, create_plane (offset / angle / midplane / three points / parallel-through-point), create_axis.

Sketching

create_sketch (on a plane or a model face), edit_sketch, close_sketch, list_sketches, list_sketch_segments, get_sketch_status.

Geometry: draw_line, draw_centerline, draw_circle, draw_rectangle, draw_arc, draw_3point_arc, draw_ellipse, draw_polygon, draw_slot, draw_point, draw_spline.

Editing: sketch_fillet, sketch_chamfer, sketch_trim, sketch_offset, sketch_mirror, convert_entities, set_construction_geometry.

Parametrics: add_relation, add_dimension, set_dimension, list_dimensions.

set_dimension with parentheses shows a model dimension's value in parentheses (true) or clears them (false), alone or together with a value or diametric. It sets IDisplayDimension.ShowParenthesis and counts only what the same object reads back: a refused, raising or unreadable state is ok: false, nothing after it is written, and the dimension keeps its value. Its answer reports the parentheses, driven and the value before and after the change; only the parentheses decide ok. A drawing copies the parentheses when insert_model_annotations brings in the model dimensions and keeps them when the model changes afterwards (measured on 2016 SP3, d-veloping/ClauSW#156), so set them before the drawing is made.

draw_hole_circle draws the seed of a centred bolt-hole pattern in the open, empty sketch in one call: a construction pitch circle around the origin, one hole on it at start_angle_deg, a construction radius line and, off the quadrants, a construction reference line along +x, with the relations and the named diameter dimensions (Lochkreis, Bohrung) and, off the quadrants, an angle dimension (Startwinkel). The angle dimension is unsigned: above 180 degrees it reads 360 minus the angle, and the hole stays where asked (measured on 2016 SP3 for 15, 105, 195, 285 and 330 degrees, with changes of the angle and the pitch in the open and the closed sketch). Line ends drawn on a circle centre share its sketch point, so those coincidences are checked by point ID, not by a relation. The call is ok only when every relation and dimension is confirmed, the sketch carries exactly these driving dimensions and is fully_defined; otherwise it stops at the failed step and leaves the sketch open as it is. Pattern the cut with circular_pattern.

Features

boss_extrude, cut_extrude, revolve, fillet, chamfer, shell, draft, rib, simple_hole, hole_wizard, sweep, loft, linear_pattern, circular_pattern, mirror_feature, delete_feature, rename_feature, set_feature_suppression.

hole_wizard drills standard holes with the Hole Wizard (IFeatureManager.HoleWizard5), one feature for one or more holes on one planar face:

  • Inputs: kind (clearance, tapped, counterbore, countersink), standard (iso, din, ansi_metric, …), fastener (the Toolbox table name as the Hole Wizard lists it: Screw Clearances, Tapped hole, Hex Socket Head ISO 4762, Hex Socket CTSK Head ISO 10642, …), size as the table lists it (M6, not M6x1.0), end_condition (through_all, or blind with depth_mm to the drill shoulder), fit (close, normal, loose; default normal; not for tapped holes), for tapped holes thread_depth_mm and cosmetic (default true), the face as face_index (from list_faces) or face_point_mm, points (hole centres in model millimetres on the face's plane, at least one) and an optional name.

  • Checks before anything is built: the fastener table must exist in the Toolbox database for that standard, offer that kind of hole and list that size; otherwise the answer names the tables or sizes that do exist. This matters: HoleWizard5 builds a feature for a size the table does not offer rather than refusing it. Every point must lie on the face's plane.

  • Outputs (ok: true): feature (the name HoleWizard5 returned, never one guessed from the tree), position_sketch, type (swWzdHoleTypes_e value and name), hole_data (the kind's IWizardHoleFeatureData2 fields in mm and degrees, e.g. ThruHoleDiameter_mm, TapDrillDepth_mm, ThreadDepth_mm, CosmeticThreadType, CounterBoreDepth_mm, CounterSinkDiameter_mm, CounterSinkAngle_deg, HoleFit), points_mm (read back from the feature), volume_before_mm3, volume_after_mm3, removed_mm3, bodies and the subfeatures (a cosmetic thread shows up as CosmeticThread).

  • ok only after the readback: the feature's own data must report the requested fastener, size, end condition, blind depth, fit or thread depth and cosmetic type, one hole per requested point, no rebuild errors, a smaller solid volume and the same body count. HoleWizard5 never says why it failed (it returns nothing), so every failure is judged from the model: the answer is ok: false with the reason, and every feature the call added is deleted again (deleted, left_behind).

Limits, measured on SOLIDWORKS 2016 SP3 (d-veloping/SW_MCP#40, d-veloping/ClauSW#253):

  • Only the standards and sizes of this machine's Toolbox database (swbrowser.sldedb in the Hole Wizard/Toolbox folder configured in SOLIDWORKS; 2016 SP3 reports C:\SOLIDWORKS Data\lang\english). Values come from that table and may differ from what you expect (ISO 4762 M6: counterbore depth 6.4, not 6.5); the tool reports what SOLIDWORKS built. Only ISO is checked live.

  • Threads are cosmetic or absent (cosmetic: false), never cut; the volume is the tap drill only.

  • Feature names are English and built from the table (M6 Clearance Hole1, CBORE for M6 Hex Socket Head Cap Screw1); rename with name.

  • The position sketch stays. The tool draws the hole centres as points in a sketch on the face (no inference snapping) and preselects them; the Hole Wizard copies them into its own sub-sketches (3DSketchN, SketchN), but the hole stays tied to the position sketch, which remains in the tree in front of it. Deleting that sketch leaves the hole feature in the tree cutting nothing, without a rebuild error.

  • A blind clearance hole, counterbore or countersink reads back in HoleDiameter/HoleDepth (the depth to the drill shoulder), a through one in ThruHoleDiameter/ThruHoleDepth; a blind tapped hole in TapDrillDepth. The clearance hole's drill angle is passed as -1 (the standard's 118 degrees): 0 builds a 0-degree tip that removes far too much material, again without any error.

  • No hole callouts: insert_model_annotations with hole_callouts places them in a drawing.

Sheet metal

Tool

Purpose

sheet_metal_base_flange

First sheet metal body from a sketch: an open chain of lines is thickened and extruded (each corner a bend), a closed outline becomes a plate. Sets thickness and bend radius for the part.

sheet_metal_edge_flange

Flange along one or more straight edges, with angle, length from the inner virtual sharp, bend position, radius and relief. The profile sketch is drawn for you.

sheet_metal_miter_flange

Profile sketch swept along connected edges with mitred corners, rip gap and optional start/end offsets.

sheet_metal_hem

Closed, open or rolled hem on selected edges.

sheet_metal_closed_corner / sheet_metal_break_corner

Close the corner between two flanges (butt / overlap / underlap with a gap, read back); fillet or chamfer the corners of a sheet edge.

sheet_metal_corner_relief

Square, circular, obround, tear, bend-waist or constant-width relief where two bends meet, one or more corners per feature.

sheet_metal_flatten

Unsuppress / suppress the Flat-Pattern feature and report the flat bounding box (single-body parts).

sheet_metal_info

Thickness, bend radius, K-factor, relief, bend state, and every sheet metal feature with its bends.

export_flat_pattern

Flat pattern as DXF or DWG with bend lines, without a dialog; a DXF result is summarised (entities, bend lines, extents when the file is in millimetres).

Every feature-creating tool here is judged by geometry, never by the API's return value: it reports the body volume and bounding box after the feature, because several of the sheet metal API calls raise on return even when they have built the feature, and others return nothing at all when they have not. What a tool asked for is held against the feature's own readback (thickness, bend radius, hem length, corner type and gap, ...), a feature that removes material must have removed some, and a mismatch is ok: false with the feature still in the tree under its reported name, so the caller can inspect it or hand it to delete_feature. Only the leftovers of a call that built nothing are removed again: a 3D sketch whose lines did not all appear, the profile sketches of a failed edge flange, a Weldment feature added for a member that was refused. The boxes of the sheet metal, weldment and list_bodies results come from IBody2::GetExtremePoint (six calls per body, exact on the geometry; for a rotated assembly component list_bodies transforms the two corners, which is exact only without rotation); get_bounding_box keeps GetPartBox, which SOLIDWORKS documents as approximate, so it is for orientation, not for a check, unless it is called with exact: true, which takes the extreme points of every solid body, hidden ones included. sheet_metal_flatten and export_flat_pattern take single-body sheet metal parts only.

Weldments

Tool

Purpose

create_3d_sketch

Straight lines between model-space points, closed as one 3D sketch; the path for structural members.

list_weldment_profiles

Standard / type / size of every .sldlfp profile in the configured folders and the install. An own profile is a part with one sketch of closed contours (outline and holes) around the origin, which is the insertion point, saved with save_document as <standard>/<type>/<size>.sldlfp; pass its path as profile_path, or add its root folder under Tools > Options > File Locations > Weldment Profiles to list it.

weldment_structural_member

A library profile swept along connected sketch segments, one body each, corners mitred or butted; adds the Weldment feature when needed. Reports each body's volume and box.

weldment_end_cap

Plate over the open end of a member, inset by a wall-thickness ratio or a distance, optionally chamfered or inward (the member is cut back); one new body per selected face, every option held against the readback.

weldment_trim_extend

Trim members flush against other bodies (butt / miter) or cut them at faces and reference planes (trim), with coped cut and weld gap; butt and miter take one member against one body, only trim takes several; reports the trimmed bodies' new boxes and volumes and refuses to call an unchanged model a success.

weldment_gusset

Triangle or polygon gusset plate between two supporting faces, thickness inner / outer / both sides, plane at start / centre / end of the corner.

Inspection — the feedback channel

Tool

Purpose

capture_screenshot

Returns the view as an image, so the model can look at its own work.

list_faces / list_edges / list_vertices / list_bodies

Topology with types, sizes, and selection indices; cylinders with axis, a point on it, radius and concave (true when the material lies outside, as for a bore; null when unreadable). Filterable by surface type, area, normal direction, curve type, length. Bodies come with their own volume and the sum.

get_mass_properties / get_bounding_box / measure

Numbers to check the geometry against.

check_errors

What SOLIDWORKS thinks is wrong — see below. With sketches: true also every sketch the solver cannot solve, which SOLIDWORKS never flags itself.

set_view

Named view plus zoom-to-fit.

Assemblies

list_components, insert_component, add_mate, list_mates, set_component_fixed.

Engineering drawings

create_drawing, list_sheets, add_sheet, activate_sheet, insert_standard_views, insert_model_view, insert_projected_view, insert_section_view, insert_detail_view, delete_drawing_view, list_drawing_views, activate_drawing_view, create_drawing_sketch, set_drawing_view, insert_model_annotations, auto_dimension_view, insert_center_marks, insert_centerlines, add_note, list_drawing_dimensions, hide_drawing_dimensions, arrange_drawing_dimensions, check_dimension_attachments, set_sheet_format, set_dimension_style, move_dimension_text, list_view_arcs.

insert_standard_views, insert_model_view, insert_projected_view and set_drawing_view take display_mode: hidden_lines_removed (SOLIDWORKS' default), hidden_lines_visible (hidden edges dashed, so bores and steps show without a section), wireframe, shaded, shaded_with_edges. The style counts as applied only when it reads back from the view; otherwise the tool returns ok: false with the style each view ended up in. insert_standard_views applies it only to the views it places. A scale on insert_model_view or set_drawing_view counts the same way: it must read back from the view.

Every drawing tool (sw_drawing, all but create_drawing) takes an optional document (the drawing's title). When another document is active, the call is refused with ok: false and active_document, and nothing is changed; the check runs in the same call. A read SOLIDWORKS refuses where the answer proves something (the view chain, cutting lines, the dimension walk) fails the call instead of counting as "none there". A dimension whose model dimension cannot be read is listed with readable: false; one whose visibility or drawing layer cannot be read with visible: null: it may be hidden, counts for no duplicate, and arrange_drawing_dimensions arranges no view that has one.

insert_section_view takes the cutting line as two sheet points or as a model point it passes through (through_model_mm) plus direction, and draws it in the parent view's own sketch, whose coordinates are (sheet - view position) / view scale, not sheet millimetres. Drawn at sheet coordinates the line lies beside the part and SOLIDWORKS still creates a "section view" that cuts nothing (issue #2). The tool succeeds only when the new view is a section with hatched faces; otherwise it deletes the view and its cutting line again and returns ok: false. When SOLIDWORKS returns no view at all, the call fails and the line it drew may remain in the parent (parent_section_lines is read back). The parent must not be rotated; an unreadable position, scale or angle fails the call. delete_drawing_view removes a section view together with its cutting line, which SOLIDWORKS otherwise leaves in the parent. Deletions are read back: DeleteSelection2 also answers true for what stays, so removed and line_removed say what is gone from the drawing afterwards. insert_detail_view converts its circle the same way. list_drawing_views reports each view's outline, hatched faces, section lines and the transform from model to sheet millimetres.

insert_model_annotations puts the same model dimension into several views, also with duplicate_dimensions: false and also when called view by view (measured on 2016 SP3: 3 to 41 duplicates per part). list_drawing_dimensions lists every visible dimension of every sheet (not those hidden or on a hidden layer) with its sheet, view, layer, model dimension and text position and names the duplicates within a sheet. The value key follows the model dimension's kind: value_mm for a length, value_deg for an angle, value for an integer such as a pattern count. hide_drawing_dimensions hides a list of them in one selection and one call (the part stays unchanged), and arrange_drawing_dimensions auto-arranges one view's dimensions, all or none, and reports how many texts moved. Both activate the view's sheet for that and the previous sheet again afterwards. A section label already used on the sheet is refused. A dimension is selected by its selection name: IAnnotation.Select3 does not select drawing dimensions.

check_dimension_attachments tells, for one view, which dimensions point into the void: their measured points (IDimension.ReferencePoints, model space, mapped onto the sheet) lie on an edge of the part's solid bodies, projected like the view, but on none the view draws with hidden lines removed — a bore depth or an inner step seen from outside, the case for a section view. Dimensions that are hidden or sit on a hidden drawing layer are left out, as in list_drawing_dimensions; one whose visibility or layer cannot be read is checked with visible: null and counted in visibility_unknown. The view is set to hidden lines removed for the reading, then back, and read back. The edges come from the bodies because a view placed without hidden lines keeps listing only its visible edges after a switch to hidden lines visible (2016 SP3). Silhouette edges are not read: ISilhouetteEdge.GetCurve and GetStartPoint raise RPC_E_SERVERFAULT inside SOLIDWORKS 2016, and the part could not be closed afterwards. An edge whose curve, end points, centre or tessellation cannot be read or is not finite is counted in edges.unreadable (model) or edges.unreadable_shown (drawn). An open edge whose tessellation comes back empty counts as its chord, a closed one as unreadable; a dimension whose verdict such an edge could change gets into_void: null, as does one whose points cannot be read, never false. An empty edge list, from the view or from the bodies, fails the call. The bodies are those of the part's active configuration, so a view of another configuration is not checked correctly. The display mode is set back with the view's own style: a view that followed its parent's style keeps the same mode afterwards, but as its own.

set_sheet_format puts a sheet format file (.slddrt, border and title block) on a sheet with a standard paper_size and the projection (first_angle), keeping the sheet's scale (SetupSheet5 with a custom template). It reads back the template path (GetTemplateName, compared case-insensitively), the sheet size (within 0.5 mm of the paper size), the projection and the scale, and succeeds only when SetupSheet5 returned true and all of them match. A missing file, a relative path or one that is not a .slddrt is refused before anything is called; a sheet that cannot be read back after SetupSheet5 fails the call with setup_returned. The file is used in place; in the live check SOLIDWORKS did not change it (size and modification time), and views and dimension texts stayed where they were (2016 SP3, 2026-11-01).

set_dimension_style, move_dimension_text and list_view_arcs work on one view of the active sheet (view_name); the first two name each dimension by the full_name that list_drawing_dimensions reports, and a dimension shown more than once in that view, or not at all, is not touched and fails its entry, as is every dimension of a view that holds an unreadable one (it could be the same dimension once more). set_dimension_style sets only the properties passed, shortened_radius (IDisplayDimension.ShortenedRadius, the foreshortened radius with a jogged leader) and solid_leader (SolidLeader, the leader as one solid line; false draws it from the arc to the text only), and reads both back after a rebuild: an entry succeeds when each property passed reads as asked and the other one, if it was readable before, reads back unchanged; a property passed that the release does not take or read gives the entry an error. move_dimension_text sets each text to a sheet position in mm (IAnnotation.SetPosition) and reads it back with GetPosition; an entry succeeds within 0.5 mm. Both succeed only when every entry does; when the dimensions cannot be read again after the change, the call fails, says the change was made, and carries the entries. Where a text should go is the caller's decision; the tool only places and checks it. Changing a style can move a text (switching shortened_radius on moved a radius text by up to 22 mm on 2016 SP3), so set the style first and move the text afterwards. SOLIDWORKS also keeps a radius text on the ray from its centre at a distance of its own choosing in some cases (with shortened_radius on and the position asked for inside the arc it landed 31.5 mm away); the move then fails with the position read back.

list_view_arcs lists the circles and arcs a view draws in true shape (circle axis along the view direction): centre, radius on the sheet (scale applied), the point at half the arc's length and the tessellated points, all in sheet mm. It reads only edges (GetVisibleEntities2 with edges, never silhouette edges, see above) and counts every drawn edge: oblique for circles seen at an angle, unreadable for edges whose curve, circle or tessellation cannot be read. An empty arcs with unreadable: 0 means the view draws no circular edge in true shape among the edges the view lists; a view switched to hidden lines visible may still list only the edges it showed before (see above), so dashed circles can be missing. A view that lists no edge at all fails the call. list_drawing_dimensions gives each dimension its measured points on the sheet, reference_points_mm (IDimension.ReferencePoints through the view's model transform), or null when they cannot be read, never an empty list.

insert_center_marks marks holes, fillets and slots by default; fillets: false leaves out fillets and other arcs (not used with selected_only). Its ok is SOLIDWORKS' answer to AutoInsertCenterMarks2: which edges got a mark is not read back.

For hand-made section and detail views, call create_drawing_sketch after activating the parent view, then use the normal draw_line or draw_circle sketch tools; their coordinates are the view sketch's, as above.


A worked example

create_new_document   { "kind": "part" }
create_sketch         { "plane": "front", "name": "Base" }
draw_rectangle        { "x1_mm": 10, "y1_mm": 10, "x2_mm": 70, "y2_mm": 50 }
add_dimension         { "selection": { "sketch_segments": [0] }, "kind": "horizontal",
                        "value_mm": 80, "place_x_mm": 40, "place_y_mm": -10 }
add_dimension         { "selection": { "sketch_segments": [1] }, "kind": "vertical",
                        "value_mm": 50, "place_x_mm": -10, "place_y_mm": 30 }
close_sketch          {}
boss_extrude          { "depth_mm": 20, "name": "BasePad" }

list_edges            { "curve_type": "line", "min_length_mm": 19 }   // find the four verticals
fillet                { "radius_mm": 5, "selection": { "edges": [0, 1, 2, 3] } }
shell                 { "thickness_mm": 2, "selection": { "faces": [4] } }

capture_screenshot    { "view": "isometric" }
get_mass_properties   {}

Notes from the implementation

These are the things that cost real time. They are documented because anyone automating SOLIDWORKS from Python will hit them.

SOLIDWORKS members are inconsistently exposed to pywin32. Most are declared in the type library as PROPGET with arguments. Late-bound pywin32 may resolve such a member on plain attribute access by invoking it with no arguments. IBody2.GetFaces then returns a bound method that looks like a one-element result — which is why an extruded box reported exactly one face. Worse, ModelDocExtension.AddDimension invoked that way crashes SOLIDWORKS outright. sw_core.flag_methods() calls _FlagAsMethod on every member the server invokes with arguments, and sw_core.value() invokes zero-argument callables rather than returning the method object.

Modal dialogs deadlock the server. AddDimension2 pops the "Modify" box whenever Input dimension value is enabled — which is the default. A modal dialog blocks the COM call that opened it, and with it the whole server, until somebody clicks. Dimension tools turn the preference off and restore it after. If a tool ever hangs, look for a dialog behind the SOLIDWORKS window.

Return values lie. SketchTrim returns False on success. The Create* sketch APIs return arrays whose truthiness is unreliable. SketchAddConstraints takes a magic string and silently ignores one it does not recognise. So the drawing tools judge success by the sketch's segment count, sketch_trim by whether the sketch actually changed, and add_relation uses the typed ISketchRelationManager.AddRelation and verifies via the relation count — and on failure reports which relations that selection would accept.

Most failures are silent. SOLIDWORKS returns null far more often than it raises. Every feature tool therefore rebuilds and reports ModelDocExtension.GetWhatsWrong, and check_errors exposes it directly.

A sketch that cannot solve is not an error to SOLIDWORKS. SetSystemValue3 stores a dimension value the solver then rejects: the sketch is left no_solution, nothing moves, the rebuild returns true and GetWhatsWrong is empty. So set_dimension reads the value back after the rebuild (it reverts to the old one) and reads the owning sketch's GetConstrainedStatus, which works on a closed sketch, and fails on either signal. add_dimension does the same for a new dimension in the open sketch: it fails when a requested value does not read back, when the sketch is left (or already was) unsolved, and when the sketch's state cannot be read (verified: false). A new dimension that would over-define the sketch, a duplicate say, is not refused either: SOLIDWORKS creates it driven, a reference dimension, and the sketch still solves. So add_dimension also reads the new dimension's DrivenState and fails on driven: true, and on a state it cannot read (driven: null, verified: false). The new dimension stays in the sketch in those cases, named by full_name. One exception: with diametric: true a dimension whose Diametric display does not read back true gets no value and is deleted again (removed), because SOLIDWORKS 2016 refuses that display for a line measured to a centerline and the value would land as the plain distance; set_dimension with diametric likewise writes no value when the display does not switch. check_errors reads the same state for every sketch when asked with sketches: true; that is one pass over the feature tree, so it is off by default. Measured on 2016 SP3.

sketch_trim needs its target selected. Pass the segment in selection; the point alone only tells SOLIDWORKS which piece to discard.

Multi-reference features want distinct marks. InsertRefPlane reads its first, second, and third reference from marks 0, 1, 2 — not from selection order. Selecting all of them with mark 0 silently produces nothing, which is why create_plane selects each reference with its own mark and documents that references are consumed in written order.

Two unit traps. IPartDoc.GetPartBox(False) returns document units, not metres, so it reads 1000x large if you treat it like the rest of the API; pass True. And swSketchLINE is 0, so folding a segment type through or turns every line into "unknown".

Known limitations

  • One SOLIDWORKS session, one COM apartment: tool calls are serialised. Two clients driving the same session at once will deadlock it.

  • Snapshot indices from list_faces / list_edges are invalidated by any geometry change. Re-list; do not cache.

  • A modal dialog opened by SOLIDWORKS for any other reason will still block the server until dismissed.

  • The sheet metal tools work on single-body sheet metal parts. A multibody sheet metal part has one Flat-Pattern feature per body; sheet_metal_flatten and export_flat_pattern refuse such a part instead of reporting one body as the whole.

  • rib is picky about its profile. InsertRib returns void and simply builds nothing unless the open profile reaches material at both ends and the extrusion direction can get there. The tool defaults to parallel_to_sketch (right for a cross-section profile) and retries the other direction automatically, reporting which one worked. A profile that overlaps an existing rib still fails, and the tool says so rather than pretending.

  • CreateUnfoldedViewAt3 projects from the selected view. With the parent only activated, the first projection off it succeeds and every further one returns nothing; insert_projected_view therefore activates and selects the parent before every projection, so several projections off one parent work.

  • Detail-view scale is absolute (model to paper), not relative to the parent. On a 1:4 sheet, 2:1 makes the detail eight times the parent view and it overflows the sheet. Pick a scale near the sheet scale.

  • Standard-plane and model-view display names are localized. Use front, top, and right for reference planes, and use names returned by list_drawing_views for drawing views; do not hard-code English UI labels.

  • through_all_both is translated internally to a two-direction feature with through_all in both directions. Passing swEndCondThroughAllBoth as a single-ended feature silently cuts only one side in SOLIDWORKS 2026.

  • circular_pattern cannot pattern a feature that built a separate body (merge: false) — SOLIDWORKS rejects the feature scope. Merge the body, or pattern the body instead.

  • save_document cannot overwrite a file SOLIDWORKS currently has open, even with overwrite: true. The error says so when that is the cause.

  • A .sldlfp holds only the features selected when it is saved; saved with nothing selected it carries no profile, and a structural member with it fails (measured on 2024 SP3). save_document therefore selects every 2D sketch of the part before it saves a .sldlfp.

  • Sheet metal (measured on 2016 SP3): the K-factor cannot be changed through the API — ISheetMetalFeatureData and ICustomBendAllowance accept the value and keep the document default — so sheet_metal_info reports what the flat pattern actually uses. tear_drop and double hems are not accepted. With the profile this tool draws, InsertSheetMetalEdgeFlange2 builds the same flange whatever dimension type it is given: the outer virtual sharp reads back length + t·tan(angle/2) for the same geometry, and the bend tangent builds nothing; so sheet_metal_edge_flange offers no length reference and measures from the inner virtual sharp. Options that the feature definitions do not read back on 2016 (all measured 2026-10-08), which are therefore passed and left to the geometry: flip and relief_type of the edge flange, trim_side_bends of the miter flange, depth_mm of the base flange, position of the hem, every parameter of the corner relief (its feature has no definition at all), gap_mm and coped_cut of the trim, thickness_direction and location of the gusset. The end cap's reverse flag is not offered: it reads back as set and moves nothing. export_flat_pattern needs a saved part, because ExportToDWG2 takes the model path; ExportFlatPatternView is not used because it opens a file dialog. A gauge table is refused on this install's templates (SetUseGaugeTable answers "not enabled on template"), and the 2016 material database carries no sheet metal parameters, so neither route sets the K-factor either.

  • Weldments: weldment_trim_extend against a body shortens the trimmed member and grows the trimming member by the same amount, whatever the API's extension option bits say (measured with every combination on 2016), so the part's get_mass_properties does not move and the tool offers no extension switch; list_bodies and the weldment tools report each body's own volume for that reason (the part total is the plain sum of its bodies, overlaps included: two 20 x 20 x 10 boxes overlapping by half report 8000 mm³). The gusset's weld-bead chamfer and sketch-plane offset arguments of InsertGussetFeature3 are accepted and change nothing on 2016, so weldment_gusset does not offer them.

Testing

The useful tests are live SOLIDWORKS tests: the COM behaviour that matters here cannot be mocked faithfully. tools\check.ps1 is the one way to run the check: the server import and the offline tests as in CI, then the live checks one after another, with SOLIDWORKS already running. It stops at the first red step and exits non-zero, so chain the commit on it:

# Windows PowerShell 5.1 (no &&)
powershell -NoProfile -ExecutionPolicy Bypass -File tools\check.ps1; if ($LASTEXITCODE -eq 0) { git commit }

Start it as its own powershell process, as above, rather than as .\tools\check.ps1: a script the execution policy blocks leaves $LASTEXITCODE at its previous value, which may well be 0.

# cmd, Bash, PowerShell 7
powershell -NoProfile -ExecutionPolicy Bypass -File tools/check.ps1 && git commit

The forward slash is deliberate: Bash would swallow the backslash of tools\check.ps1.

Never pipe the check into another command (... | tail): the exit code that counts is then the last command's, and a red live test no longer stops the commit (in Bash only set -o pipefail changes that). -Offline skips the live checks on a machine without SOLIDWORKS, -Python names another interpreter (for a worktree without its own .venv), -SelfTest checks the exit codes of the check itself without SOLIDWORKS. Every tests\live_*.py is either run by the check or listed in it with the reason it is not (measurements that always exit 0, checks that need a saved part as argument); an unlisted one fails the check. If other processes drive the same SOLIDWORKS, run the live part only while you hold their lock.

tests\live_p0_regression.py verifies the P0 geometry/constraint regressions, including the full-volume through_all_both cut. tests\live_sheet_metal.py builds an L profile and a plate with every sheet metal tool and checks the flanges, the flat pattern and the break corner against a closed-form number: flange volumes, the developed length from the K-factor, the material a break corner removes, the bend lines in the exported DXF; the hem, the closed corner and the corner relief are checked by readback, added or removed material and the DXF (32 checks on 2016 SP3, plus 11 for the third part). tests\live_weldment.py does the same for weldments: members measure profile area times length and reach the mitred outer corner, the end cap its inset plate, the trimmed member its new length, the gussets abt/2 with their leg lengths and the polygon with its corner cut, a plane cut into two halves, and a degenerate 3D line leaves no sketch behind; a second pair with butt corners, a turned and mirrored profile and a gap, and end caps with ratio inset and chamfer (volume), and inset by distance and inward (the plate ends flush inside, the recut member is reported), are checked by readback and geometry (41 checks). A third sheet metal part checks an edge flange and a miter flange with every option off its default by readback and reach.

tests\live_template_path.py checks the template create_new_document uses: exactly the file named in template_path, unusable paths creating nothing, and without template_path a part, an assembly and a drawing each from the default template set in SOLIDWORKS for its kind (swDefaultTemplatePart/Assembly/Drawing = 8/9/10), reported as preference (2026-11-09, 2016 SP3: all three from the configured default templates, 28 checks).

Every tool except the 16 sheet metal and weldment tools, activate_document and set_sheet_format, set_dimension_style, move_dimension_text and list_view_arcs (measured on 2016 SP3 only) has been exercised against SOLIDWORKS 2026 SP3.2 on a Simplified Chinese install. Where a result could be checked numerically it was: the revolved ring, swept rod and lofted cone match their closed-form volumes; a 5-degree draft removes exactly the expected wedge; rib produces exactly the triangle under its profile; through_all_both removes the full cylinder rather than half of it. The limitations above are what survived that pass.

Older releases work too, back to at least SOLIDWORKS 2016 SP3, where every tool was exercised the same way on a German install. Where a release lacks the newest numbered method (FeatureCut4, FeatureLinearPattern5, CreateDetailViewAt4, ...) the tool falls back to the earlier variant with the arguments it takes; on newer releases the newest name is always tried first, so nothing changes there. The sheet metal and weldment tools are the exception in both directions: they were measured on 2016 SP3 only (tests\live_sheet_metal.py, tests\live_weldment.py), have not been run against 2026, and call the API names that build on 2016 (InsertSheetMetalBaseFlange, InsertSheetMetalHem, InsertStructuralWeldment4, InsertEndCapFeature3, ...) without a newest-name-first fallback.

Supported releases

Release

Binding

State

SOLIDWORKS 2016 SP3 (desktop, German)

late (default)

every tool measured

SOLIDWORKS 2026 SP3.2 (desktop, Simplified Chinese)

late (default)

every tool except sheet metal, weldments, activate_document and the four 2016-only drawing tools above measured

SOLIDWORKS Design 2026 (3DEXPERIENCE R2026x, German)

not supported

late binding fails on the first sketch member; with early and SW_MCP_QUIET_UI=1 (SP4.0) a sketch rectangle is drawn, then SOLIDWORKS crashes in slduiu.dll during close_sketch (#26)

Late binding is pywin32's dynamic dispatch: every member is resolved by name on the object's default interface. Early binding (solidworks_mcp/sw_binding.py) has makepy generate wrapper classes from the installed sldworks.tlb into pywin32's gen_py cache (%TEMP%\gen_py\<python version>, a few seconds on the first attach, imported afterwards) and calls every member by dispid through the interface that declares it; where the type library declares a bare IDispatch (ActiveDoc, FirstFeature, arrays of bodies, faces and segments), the object is asked which of the declaring interfaces it implements. A failed early attach (type library not registered, generation failed) falls back to late binding with one warning in server.log, so the connection never depends on it.

The mode is set, not detected: a dispatch without type information is not a usable signal, since GetTypeInfo fails on the 2016 SP3 application dispatch too, where late binding works.

Late binding stays late when a gen_py cache of sldworks.tlb exists (#27). Such a cache is shared by every pywin32 process of the same Windows user; makepy, EnsureDispatch and SW_MCP_BINDING=early all write to it. Once it exists, GetActiveObject returns the generated SldWorks class, and the server wraps it dynamically again. Other pywin32 tools of the same user that drive SOLIDWORKS without binding explicitly are not protected: do not generate the cache on a machine where such a tool runs, or move it aside afterwards.

Layout

Module

Contents

sw_core.py

COM attachment, units, feature tree, topology enumeration, selection engine, tool registry

sw_file.py

Session status, documents, saving, exporting, appearance, material

sw_refgeom.py

Reference planes and axes

sw_sketch.py

Sketches, geometry, editing, relations, dimensions

sw_feature.py

Solid features

sw_sheetmetal.py

Sheet metal features, flat pattern, DXF/DWG export

sw_weldment.py

3D sketches, structural members, end caps, trim/extend, gussets

sw_inspect.py

Topology listings, measurement, mass properties, screenshots

sw_assembly.py

Components and mates

sw_drawing.py

Sheets and sheet formats, views, model items, dimensions and their style, arcs, center marks, notes

sw_demo.py

Basketball demo, opt-in via SW_MCP_DEMO_TOOLS

tests/live_p0_regression.py

Live regression checks for the confirmed P0 part/sketch defects

tests/live_sheet_metal.py

Live sheet metal checks against closed-form geometry

tests/live_weldment.py

Live weldment checks against closed-form geometry

tools/check.ps1

The one check: server import, offline tests, live checks; exits non-zero on the first red step

tools/tlb_probe.py

Reads signatures and enums straight off your installed type library

server.py

Registry assembly and stdio dispatch

tools/tlb_probe.py is worth knowing about before you add a tool. The published API reference disagrees with the shipped type library often enough to matter — FeatureFillet3 takes 14 arguments here, not the documented 7 — so check first:

python tools/tlb_probe.py methods '^IFeatureManager$' '^FeatureFillet3$'
python tools/tlb_probe.py enums '^swMateType_e$'

Adding a tool means writing one decorated function; the registry does the rest.

@tool("my_tool", "What it does. Lengths are millimetres.",
      {"depth_mm": {"type": "number"}}, ["depth_mm"])
def my_tool(args: dict[str, Any]) -> dict[str, Any]:
    _, doc = require_part()
    ...
    return result(True, "Did the thing.")

License

Apache License 2.0 — see LICENSE. Copyright 2026 JIALE LIU; modifications Copyright 2026 Christian Dengler (d-veloping), see NOTICE.

Use it, change it, ship it in a commercial product; that is all allowed. What the license does require, if you redistribute this or anything derived from it, is that you keep the copyright notices, pass on a copy of the NOTICE file, and state which files you changed.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      A
      maintenance
      Enables AI agents to control a running SOLIDWORKS session through its COM API, with tools for sketching, feature creation, assemblies, and visual feedback via screenshots.
      22
      Apache 2.0
    • F
      license
      Not graded
      quality
      D
      maintenance
      Enables control of a live SOLIDWORKS session through the Windows COM API, providing native sketch, feature, body, reference-geometry, view, probe, and export operations, along with transactional CAD plans, parametric sketches, multibody tools, and deterministic raster-to-sketch vectorization pipelines.
      1
      -
    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables AI agents to build, measure, verify, and correct parametric SolidWorks parts and assemblies locally via the COM API, supporting operations like sketching, extruding, modeling, dimensioning, material assignment, export, and assembly mating.
      MIT