Skip to content

block0ps/fluidd-klipper-mcp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

14 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Fluidd / Klipper 3D Printer MCP Server

An MCP (Model Context Protocol) server that gives AI assistants (Claude, etc.) full real-time control and visibility over 3D printers running Klipper firmware via the Fluidd / Moonraker API stack.

Also includes a standalone local monitor server (monitor_server.py) with a live web UI and multi-channel alerting β€” push, SMS, email, and iMessage β€” that fires even when the browser tab is closed.


Features

πŸ“Š Real-Time Monitoring

Tool Description
get_printer_status Full real-time status β€” state, temps, progress, ETA, position
get_temperatures Hotend, bed, and all extra sensor temperatures
get_print_job_status Current job file, layer, progress, elapsed & ETA
get_klippy_status Klippy firmware health and error messages
get_moonraker_status Moonraker API server health
get_active_alerts All active alerts in one call
get_printer_logs Recent Klippy log lines with error highlighting

🚨 Failure Detection & Alerts

Tool Description
check_failure_detection Heuristic checks for spaghetti, layer shifts, thermal anomalies, under-extrusion, and stalls
get_active_alerts Continuous alert summary β€” thermal runaway, Klippy errors, clog detection

Camera integration: Use get_camera_snapshot_url to retrieve live snapshot/stream URLs from Fluidd-configured webcams. For AI-powered visual spaghetti detection, pipe the snapshot URL to a vision model (e.g., Claude's image analysis).

πŸ“· Camera

Tool Description
get_camera_snapshot_url Snapshot + stream URL(s) for all configured webcams

πŸ–¨οΈ Print Job Management

Tool Description
start_print Start printing a file from storage
pause_print Pause the current print
resume_print Resume a paused print
cancel_print Cancel the current print
emergency_stop Immediate M112 hardware stop

πŸ“‹ Queue & File Management

Tool Description
get_print_queue View the Moonraker job queue
add_to_queue Add a file to the print queue
remove_from_queue Remove a job by ID
list_print_files Browse files on printer storage
get_print_history Recent job history with durations and results

πŸ’° Cost & Profitability

Tool Description
calculate_print_cost Calculate material + power cost and recommended sale price with configurable markup

βš™οΈ Printer Control

Tool Description
set_temperature Set hotend or bed temperature
send_gcode Send any raw G-code command
restart_klippy Restart Klippy service
restart_firmware Firmware restart

Prerequisites

  • Docker Desktop with MCP Toolkit enabled
  • A 3D printer running Klipper + Moonraker (exposed on your network)
  • Fluidd or Mainsail as the front-end (optional β€” Moonraker API is the interface)
  • Moonraker API key (if authentication is enabled)
  • Python 3.7+ (for the monitor server β€” no extra packages needed)

Quick Start β€” MCP Server (Claude Desktop)

⚑ Automated Setup (Recommended)

Run the interactive setup script β€” it handles all steps below, asks for confirmation before making changes, and works on macOS, Linux, and Windows (Git Bash).

git clone https://github.com/block0ps/fluidd-klipper-mcp.git
cd fluidd-klipper-mcp
chmod +x setup.sh
./setup.sh

Or via one-liner (no clone needed):

curl -fsSL https://raw.githubusercontent.com/block0ps/fluidd-klipper-mcp/main/setup.sh | bash

Manual Setup

1. Clone & Build

git clone https://github.com/block0ps/fluidd-klipper-mcp.git
cd fluidd-klipper-mcp
docker build -t fluidd-klipper-mcp-server .

2. Set Secrets

docker mcp secret set PRINTER_HOST="http://192.168.1.100"
docker mcp secret set PRINTER_API_TOKEN="your-moonraker-api-key"

# Cost calculation config (optional β€” defaults shown)
docker mcp secret set FILAMENT_COST_PER_KG="25.0"
docker mcp secret set POWER_COST_PER_KWH="0.12"
docker mcp secret set PRINTER_WATTS="150.0"
docker mcp secret set MARKUP_PERCENTAGE="30.0"

docker mcp secret list

3. Register in Docker MCP Catalog

mkdir -p ~/.docker/mcp/catalogs
cp custom.yaml ~/.docker/mcp/catalogs/custom.yaml

Add to ~/.docker/mcp/registry.yaml under the registry: key:

registry:
  fluidd-klipper:
    ref: ""

4. Configure Claude Desktop

Edit ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "mcp-toolkit-gateway": {
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "-v", "/var/run/docker.sock:/var/run/docker.sock",
        "-v", "/Users/YOUR_USERNAME/.docker/mcp:/mcp",
        "docker/mcp-gateway",
        "--catalog=/mcp/catalogs/docker-mcp.yaml",
        "--catalog=/mcp/catalogs/custom.yaml",
        "--config=/mcp/config.yaml",
        "--registry=/mcp/registry.yaml",
        "--tools-config=/mcp/tools.yaml",
        "--transport=stdio"
      ]
    }
  }
}

