Skip to main content
Glama
orca-slicer-mcp

orca-slicer-mcp

by dmikushin

orca-slicer-mcp

An MCP server that drives OrcaSlicer headlessly on a private Xvfb display, so an agent can import a model, slice it, and export G-code without a physical screen.

It exists because OrcaSlicer has no scripting API for slicing profiles the way its GUI does. Rather than click buttons by screen coordinate (fragile across versions and resolutions), this server drives OrcaSlicer through its single-instance IPC channel: a short-lived orca-slicer <arg> process forwards its argument over DBus to the already-running GUI. Model paths load via Plater::load_files; a small source patch adds an orca-cmd:export:<path> command that slices the current plate and writes the G-code straight to a file. No coordinate clicking, no file-chooser scripting.

Requirements

System binaries on PATH:

  • orca-slicer 2.4.2, patched (see "OrcaSlicer patch" below)

  • Xvfb

  • openbox

  • xdotool

  • scrot

Python deps are declared in pyproject.toml (mcp, Pillow).

uv venv .venv
uv pip install --python .venv/bin/python -e .

Related MCP server: Klipper MCP Server

OrcaSlicer patch

The DBus-command tools require a patched OrcaSlicer: patches/orca-mcp.patch adds one IPC command, orca-cmd:export:<path>, that slices the current plate and exports the G-code to <path> with no file dialog. It touches four files (InstanceCheck.{hpp,cpp}, Plater.{hpp,cpp}): a new EVT_EXPORT_GCODE_OTHER_INSTANCE event, its parsing in OtherInstanceMessageHandler::handle_message, and Plater::export_gcode_to(), which reuses the existing slice+export path (priv::export_gcode with FORCE_EXPORT).

Apply it in the AUR PKGBUILD (portable, survives OrcaSlicer updates): add orca-mcp.patch to source=()/sha256sums=() and

prepare() {
  cd "$srcdir/OrcaSlicer-${pkgver}"
  patch -p1 < "$srcdir/orca-mcp.patch"
}

then rebuild with makepkg. The patch applies cleanly with patch -p1 against the v2.4.2 source tree.

Single-instance IPC is only active when app.single_instance is true in ~/.config/OrcaSlicer/OrcaSlicer.conf; start_session sets this automatically before launching. (The --single-instance CLI flag is not used - it is not a valid OrcaSlicer 2.4.x option and is rejected by read_cli() before the IPC code runs.)

Running

.venv/bin/orca-slicer-mcp          # stdio MCP server

Register it with your MCP client, e.g. for Claude Code:

claude mcp add orca-slicer -- /home/USER/forge/orca-slicer-mcp/.venv/bin/orca-slicer-mcp

Tools

Tool

Purpose

start_session(display, width, height)

Launch Xvfb + openbox + OrcaSlicer; enable single-instance IPC; dismiss first-run/crash dialogs. Call first.

stop_session()

Terminate OrcaSlicer, openbox and Xvfb.

session_status()

Report running state and current windows.

screenshot()

Return the current screen as a PNG image.

import_model(path)

Load STL/OBJ/3MF/STEP/AMF/SVG into the running instance via single-instance IPC (Plater::load_files).

export_gcode(path)

Slice the current plate and export G-code to path via orca-cmd:export: (one IPC command); returns a header summary.

process_model(stl, gcode)

Convenience: import + export.

print_gcode(gcode, start=True)

Ship a local G-code to the Creality printer and start it (see Printing).

screenshot / click / type_text / press_key / zoom

Low-level primitives for dialogs not yet covered by the high-level tools.

Printing (Creality K1 Max)

print_gcode(gcode_path, start=True) closes the loop: it takes a G-code file this server just exported and gets it printing without you walking to the machine.

The printer's own web UI does expose starting a print, but only as a right-click/tap context-menu item per file — easy to miss and awkward on a phone. This tool drives the exact same two web actions programmatically:

  1. upload — POST /upload/<name> (multipart, field file), and

  2. start — a WebSocket set on /wsapi with opGcodeFile: "printprt:<gcode_dir>/<name>".

It reaches the Creality web UI through the docker container that serves it, bypassing the public oauth2-proxy gate — the local side only runs scp and ssh <host>; the HTTP upload and WebSocket start execute on the docker host (see creality_print_remote.py), the only machine on the printer's LAN.

Configuration (environment variables):

Variable

Default

Meaning

CREALITY_SSH_HOST

t580

SSH alias of the host running the Creality docker stack.

CREALITY_PROXY_CONTAINER

creality-proxy

Docker container serving the web UI; talked to directly, bypassing oauth2-proxy.

CREALITY_GCODE_DIR

/usr/data/printer_data/gcodes

Upload directory on the printer, used to build the printprt path.

Requires on the docker host: docker, curl, and Python with websocket-client. Pass start=False to stage a file without printing.

Why each moving part exists (hard-won lessons)

These are baked into session.py; do not "simplify" them away:

  • A window manager is mandatory. Without one there is no _NET_ACTIVE_WINDOW; focus and window management silently misbehave. openbox is launched with a bundled openbox-rc.xml that makes every window undecorated and maximized.

  • Commands travel over single-instance IPC, not the CLI action API. A second orca-slicer <arg> process passes CLI validation (the arg is a plain positional, not an option), reaches instance_check, and — because app.single_instance is enabled — forwards the whole command line over DBus to the running instance, then exits. --single-instance must not be passed: it is not a valid 2.4.x option and read_cli() rejects it before instance_check runs, so the sender would error out or spawn a second GUI.

  • app.single_instance must be true before launch. It lives nested under the "app" object in OrcaSlicer.conf (not at the top level); start() sets it and OrcaSlicer preserves it across runs.

  • Export completion is detected by the G-code file on disk, not by any GUI signal: export_gcode polls until the file stops growing across several samples (so a mid-write stall cannot yield a truncated read).

  • Dialogs block the main window. The first-run SSL-certificate dialog, the update-check dialog, and — after any unclean exit — the crash "Restore" dialog all prevent the main window from being created. start() interleaves dismissing them with waiting for the main window, in one loop.

  • The main window's title varies ("Unnamed Window", "*Untitled", a project name), so it is detected by size (>=90% of screen width), not by title.

  • Every xdotool/scrot call has a timeout. A single blocked call (e.g. if the X server dies) would otherwise freeze every polling loop.

  • Long-lived processes are owned by the server. They are spawned with start_new_session=True and held by the OrcaSession object; launching them from an ephemeral shell that then exits would kill them.

Testing

.venv/bin/python test_e2e.py

Runs the full import -> export against a sample STL on a fresh Xvfb and asserts a non-trivial G-code is produced.

Available Tools

12 tools
clickA

Click at absolute screen coordinates (button 1=left, 3=right).

Inputs: x (required), y (required), button. Returns: result

export_gcodeA

Slice the current plate and export G-code to an absolute path.

Sends a single orca-cmd:export:<path> command over the single-instance DBus channel. Inside OrcaSlicer this slices the current plate and writes the G-code straight to (Plater::export_gcode_to), bypassing the file dialog entirely. Completion is detected by the G-code file appearing on disk. Returns a summary parsed from the generated G-code header.

Inputs: path (required), timeout. Returns: result

import_modelA

Import a model (STL/OBJ/3MF/STEP/AMF/SVG) into the running instance.

Delivers the file path to the already-running OrcaSlicer over the single-instance DBus channel (orca-slicer <path> with single-instance mode enabled in the app config), which routes it to Plater::load_files - no coordinate clicking. Waits until a top-level window title reflects the loaded model.

Inputs: path (required). Returns: result

press_keyA

Send a key or chord in xdotool syntax (e.g. 'ctrl+i', 'Return', 'Escape').

Inputs: keys (required). Returns: result

process_modelA

Convenience: import a model then slice + export G-code in one call.

Inputs: stl_path (required), gcode_path (required). Returns: result

screenshotA

Capture the current OrcaSlicer screen and return it as a PNG image.

Inputs: no named parameters.

session_statusA

Report whether a session is running and list its top-level windows.

Inputs: no named parameters. Returns: result

start_sessionA

Start a private Xvfb display with openbox and launch OrcaSlicer on it.

Must be called before any other tool. Dismisses the first-run SSL and update dialogs. Returns a status string.

Inputs: width, height, display. Returns: result

stop_sessionA

Terminate OrcaSlicer, openbox and Xvfb, freeing the display.

Inputs: no named parameters. Returns: result

type_textC

Type literal text into the focused widget.

Inputs: text (required). Returns: result

zoomC

Zoom the 3D view. Positive steps zoom in, negative out, over (x,y).

When x/y are left at -1 the screen centre of the active session is used.

Inputs: steps (required), x, y. Returns: result

Tool Schema Changelog

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

Loading tool schema changelog…

    TDQS

    A3.8/5.0

    Scored across 12 tools

    Disambiguation5/5

    Each tool has a distinct purpose: UI actions (click, press_key, type_text), file operations (export_gcode, import_model, process_model), session management (start/stop_session, session_status), printer control (print_gcode), view manipulation (zoom), and capture (screenshot). No overlapping functionality.

    Naming Consistency4/5

    Most tools follow a verb_noun pattern (e.g., import_model, start_session). However, 'screenshot' is a noun, 'zoom' is a single verb, and 'session_status' uses noun_noun, introducing a few inconsistencies.

    Tool Count5/5

    12 tools cover the core workflow (session lifecycle, model import, slicing, printing, UI interaction) without being excessive. Each tool justifies its existence for automating OrcaSlicer.

    Completeness4/5

    The set covers major workflows but lacks direct tools for model editing (e.g., scale, rotate) and printer status. However, UI tools like click and press_key can compensate, and the core slice-and-print path is complete.

    Maintenance

    ActivityInactive
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers