Docker-Image: FreeCAD (Xvfb) + freecad-ai MCP-Server, Backend für das Iris-Plugin freecad-bridge
  • Python 93.9%
  • Dockerfile 3.1%
  • Shell 3%
Find a file
2026-10-19 09:47:13 +02:00
__pycache__ feat: kit.wall_cutout/slot_array/slots (prüfende CadQuery-Bausteine), Zielordner werden angelegt, Rezepte getestet 2026-10-03 22:56:08 +02:00
docs docs(primitives): Entwurf der Primitive-Werkzeuge, Fehlerbehandlung und Testfälle (iris/iris-plugins#127) 2026-10-19 09:47:13 +02:00
help feat(kit): enclosure() — Gehäuse inkl. erkannter Anschluss-Aussparungen in Weltkoordinaten 2026-10-04 09:09:50 +02:00
.env.example feat: FreeCAD-Image mit freecad-ai MCP-Server (Xvfb, Watchdog, Viewport-Fix) 2026-10-03 06:17:43 +02:00
.gitignore feat: FreeCAD-Image mit freecad-ai MCP-Server (Xvfb, Watchdog, Viewport-Fix) 2026-10-03 06:17:43 +02:00
build-and-push.sh feat: FreeCAD-Image mit freecad-ai MCP-Server (Xvfb, Watchdog, Viewport-Fix) 2026-10-03 06:17:43 +02:00
cadlib.py feat: Rezept rohrschelle, view_inside-Fix (kein processEvents nach dem Ausblenden) 2026-10-04 00:26:23 +02:00
cq_runner.py feat: kit.wall_cutout/slot_array/slots (prüfende CadQuery-Bausteine), Zielordner werden angelegt, Rezepte getestet 2026-10-03 22:56:08 +02:00
cqkit.py feat(kit): enclosure() — Gehäuse inkl. erkannter Anschluss-Aussparungen in Weltkoordinaten 2026-10-04 09:09:50 +02:00
docker-compose.yml feat: FreeCAD-Image mit freecad-ai MCP-Server (Xvfb, Watchdog, Viewport-Fix) 2026-10-03 06:17:43 +02:00
Dockerfile feat: kit.wall_cutout/slot_array/slots (prüfende CadQuery-Bausteine), Zielordner werden angelegt, Rezepte getestet 2026-10-03 22:56:08 +02:00
documents.py fix(vase_from_mesh): Profil bis zu den echten Enden 2026-10-04 10:34:02 +02:00
entrypoint.sh feat: run_cadquery (CadQuery im venv) und cad_help mit getesteten Rezepten; Watchdog zählt arbeitende Werkzeuge nicht als Hänger 2026-10-03 22:29:16 +02:00
README.md feat: run_cadquery (CadQuery im venv) und cad_help mit getesteten Rezepten; Watchdog zählt arbeitende Werkzeuge nicht als Hänger 2026-10-03 22:29:16 +02:00
start_mcp.py feat: FreeCAD-Oberfläche per VNC (Xvfb :99, x11vnc mit Passwort, Hauptfenster vollflächig) 2026-10-03 20:08:17 +02:00

freecad-mcp

Docker-Image: FreeCAD 1.1 (headless unter Xvfb) mit dem MCP-Server des Addons ghbalf/freecad-ai. Agenten (Claude Code, Hermes, opencode) steuern damit FreeCAD über MCP (Streamable HTTP, /mcp). Gedacht als Backend des Iris-Plugins freecad-bridge.

Image: forgejo.lewerken.duckdns.org/iris/freecad-mcp

Betrieb

cp .env.example .env     # MCP_AUTH_TOKEN setzen (openssl rand -hex 24)
docker compose up -d     # zieht das Image aus der Forgejo-Registry

MCP-Endpunkt: http://<host>:3100/mcp mit Authorization: Bearer <MCP_AUTH_TOKEN>. Dateien (Exporte, Screenshots, .FCStd) liegen im Volume ./workspace, die freecad-ai-Config in ./config. Der Server braucht nach dem Start etwa 60 Sekunden.

Bauen und veröffentlichen

Auf einem amd64-Docker-Host (der FreeCAD-AppImage ist x86_64):

FORGEJO_TOKEN=... ./build-and-push.sh --version v0.1.0

Build-Argumente im Dockerfile: FREECAD_VERSION, FREECAD_AI_REF (Commit des freecad-ai-Repos, gepinnt).

Aufbau und Besonderheiten

  • Dockerfile — Ubuntu 24.04, FreeCAD-AppImage entpackt (kein FUSE), freecad-ai auf festen Commit gepinnt.
  • start_mcp.py — startet den MCP-Server per Timer erst, wenn FreeCADs Event-Loop läuft. Ohne das ist der Viewport-Ausschnitt bei capture_viewport/set_view falsch (View-Widget entsteht vor dem Fenster-Layout).
  • entrypoint.sh — Xvfb + FreeCAD, plus Watchdog: alle 30 s ein echter Tool-Call (list_documents); nach 3 Fehlschlägen beendet sich der Container, restart: unless-stopped startet ihn neu.
  • documents.py — jedes Tool bekommt den Pflichtparameter document: pro Aufruf wird das Dokument gewählt (bei Bedarf angelegt oder aus /workspace/documents/<name>.FCStd geöffnet) und nach jedem schreibenden Tool gespeichert. Mehrere Chats arbeiten so parallel in getrennten Modellen, ein Neustart verliert nichts. switch_document entfällt, list_documents zeigt zusätzlich die gespeicherten Dokumente. Bei Ansichts-Tools wird das 3D-Fenster des Dokuments nach vorne geholt (verdeckte Fenster liefern leere/angeschnittene Screenshots), capture_viewport zieht vorher fitAll nach. Dateipfade in Ausgaben nennen den Nutzerpfad /workspaces/freecad/….
  • import_model (eigenes Tool in documents.py): lädt STEP/IGES/BREP/STL/OBJ ins Dokument und meldet die Gesamtmaße. Upstream hat keinen Import; über execute_code (Sandbox ohne GUI) scheitern die üblichen Wege. Container-Locale C.UTF-8 ist nötig, sonst findet Python Pfade mit Umlauten („Anhänge“) nicht.
  • create_enclosure_around (eigenes Tool): Gehäuse (Wanne mit offener Seite) rechnerisch exakt um die Bounding-Box eines Objekts, in dessen Koordinaten; Öffnung an der kürzesten Seite; echte Überschneidungsprüfung. Ersetzt das unzuverlässige Nachbauen durch das Modell.
  • run_script (eigenes Tool) und cadlib.py (cad.*): FreeCAD-Python im aktiven Dokument, mit Bausteinen für Druckteile (Gehäuse mit Deckel/Lippe, Lüftungsschlitze, Fasen, Schraubdome, Löcher). Zeitlimit 60 s, bei Fehler/Zeitüberschreitung werden alle Änderungen des Skripts zurückgenommen. Der Watchdog wartet vier Fehlproben ab (länger als das Skript-Limit).
  • Upstream-Fehler im Executor behoben (documents.py, _patch_executor): QtMainThreadToolExecutor weckte mit wakeAll() alle wartenden Aufrufe; parallele Aufrufe (z. B. Watchdog-Probe während eines Skripts) bekamen None zurück ("'NoneType' object has no attribute 'success'") und lösten Hermes' Schutzschalter aus. Jetzt wartet jeder Aufruf auf sein eigenes Ereignis.
  • run_cadquery + cad_help (allgemeiner Konstruktionsweg): CadQuery läuft in eigenem venv /opt/cq (Python 3.12, getrennt von FreeCADs Python); das Skript (cq_runner.py) kennt show_object, result und load(label) für übergebene Dokumentobjekte, die Ergebnisse gehen als BREP an FreeCAD und erscheinen als Part::Feature (gleichnamige werden aktualisiert). Zeitlimit 50 s, bei Fehlern bleibt das Dokument unverändert. cad_help liefert getestete Rezepte aus help/*.md (alle Codeblöcke dort werden vor jedem Release gegen das Image ausgeführt).
  • Watchdog: Ein laufendes Werkzeug schreibt /tmp/mcp_busy; solange es < 150 s arbeitet, zählt der Watchdog keine Fehlproben.
  • Dokumentnamen: list_documents nennt den Wert für document (FreeCADs interner Name kann abweichen: führender _, _ statt -); UUID-artige Namen werden auf die Schreibweise mit Bindestrichen abgebildet. execute_code/run_macro/switch_document sind ausgeblendet — run_script ersetzt sie (execute_code scheiterte im GUI-losen Sandbox-Prozess an jedem Dokumentzugriff).
  • Oberfläche per VNC: Xvfb (fest :99, 1280×800) + x11vnc auf Port 5900, nur mit VNC_PASSWORD (ohne Variable kein Zugang). Der Port wird nicht veröffentlicht; der Iris-Server leitet ihn per WebSocket an einen noVNC-Client weiter. FreeCADs Hauptfenster füllt den Bildschirm (start_mcp.py).
  • Mounts (vom Plugin gesetzt): alle Workspaces schreibgeschützt unter /workspaces, /workspaces/freecad beschreibbar.
  • Schema-Patch (Dockerfile): pad_sketch.length akzeptiert Zahl und String. Upstream deklariert nur string, Hermes lehnt dann length: 8 ab.
  • init: true in der Compose-Datei ist nötig: xvfb-run hängt als PID 1 (Xvfb meldet "bereit" per SIGUSR1).

Sicherheit

Das Token ist Pflicht (MCP_AUTH_TOKEN). execute_code und run_macro laufen im Normalmodus in einem Sandbox-Subprozess; der "Dangerous Mode" von freecad-ai wird nicht aktiviert. Den Port nicht ungeschützt ins Internet stellen.

Lizenz

FreeCAD und freecad-ai stehen unter LGPL-2.1.