5. Restart Claude Desktop


πŸ–₯️ Live Monitor & Alerting (monitor_server.py)

A standalone Python server that runs locally, serves a live web UI, and dispatches alerts across four channels when anomalies are detected. Polling runs on a background thread β€” alerts fire even when the browser tab is closed or your screen is locked.

Why a separate server?

Browsers block direct fetch() calls from file:// or https:// pages to local http:// printer IPs (CORS + mixed content policy). monitor_server.py acts as a local proxy: the browser talks to localhost, and Python forwards requests to Moonraker server-side where CORS rules don't apply.

Starting the monitor

# Uses default printer at http://10.0.107.158, port 8484
python3 monitor_server.py

# Custom printer URL
python3 monitor_server.py http://192.168.1.100

# Custom printer URL and port
python3 monitor_server.py http://192.168.1.100 9000

Then open http://localhost:8484 in your browser.

No dependencies beyond Python's standard library β€” nothing to pip install.

What it monitors

Check Threshold
🌑️ Thermal anomaly β€” hotend Actual vs target divergence > 20Β°C
🌑️ Thermal anomaly β€” bed Actual vs target divergence > 15Β°C
πŸ”΄ Klippy not ready Any non-ready firmware state
🧡 Clog / under-extrusion < 5mm filament used after 5+ min printing
⏸️ Print stall No progress after 10+ min printing
πŸ“ Z position anomaly Z < 0.1mm after 2+ min printing
πŸ›‘ Print error / cancelled State change to error or cancelled
πŸŽ‰ Print complete State change to complete

Configuring alert channels

On first run, monitor_server.py creates monitor_config.json in the same directory. Open it, set "enabled": true for each channel you want, fill in the credentials, then restart the server.

{
  "printer_host": "http://10.0.107.158",
  "poll_interval_seconds": 1800,
  "alert_on_warnings": true,

  "ntfy": {
    "enabled": false,
    "topic": "my-printer-alerts",
    "server": "https://ntfy.sh"
  },
  "twilio": {
    "enabled": false,
    "account_sid": "",
    "auth_token": "",
    "from_number": "+1XXXXXXXXXX",
    "to_number": "+1XXXXXXXXXX"
  },
  "email": {
    "enabled": false,
    "smtp_host": "smtp.gmail.com",
    "smtp_port": 587,
    "username": "you@gmail.com",
    "password": "your-app-password",
    "from_address": "you@gmail.com",
    "to_address": "you@gmail.com"
  },
  "imessage": {
    "enabled": false,
    "to_number": "+1XXXXXXXXXX"
  }
}

πŸ“± Push Notifications β€” ntfy.sh (free, no account)

ntfy.sh is a free, open-source push notification service.

  1. Install the ntfy app on your phone (iOS / Android)
  2. In the app, tap Subscribe to topic and enter a unique topic name (e.g. mahdi-printer-9482) β€” treat it like a password, anyone who knows it can send to it
  3. In monitor_config.json:
"ntfy": {
  "enabled": true,
  "topic": "mahdi-printer-9482",
  "server": "https://ntfy.sh"
}

