""" CadQuery MCP Server Ermöglicht Claude, CadQuery-Python-Code auszuführen und STL-Dateien zu erzeugen. """ import os import sys import tempfile import base64 import traceback from pathlib import Path from mcp.server.fastmcp import FastMCP import cadquery as cq from cadquery import exporters OUTPUT_DIR = Path(os.environ.get("CADQUERY_OUTPUT_DIR", Path.home() / "3d-models")) OUTPUT_DIR.mkdir(parents=True, exist_ok=True) mcp = FastMCP("cadquery") def _run_cadquery(code: str) -> cq.Workplane: """Führt CadQuery-Code aus und gibt das Ergebnis zurück.""" captured = {} def show_object(obj, name="result", options=None): captured["result"] = obj def show(obj, name="result", options=None): captured["result"] = obj namespace = { "cq": cq, "cadquery": cq, "show_object": show_object, "show": show, } exec(code, namespace) # noqa: S102 if "result" in captured: return captured["result"] # Letzte Variable suchen, die ein Workplane oder Shape ist for val in reversed(list(namespace.values())): if isinstance(val, (cq.Workplane, cq.Shape, cq.Assembly)): return val raise ValueError( "Kein CadQuery-Objekt gefunden. " "Bitte 'show_object(result)' am Ende des Codes aufrufen " "oder das Ergebnis in eine Variable namens 'result' speichern." ) @mcp.tool() def render_stl(code: str, filename: str = "model.stl") -> str: """ Rendert CadQuery-Python-Code als STL-Datei für den 3D-Drucker. Args: code: Gültiger CadQuery-Python-Code filename: Dateiname für die STL-Ausgabe (z.B. "halter.stl") Returns: Pfad zur erzeugten STL-Datei oder Fehlermeldung """ if not filename.endswith(".stl"): filename += ".stl" output_path = OUTPUT_DIR / filename try: result = _run_cadquery(code) exporters.export(result, str(output_path)) size_kb = output_path.stat().st_size // 1024 return f"STL erfolgreich erstellt: {output_path}\nDateigröße: {size_kb} KB" except Exception as e: return f"Fehler beim Rendern:\n{traceback.format_exc()}\nBitte CadQuery-Code prüfen." @mcp.tool() def preview_png(code: str, filename: str = "preview.png") -> str: """ Rendert eine PNG-Vorschau des CadQuery-Modells. Args: code: Gültiger CadQuery-Python-Code filename: Dateiname für die PNG-Ausgabe Returns: Base64-kodiertes PNG-Bild oder Fehlermeldung """ if not filename.endswith(".png"): filename += ".png" svg_path = OUTPUT_DIR / filename.replace(".png", ".svg") output_path = OUTPUT_DIR / filename try: result = _run_cadquery(code) exporters.export(result, str(svg_path)) size_bytes = svg_path.stat().st_size return f"SVG-Vorschau erstellt: {svg_path} ({size_bytes} Bytes)\n(PNG-Konvertierung erfordert zusätzliche Abhängigkeiten)" except Exception as e: return f"Fehler beim Rendern der Vorschau:\n{traceback.format_exc()}" @mcp.tool() def list_models() -> str: """Listet alle bisher erstellten 3D-Modelle im Output-Verzeichnis.""" files = list(OUTPUT_DIR.glob("*.stl")) if not files: return f"Keine STL-Dateien in {OUTPUT_DIR}" lines = [f"Modelle in {OUTPUT_DIR}:"] for f in sorted(files): size_kb = f.stat().st_size // 1024 lines.append(f" {f.name} ({size_kb} KB)") return "\n".join(lines) if __name__ == "__main__": mcp.run()