Skip to main content
Glama
CiphemonJY

photon-workshop-mcp

by CiphemonJY

photon-workshop-mcp

An MCP server that prepares resin prints in Anycubic Photon Workshop (tested on 4.2.1, Windows): it orients each model, loads it, repairs flagged meshes, auto-supports, and lays out the plate.

Photon Workshop has no API or CLI. Its Qt Quick controls are exposed through Windows UI Automation by their visible text, so the server drives the app the way a user would (pwlib.py) and returns a screenshot or a state read back from the UI after each action.

Photon Workshop has no auto-orient, so orientation is computed here (orient.py) and baked into <name>_oriented.stl before loading. Supports, repair, layout and slicing use Photon Workshop's own engine.

Orientation scoring

Inverted MSLA frame: plate at z=0, layers grow toward +z, the FEP caps the current layer. About 600 candidate "up" directions are scored on:

term

meaning

support

down-facing area steeper than the overhang angle; area on protected (cosmetic) normals counts x10

peel

largest single-layer cross-section

cup

resin cavities sealed against the FEP during printing (voxel flood-fill per layer) - suction cups

height

print height (time), small weight

The cheap terms rank every direction; peel and cup are evaluated on the best 12. python test_orient.py checks each term on shapes built to trigger it: a cup facing the FEP must score as a suction cup, the same cup facing the plate must not, a flat plate must peel more than a tilted one, and protected faces must end up facing away from the plate.

Related MCP server: mcp-test-utils

Tools

tool

does

pw_prepare(paths, protect)

whole job: orient, load onto a cleared plate, repair, auto-support, lay out

pw_orient(paths, protect, overhang_deg)

orientation only (writes *_oriented.stl, optionally loads)

pw_repair()

repair every object flagged "Deficient model"

pw_support(script, support_angle, platform_only)

auto-generate supports for all objects

pw_layout()

Layout All

pw_slice()

Slice Plate

pw_save_slice(path, overwrite=False)

save the sliced plate to path (never answers Yes to a replace prompt unless overwrite and it names path)

pw_check_slice(path)

independent post-slice check with UVtools, see below

pw_open, pw_clear_scene, pw_select, pw_rotate

scene control

pw_status, pw_screenshot

objects, flagged meshes, layer/exposure settings, screenshot

pw_click, pw_keys, pw_controls

escape hatches: click by name or position, send keys, list controls

protect maps a file name to cosmetic face normals in that file's own coordinates, for example {"case_front.stl": [[0, 0, -1]]} keeps the -Z face (a screen face) free of supports.

Post-slice check (UVtools)

pw_check_slice runs UVtoolsCmd print-issues (islands, resin traps, suction cups, empty layers, print height, touching bounds) on the sliced file. This checks the layer images the printer will actually expose, independently of orient.py's mesh-based score. uvcheck.py:

  • converts pixels and layer indices to mm using the file's own resolution, display size and layer height;

  • splits issues into the raft zone (the bottom raft_mm, default 1.0) and the model zone. Photon Workshop's honeycomb raft always reads as hundreds of suction cups (each hex pocket, about 22 mm3, is sealed by the build plate), so raft-zone issues are counted, with their largest size reported, but not flagged. The exception is a raft-zone suction cup bigger than raft_pocket_max_mm3 (default 40), which cannot be a pocket and is flagged. For a plate printed without a raft, pass raft_mm=0;

  • flags model-zone suction cups and resin traps of 5 mm3 or more and islands of 0.05 mm2 or more (all adjustable). The verdict is PASS or WARN. An issue line it cannot parse always forces WARN.

python test_uvcheck.py checks the parser and flags on recorded UVtools output, including the mangled unit glyph UVtools prints under some console code pages.

Example, the 4-part plate this was built on: 307 suction cups reported, 251 of them in the raft; largest model-zone cup 1.5 mm3, largest island 0.006 mm2 (about one pixel), so the verdict is PASS. UVtools' resin-trap count varies slightly between runs (2049-2061 on the same file, all under 0.11 mm3).

UVtools is found via UVTOOLS_CMD, ../UVtools/v7.1.0/UVtoolsCmd.exe, C:\Program Files\UVtools or PATH. Tested with UVtools 7.1.0. A full plate takes about 1-2 minutes.

Install

Windows only (UI Automation). Tested with Python 3.12, Photon Workshop 4.2.1 at 100% display scaling.

python -m venv .venv
.venv/Scripts/python -m pip install -r requirements.txt

Register with Claude Code (~/.claude.json, top-level mcpServers):

"photon-workshop": {
  "type": "stdio",
  "command": "C:/path/to/photon_mcp/.venv/Scripts/python.exe",
  "args": ["C:/path/to/photon_mcp/server.py"],
  "env": {"PYTHONIOENCODING": "utf-8"}
}

python smoke_mcp.py [sliced-file] starts the server over stdio, lists its tools, calls pw_status and, given a sliced file, pw_check_slice.

Known behaviour and limits

  • Ctrl+O opens scene files, not models. Models are imported through the toolbar icon, which opens an "Import Files" dialog as a child of the main window.

  • Repair drops supports. Photon Workshop recreates a repaired object as <name>_fixed without its supports, so pw_prepare runs repair, then support, then layout.

  • "Deficient model" is Photon Workshop's own check. It flagged a mesh that trimesh reports as watertight, with 4 bad edges. Trust its flag and repair.

  • The save dialog needs real keystrokes. Setting its file-name box through UI Automation changes what it shows but not what it saves: the file goes to the default name in the last folder. The tool types the path and reads it back before clicking Save.

  • Some controls are clicked by position. The Repair panel buttons, the slice view's Save to Disk button, the Placing section headers and the view cube are not exposed to UI Automation. Their positions assume the default window layout (tested at 1300x1391), so check the returned screenshot.

  • Fixed build volume. The build volume in orient.BUILD is set for the Photon Mono M5s; change it for other printers.

  • English UI assumed. Controls and dialogs are found by their English labels ("Support", "Save to Disk", "Confirm Save As"). On another language a control is not found, or a save waits until its timeout; it does not overwrite anything.

  • It moves your mouse. It drives the real Photon Workshop window, so don't use the app while a tool call is running.

License

MIT - see LICENSE. Not affiliated with Anycubic or UVtools.

Related MCP Connectors

Related MCP Servers

  • F
    license
    A
    quality
    D
    maintenance
    An intelligent 3D printing assistant that enables users to analyze meshes, generate optimal print profiles, and automate PrusaSlicer operations through an MCP client. It provides a comprehensive suite of tools for geometric analysis, printability checks, filament recommendations, and post-print diagnostics.
    17
    9
    -
  • F
    license
    Not graded
    quality
    B
    maintenance
    Desktop UI automation for AI agents: screenshots, window management, mouse, keyboard, UI Automation tree, OCR. Single Windows x64 binary, no dependencies.
    -
  • A
    license
    A
    quality
    B
    maintenance
    Enables headless slicing with OrcaSlicer, preset management, G-code analysis, and printer control over LAN for Klipper, OctoPrint, Prusa, Duet, Elegoo, and Bambu printers.
    15
    3
    MIT
  • A
    license
    C
    quality
    B
    maintenance
    Enables AI agents to perform reproducible Snapmaker U1 headless slicing with Snapmaker Orca, including model/profile discovery, STL/3MF-to-G-code slicing, G-code analysis, controlled overrides, and slice or orientation comparisons without GUI automation or printer control.
    33
    1
    MIT