Alerts arrive instantly on your phone with priority levels β€” critical alerts are marked urgent and bypass Do Not Disturb.

Self-hosting: If you prefer to run your own ntfy server, change "server" to your instance URL.


πŸ’¬ SMS β€” Twilio

  1. Sign up at twilio.com (free trial includes test credits)
  2. From the Twilio Console, copy your Account SID and Auth Token
  3. Get a Twilio phone number (free with trial)
  4. In monitor_config.json:
"twilio": {
  "enabled": true,
  "account_sid": "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "auth_token": "your_auth_token",
  "from_number": "+15551234567",
  "to_number": "+15559876543"
}

Trial accounts: Twilio trial numbers can only send to verified phone numbers. Verify your number at Console β†’ Phone Numbers β†’ Verified Caller IDs.


πŸ“§ Email β€” SMTP (Gmail)

  1. In your Google Account, go to Security β†’ 2-Step Verification and enable it
  2. Then go to Security β†’ App Passwords, create a new app password for "Mail"
  3. Copy the 16-character password (spaces don't matter)
  4. In monitor_config.json:
"email": {
  "enabled": true,
  "smtp_host": "smtp.gmail.com",
  "smtp_port": 587,
  "username": "you@gmail.com",
  "password": "abcd efgh ijkl mnop",
  "from_address": "you@gmail.com",
  "to_address": "you@gmail.com"
}

Other providers: Change smtp_host and smtp_port for Outlook (smtp.office365.com, 587), Yahoo (smtp.mail.yahoo.com, 587), or any other SMTP provider.


πŸ’¬ iMessage β€” macOS only, no setup required

Uses macOS AppleScript to send iMessages via the Messages app already on your Mac. The Mac running monitor_server.py must be signed into iMessage.

"imessage": {
  "enabled": true,
  "to_number": "+15551234567"
}

to_number accepts a phone number (+15551234567) or an Apple ID email address (you@icloud.com).

Note: macOS may prompt you to grant Terminal (or your Python app) access to Messages the first time. Accept the permission request in System Settings β†’ Privacy & Security β†’ Automation.


Testing alerts

Once configured, use the πŸ”” Test Alerts button in the web UI to fire a test message across all enabled channels before walking away from the printer.

You can also trigger an immediate poll (without waiting for the interval) using the πŸ”„ Poll Now button.


Alert deduplication

Each unique alert fires once per print job β€” you won't get spammed with repeated SMS messages if a thermal anomaly persists across multiple poll cycles. The dedup set resets automatically when a new print job starts.


Adjusting the poll interval

Change poll_interval_seconds in monitor_config.json and restart the server. Recommended values:

Print type Suggested interval
Short print (< 2h) 300 (5 min)
Overnight print 900 (15 min)
Multi-day print 1800 (30 min)

πŸ–¨οΈ Multi-Printer Support

Both the MCP server and the monitor support an unlimited number of printers. Each printer is polled on its own background thread; alerts, status, and camera feeds are scoped per printer.


MCP Server β€” Multiple Printers

Set PRINTER_HOSTS as a JSON array (instead of the single-printer PRINTER_HOST):

[
  {"id": "voron",  "name": "Voron 2.4",  "host": "http://192.168.1.100", "api_token": ""},
  {"id": "ender",  "name": "Ender 5 Pro","host": "http://192.168.1.101", "api_token": ""},
  {"id": "bambu",  "name": "Bambu P1S",  "host": "http://192.168.1.102", "api_token": ""}
]

Via Docker MCP secrets:

docker mcp secret set PRINTER_HOSTS='[{"id":"voron","name":"Voron 2.4","host":"http://192.168.1.100"},{"id":"ender","name":"Ender 5 Pro","host":"http://192.168.1.101"}]'

Once set, Claude can target any printer by name or URL in every tool:

"Check the status of the Voron"
"Pause the Ender"
"What's the bed temp on printer http://192.168.1.102?"
"List all my printers"   ← uses list_printers tool

The list_printers tool shows all configured printers with their IDs and hosts.

Automated setup (adds printers interactively)

./setup.sh
# Step 2 will ask: "Add another printer?" after each one

Monitor Server β€” Multiple Printers

Initial setup β€” adding printers during ./setup.sh

Step 2 of setup.sh loops until you decline to add another printer. Each printer's name, host, and token is collected and written to both PRINTER_HOSTS (Docker MCP) and monitor_config.json.

Adding a printer after initial setup

Option A β€” interactive CLI (recommended):

python3 monitor_server.py add-printer
# β€” or via setup.sh shortcut β€”
./setup.sh add-printer

You'll be prompted for the printer name and host URL. The entry is written to monitor_config.json and a poll thread starts on the next server restart.

Option B β€” REST API (while server is running):

curl -X POST http://localhost:8484/api/printers \
  -H "Content-Type: application/json" \
  -d '{"name": "Bambu P1S", "host": "http://192.168.1.103", "api_token": ""}'

The printer is registered immediately and starts polling β€” no restart required.

Option C β€” edit monitor_config.json directly:

{
  "printers": [
    {"id": "voron",  "name": "Voron 2.4",  "host": "http://192.168.1.100", "enabled": true, "api_token": ""},
    {"id": "ender",  "name": "Ender 5 Pro","host": "http://192.168.1.101", "enabled": true, "api_token": ""}
  ]
}

Then restart monitor_server.py.

Renaming or editing a printer

From the web UI:

  1. Open http://localhost:8484
  2. Click βš™ Manage next to the printer tabs
  3. Click ✎ Edit on any printer to rename it, change its host URL, or update the API token
  4. Toggle the enable/disable switch to pause monitoring without removing the printer

From the CLI (while server is running):

# Rename
curl -X PATCH http://localhost:8484/api/printers/voron \
  -H "Content-Type: application/json" \
  -d '{"name": "Voron 2.4 β€” Garage"}'

# Change host
curl -X PATCH http://localhost:8484/api/printers/ender \
  -H "Content-Type: application/json" \
  -d '{"host": "http://10.0.0.55"}'

# Disable monitoring (pauses polling without removing)
curl -X PATCH http://localhost:8484/api/printers/bambu \
  -H "Content-Type: application/json" \
  -d '{"enabled": false}'

Changes are written to monitor_config.json immediately and take effect live.

Direct JSON edit: Modify monitor_config.json and restart the server.

Monitor UI β€” fleet navigation

Element Description
Printer tabs One tab per printer β€” click to switch the status card
Tab dot colour 🟒 printing, 🟑 paused, πŸ”΄ error, ⚫ idle/standby
βš™ Manage button Opens the manage panel (edit, rename, enable/disable, add new)
Alert log Combined across all printers; printer name shown on each entry
Camera button Fetches snapshot from the currently selected printer's webcam

Alert routing

Alerts from all printers are dispatched over the same channels (ntfy, SMS, email, iMessage). Each notification includes the printer name so you always know which machine fired:

[Voron 2.4] CRITICAL
Thermal anomaly β€” Bed: target 110Β°C actual 72.3Β°C

Once the MCP server is configured, ask Claude:

  • "What's my printer doing right now?"
  • "Are there any alerts or errors on the printer?"
  • "Show me my print queue"
  • "Start printing benchy.gcode"
  • "Pause the current print"
  • "Check for spaghetti or layer shifts"
  • "What's the camera snapshot URL?"
  • "How much did this print cost? What should I charge?"
  • "Set the bed to 60Β°C"
  • "Show me the last 20 log lines"
  • "Restart Klippy"

Cost Calculation

The calculate_print_cost tool uses these configurable parameters:

Env Var Default Description
FILAMENT_COST_PER_KG 25.0 USD per kilogram of filament
POWER_COST_PER_KWH 0.12 USD per kWh electricity
PRINTER_WATTS 150.0 Average power draw of your printer
MARKUP_PERCENTAGE 30.0 Profit margin % on top of costs

Failure Detection

The check_failure_detection and get_active_alerts tools use heuristics against live Moonraker data (same logic as the monitor server):

Detection Method
Thermal anomaly Heater actual vs target divergence > 15Β°C (bed) or 20Β°C (hotend)
Under-extrusion / clog Very low filament usage after 5+ min of printing
Layer shift / stall No Z progress after 10+ min of printing
Z position anomaly Z < 0.1 mm after 2+ min
Spaghetti (visual) Pull camera snapshot URL β†’ analyze with vision AI

Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                   Your Network                       β”‚
β”‚                                                      β”‚
β”‚  Claude Desktop                                      β”‚
β”‚       β”‚                                              β”‚
β”‚       β–Ό                                              β”‚
β”‚  MCP Gateway (Docker)                                β”‚
β”‚       β”‚                                              β”‚
β”‚       β–Ό                                              β”‚
β”‚  fluidd-klipper-mcp-server (Docker)                  β”‚
β”‚       β”‚                          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚       β”‚    monitor_server.py ─────  Background     β”‚ β”‚
β”‚       β”‚    (localhost:8484)      β”‚  Poll Thread    β”‚ β”‚
β”‚       β”‚         β”‚                β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚       β”‚         β”‚  Alerts                 β”‚          β”‚
β”‚       β”‚         β”œβ”€β”€β”€β”€ πŸ“± ntfy push        β”‚          β”‚
β”‚       β”‚         β”œβ”€β”€β”€β”€ πŸ’¬ SMS (Twilio)     β”‚          β”‚
β”‚       β”‚         β”œβ”€β”€β”€β”€ πŸ“§ Email (SMTP)     β”‚          β”‚
β”‚       β”‚         └──── πŸ’¬ iMessage         β”‚          β”‚
β”‚       β”‚                                  β”‚          β”‚
β”‚       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜          β”‚
β”‚                        β”‚                             β”‚
β”‚                        β–Ό HTTP/REST                   β”‚
β”‚              Moonraker API (printer)                 β”‚
β”‚                        β”‚                             β”‚
β”‚                        β–Ό                             β”‚
β”‚              Klipper Firmware + Fluidd               β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Development

Local Testing

export PRINTER_HOST="http://192.168.1.100"
export PRINTER_API_TOKEN="your-key"
python3 fluidd_klipper_server.py

# Test MCP protocol
echo '{"jsonrpc":"2.0","method":"tools/list","id":1}' | python3 fluidd_klipper_server.py

Adding New Tools

  1. Add a new @mcp.tool() function to fluidd_klipper_server.py
  2. Keep the docstring to a single line
  3. Default all parameters to "" (empty string)
  4. Always return a string
  5. Add the tool name to custom.yaml
  6. Rebuild: docker build -t fluidd-klipper-mcp-server .

Security

  • All secrets stored in Docker Desktop secrets β€” never hardcoded
  • Container runs as non-root user (mcpuser)
  • Sensitive values (API tokens) are never logged
  • monitor_config.json stores credentials locally β€” keep it out of version control (it's in .gitignore)
  • Emergency stop is intentionally available β€” treat chat access to this server with care

Troubleshooting

Issue Fix
Connection refused on MCP server Verify PRINTER_HOST is reachable from Docker network
401 Unauthorized on MCP server Set PRINTER_API_TOKEN via Docker secrets
Tools not appearing in Claude Rebuild Docker image, restart Claude Desktop
Monitor shows "proxy error" Ensure monitor_server.py is running (python3 monitor_server.py)
Push alerts not arriving Check ntfy topic name matches app subscription; try πŸ”” Test Alerts
SMS not sending Verify Twilio trial number is verified; check account SID / auth token
Email not sending Use an App Password (not your Gmail login password); ensure 2FA is on
iMessage permission denied Grant Terminal access in System Settings β†’ Privacy & Security β†’ Automation
Alerts firing repeatedly Dedup resets per print job β€” check if a new job started

License

MIT

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors