Turned the bambuddy self-host into a full print control plane on telep-mainframe: a server-side Bambu Studio slicer-api sidecar, four material pipelines (PLA/PETG/ABS/PC-FR), the built-in maintenance tracker wired to the H2S, Telegram notifications, and a tailnet-reachable MCP endpoint so the Aperture ai node can drive the printer. All deployed and verified end-to-end on 2026-09-01. This replaced the standalone OrcaSlicer KasmVNC sidecar (see 2026-09-01-orcaslicer-tailnet-deploy — now retired) with bambuddy’s built-in Slicer API.
For Agents — quick facts
- bambuddy =
maziggy/bambuddy, host-networked, UI at127.0.0.2:8000, nodebambuddy.taild4189d.ts.net- Slicer API sidecar =
bambu-studio-api(ghcr.io/maziggy/bambu-studio-api:latest), bridge-published127.0.0.2:3001:3000, in/home/levander/slicer-api/- MCP endpoint for Aperture =
https://bambuddy.taild4189d.ts.net/mcp(streamable-HTTP; SSE at/sse) — path-mounted on the existing bambuddy node, no new node- Everything binds
127.0.0.2(loopback hardening per 2026-08-31-tailnet-plaintext-port-hardening); tailnet +tag:telepACL is the gate- Printer = Bambu Lab H2S (bambuddy printer id
1, DevName3DP-093-310, LAN192.168.1.202reserved asbambu.lan)- No secrets in this note: the bambuddy API key, the Telegram bot token, and the chat id are stored in
.envfiles (chmod-600) — never committed- REST base is
http://127.0.0.2:8000/api/v1/
1. Slicer API — server-side slicing
Deployed the Bambu Studio slicer-api sidecar so bambuddy can slice on the box instead of relying on a desktop Studio/OrcaSlicer session.
docker composein/home/levander/slicer-api/, imageghcr.io/maziggy/bambu-studio-api:latest, containerbambu-studio-api.- It is a normal bridge container, NOT host-networked — published
127.0.0.2:3001:3000(internal port3000). No--shm-sizeneeded. Healthcheckcurl :3000/health. - Bound to
127.0.0.2only (loopback hardening; the sidecar itself has no auth).
Port collision — the ESP32 already owns 127.0.0.1:3001
An ESP32 device already occupies
127.0.0.1:3001. That is exactly why the slicer sidecar is published on127.0.0.2:3001(a distinct loopback address, same port number) and bambuddy is pointed at127.0.0.2. Do not move it back to127.0.0.1.
Wiring bambuddy → sidecar (REST)
PATCH /api/v1/settings/
use_slicer_api = true
bambu_studio_api_url = http://127.0.0.2:3001
(preferred_slicer already "bambu_studio", slice_engine "sidecar")
Port map — bambuddy reserves 3000/3002 for its virtual printer
Ports 3000 and 3002 are reserved by bambuddy’s own virtual-printer. Slicer sidecars use 3001 (Bambu Studio) and 3003 (Orca — not deployed).
Remaining manual affordance: “Save as pipeline” is a UI action, but we created all pipelines via the API (below).
2. Slicer pipelines — PLA / PETG / ABS / PC-FR
Created 4 pipelines via POST /api/v1/slicer-pipelines/ (schema SlicerPipelineCreate: name, description, printer_preset, process_preset, filament_presets[], bed_type; presets are PresetRef {source:"standard", id:"<exact bundled preset name>"}). All returned 201 (ids 1–4).
| Pipeline | Filament preset (@BBL H2S) | id |
|---|---|---|
| PLA | Bambu PLA Basic @BBL H2S | 1 |
| PETG | Bambu PETG Basic @BBL H2S | 2 |
| ABS | Bambu ABS @BBL H2S | 3 |
| PC-FR | Bambu PC FR @BBL H2S | 4 |
Shared across all four:
- Printer preset →
Bambu Lab H2S 0.4 nozzle - Process preset →
0.20mm Standard @BBL H2S - Bed type →
Textured PEI Plate
Bambu ships H2S-specific
@BBL H2SprofilesThe temps / chamber / cooling values live inside Bambu’s
@BBL H2Sprofiles, not in the pipeline. The 0.4 mm ladder:0.08 / 0.12 / 0.16High Quality,0.16 / 0.20 / 0.24Standard,0.20High Quality.
Per-material operational guidance (baked into each pipeline description)
Material cheat sheet
- PLA — chamber OPEN/vented (heat-creep in an enclosure), bed 35–45 °C, no glue, full cooling.
- PETG — bed 70 °C + glue (for release), chamber ambient / no active heat, keep dry (AMS 2 Pro 65 °C ok).
- ABS — chamber CLOSED ~60 °C, low cooling, bed 90–100 °C + glue + brim, ventilate. Drying needs 80–100 °C (AMS 2 Pro too cool for this).
- PC-FR — chamber CLOSED ~60 °C, bed 90–110 °C + glue + brim, drying CRITICAL (80–100 °C; AMS insufficient), ventilate, brass nozzle fine (unfilled).
Do not co-print PLA with ABS / PC-FR
The printer runs the chamber at the highest requested chamber temp, so mixing PLA with a high-chamber material makes the PLA heat-creep. Also keep PLA out of the AMS during high-temp drying cycles.
Running a pipeline
- File Manager ⋮ → Run with pipeline, or Archives → Reprint with pipeline.
- Pipelines require the slicer-api sidecar from §1 to be up.
3. Maintenance tracker
Assigned bambuddy’s built-in maintenance types to the H2S (printer id 1, DevName 3DP-093-310) via POST /api/v1/maintenance/printers/1/assign/{type_id}. 6 H2S-appropriate tasks are now tracked against print hours:
- Lubricate Linear Rails — currently DUE
- Clean Linear Rails
- Clean Nozzle / Hotend
- Check Belt Tension
- Clean Build Plate
- Check PTFE Tube
The 400 on Steel/Carbon-Rod types is correct, not a failure
The default Steel / Carbon-Rod maintenance types are meant for A1 / P1-class printers. bambuddy rejects (HTTP 400) assigning them to an H2S — that is expected validation, not an error.
Endpoints:
GET /api/v1/maintenance/summaryandGET .../overview— due state.POST /api/v1/maintenance/items/{id}/perform— reset a task after doing it.
4. Telegram notifications
Created a notification provider via POST /api/v1/notifications/ (provider_type telegram, config {bot_token, chat_id} — both strings; keys confirmed against bambuddy’s source schemas/notification.py).
- Target = the existing “Telephely biztonsági riasztások” supergroup (the
chat_idis a negative supergroup id). Test message sent successfully. - Events enabled:
on_print_complete/on_print_failed/on_print_stopped,on_printer_offline/on_printer_error,on_filament_low,on_maintenance_due,on_ams_humidity_high,on_ai_failure_detection.
Secrets + open API
The bot token and chat id are NOT recorded here — they live in the provider config (and
.env). Also note the provider config / notifications API is currently open (no bambuddy auth enabled).
5. Bambuddy MCP on the tailnet (for Aperture)
Goal: let Aperture (the ai node, https://ai.taild4189d.ts.net) drive the printer. bambuddy-mcp (github MrMebelMan/bambuddy-mcp) is a stdio-only Python MCP that dynamically exposes bambuddy’s REST API (731 endpoints) through meta-tools: list_categories / search_tools / execute_tool / find_printer.
Why we self-host it behind a bridge
Aperture is not self-hosted, so it can only consume a network MCP endpoint. bambuddy-mcp only speaks stdio, so we self-host it on the mainframe wrapped in an stdio → streamable-HTTP bridge.
The bridge container
- Container
bambuddy-mcp-bridgein/home/levander/bambuddy-mcp/. - Dockerfile:
python:3.12-slim,pip install uv mcp-proxy==0.12.0 mcp==1.29.1, thenuv tool install --with mcp==1.29.1 bambuddy-mcp. --network host, ENTRYPOINT:mcp-proxy --host 127.0.0.2 --port 8091 --pass-environment -- bambuddy-mcp- Env:
BAMBUDDY_URL=http://127.0.0.2:8000+BAMBUDDY_API_KEY(full-scope key minus cloud, stored in a chmod-600.env). - Bound
127.0.0.2:8091loopback-only.
Version-pin gotcha — pin
mcp==1.29.1in BOTH envsThe current
mcpSDK 2.x removedmcp.server.lowlevel.server.request_ctx(breaks mcp-proxy) and the low-levelServer.list_toolsdecorator (breaks bambuddy-mcp). Both tools are written againstmcp1.x, so pinmcp==1.29.1in both the proxy pip env and bambuddy-mcp’suv-tool env. Same class of SDK-drift trap as the FastMCPallowed_hosts421 in 2026-08-31-telep-kb-mcp-server.
Exposure — path mount on the existing bambuddy node (no new node)
Rather than spin up a dedicated sidecar node, the MCP is path-mounted onto the existing bambuddy tailscale node:
tailscale --socket=/run/tailscale-bambuddy/tailscaled.sock serve --bg \
--https=443 --set-path=/mcp http://127.0.0.2:8091/mcp
serve status shows both / (the UI, preserved) and /mcp.
Prefix-strip behaviour on tailscale 1.102.2
On tailscale 1.102.2 the mount strips the prefix and joins the remainder onto the target, so external
/mcpmaps to backend/mcp(which is why the target URL includes/mcp).
Endpoint + verification
Endpoint for Aperture: https://bambuddy.taild4189d.ts.net/mcp (streamable-HTTP; SSE also at /sse).
Verified end-to-end from a tailnet client (personal-mac): initialize returns a session, tools/list returns the meta-tools.
The mainframe can't self-hairpin — test from another node
The mainframe runs a userspace tailscaled (
TUN:false) and cannot hairpin to its own tailnet HTTPS, so end-to-end reachability must be proven from a different node (we usedpersonal-mac). Same hairpin caveat noted in 2026-08-31-nextcloud-drive-code-server-runbook.
Security posture — tailnet ACL is the only gate
The
/mcpendpoint has no auth of its own (mcp-proxy adds none; the bambuddy API key is server-side). Tailnet membership +tag:telepACL is the only gate, andexecute_toolcan control the printer. bambuddy-mcp masksaccess_code/serialby default. Tighten the ACL if owner-only access is desired. Do NOT expose via Funnel (standing rule, cf. 2026-08-31-nextcloud-drive-code-server-runbook).
Related
- 2026-08-08-bambuddy-deploy-plan — the original bambuddy self-host / tailnet-node plan
- 2026-09-01-orcaslicer-tailnet-deploy — retired: the standalone OrcaSlicer sidecar this Slicer API replaced
- telep-mainframe — the host running bambuddy, the sidecar, and the MCP bridge
- tailnet-service-exposure-convention — the per-service node convention (here we path-mounted instead)
- 2026-08-31-tailnet-plaintext-port-hardening — the
127.0.0.2loopback-bind rule - 2026-08-31-telep-kb-mcp-server — sibling self-hosted MCP; the SDK-version / Host-header traps rhyme
- 2026-08-26-router-reflash-mac-5ghz-dfs-and-bambu-offline — H2S network identity + offline diagnostics