orca-slicer-mcp
An MCP server that drives OrcaSlicer headlessly on a virtual display, enabling an agent to import 3D models, slice them, and export G-code without a physical screen or GUI automation.
README
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-slicer2.4.2, patched (see "OrcaSlicer patch" below)Xvfbopenboxxdotoolscrot
Python deps are declared in pyproject.toml (mcp, Pillow).
uv venv .venv
uv pip install --python .venv/bin/python -e .
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:
- upload —
POST /upload/<name>(multipart, fieldfile), and - start — a WebSocket
seton/wsapiwithopGcodeFile: "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.openboxis launched with a bundledopenbox-rc.xmlthat 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), reachesinstance_check, and — becauseapp.single_instanceis enabled — forwards the whole command line over DBus to the running instance, then exits.--single-instancemust not be passed: it is not a valid 2.4.x option andread_cli()rejects it beforeinstance_checkruns, so the sender would error out or spawn a second GUI. app.single_instancemust betruebefore launch. It lives nested under the"app"object inOrcaSlicer.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_gcodepolls 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/scrotcall 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=Trueand held by theOrcaSessionobject; 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.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
Neon Database
MCP server for interacting with Neon Management API and databases
E2B
Using MCP to run code via e2b.
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.