open-mcp-cad
<p align="center">
<img src="assets/wortmarke.svg" alt="Open MCP CAD" width="210">
</p>
# Open MCP CAD
**Die Brücke zwischen einem KI-Assistenten und deinem laufenden CAD.**
Ein MCP-Server plus CAD-Plugin, über das ein Sprachmodell Geometrie in einem
**geöffneten Cadwork-3D-Dokument** liest und erzeugt — mit Warteschlange,
Freigabe-Karten, Schreiblizenz, Rückgängig-Unterstützung und einem Fenster,
in dem man jederzeit sieht, was gerade läuft.
> **Was hier NICHT drin ist:** Konstruktionslogik. Kein Detail-Katalog, keine
> Bauteil-Generatoren, kein Fachwissen einer Branche. Dieses Repo ist das
> Rohr, nicht das Wasser. Eigenes Fachwissen hängst du über
> `OPEN_MCP_CAD_KNOWLEDGE` ein — siehe [Eigenes Fachwissen](#eigenes-fachwissen).
---
## Warum das existiert
Ein Sprachmodell kann cwapi3d-Code schreiben. Es in ein laufendes CAD zu
bekommen, ist das eigentliche Problem:
- **cwapi3d ist nicht thread-sicher.** Jeder API-Aufruf muss im Hauptthread
laufen, sequentiell. Wer das ignoriert, bekommt Abstürze, die nicht
reproduzierbar aussehen.
- **Das CAD darf nicht einfrieren**, während ein Auftrag läuft.
- **Nichts darf unbemerkt am Modell passieren.** Jeder Aufruf gehört in einen
Verlauf, jeder schreibende Zugriff hinter eine Freigabe.
- **Mehrere Dokumente gleichzeitig** brauchen getrennte Leitungen, die sich
nicht kreuzen.
Das alles steckt hier drin, gemessen statt behauptet: **über 600 Prüfungen
ohne CAD-Installation**, dazu ein Gate, das die Oberfläche wirklich baut und
bedient.
## Architektur
```
KI-Assistent --stdio--> MCP-Server --TCP 127.0.0.1:53127..53199--> CAD-Plugin
(Host) (open-mcp-cad) (in Cadwork)
|
cwapi3d
```
**Beliebig viele Leitungen.** Ein Menüeintrag **Open MCP CAD**, in so vielen
Cadwork-Fenstern gestartet, wie man braucht. Ein Klick öffnet das Dock und
verbindet: jedes Fenster bekommt den nächsten freien Port (53127–53199), ein
eigenes Log und einen eigenen Briefkasten — so bedienst du mehrere Dokumente
parallel, ohne dass sich die Leitungen kreuzen.
Jede Instanz trägt sich mit ihrem **Dokumentnamen** in eine Registry ein. Gefunden wird er
danach über das Dokument, nicht über den Port:
```bat
set OPEN_MCP_CAD_DOC=Seeblick
```
Das ist die Frage, die man wirklich hat. *"Welcher Port bedient Seeblick?"*
stand vorher nirgends — man musste es sich merken. Passen **mehrere**
laufende Instanzen auf den Suchbegriff, bricht der Client ab und nennt
beide: Code in der falschen Datei ist genau der Schaden, den der
Dokumentschutz verhindern soll.
Der Kern steht **einmal** in `cad_plugin/_core/omcad_bridge_core.py`; die
Plugin-Ordner werden daraus erzeugt und byteweise gegengeprüft. Neben dem
ausgelieferten `Open MCP CAD` liegen im Repo `Open MCP CAD A` … `F` mit
festen Ports (53127–53132) — für Tests und Hosts, die einen festen Port
brauchen.
### Wie das CAD bedienbar bleibt
Der TCP-Listener läuft in einem Nebenthread, die Bearbeitung eines Auftrags
ausschliesslich im Hauptthread — über einen `QTimer`, der sich in die
**bestehende** Ereignisschleife des CAD einhängt. Statusabfragen, Pause und
Beenden beantworten die Worker-Threads selbst und warten nie auf einen
laufenden Auftrag.
> Der naheliegende Weg — Fensternachrichten aus dem Plugin heraus zu pumpen —
> war nicht die Lösung, sondern die Ursache: er hat nachweislich eine
> Zugriffsverletzung im CAD-Prozess ausgelöst. Die Herleitung steht in
> [`docs/BRIDGE.md`](docs/BRIDGE.md), Abschnitt 2.
## Werkzeuge
| Werkzeug | Was es tut | Über die Brücke? |
|---|---|---|
| `get_document_info` | Dokumentname + Elementanzahl | ja |
| `get_connection_status` | Zustand, laufender Auftrag, Warteschlange, Schreiblizenz — **antwortet auch, während gezeichnet wird** | ja, ohne Hauptthread |
| `execute_cadwork_command` | führt cwapi3d-Python-Code aus | ja |
| `set_fast_draw` | schaltet die Bildschirm-Auffrischung während langer Zeichenläufe ab | ja |
| `report_check_note` | meldet eine Annahme oder Unsicherheit ins CAD-Fenster, mit anklickbaren Element-IDs | ja, ohne Hauptthread |
| `clear_check_notes` | räumt erledigte Prüfhinweise weg | ja, ohne Hauptthread |
| `get_pending_messages` | holt Nachrichten ab, die der Nutzer im CAD hinterlegt hat | ja, ohne Hauptthread |
| `list_stored_keys` / `clear_store` | Session-Speicher der Bridge (Element-ID-Listen) ansehen / leeren | ja |
| `create_from_init` | legt eine neue `.3d` als Kopie einer Vorlage an (überschreibt nie) | nein, lokal |
| `open_document` | öffnet eine `.3d` über die Windows-Verknüpfung | nein, lokal |
| `wait_for_bridge` | wartet, bis genau diese Datei verbunden ist, prüft sie und bindet die Sitzung daran | ja |
| `get_cadwork_api_help` | Module, Funktionen und Signaturen aus den Type-Stubs | nein, lokal |
| `get_working_examples` | geprüfte Code-Beispiele | nein, lokal |
| `get_detail` | Detail-Katalog — **nur mit eingehängtem Fachwissen** | nein, lokal |
**Neue Datei anlegen und verbinden:** `create_from_init` → `open_document` →
einmal auf **Open MCP CAD** klicken (der Nutzer oder der Agent-Host) →
`wait_for_bridge`. Erst danach schreibt ein Auftrag ins Modell.
## Eigenes Fachwissen
Das eingebaute Wissen in `open_mcp_cad/knowledge/` handelt ausschliesslich von
der **cwapi3d-Schnittstelle** — Stolperfallen, die jedem begegnen: dass
`cut_element_with_plane` die Anti-Normalen-Seite behält, dass `z_local` die
Drehung bestimmt, dass reine Berechnungen nichts über der Brücke verloren
haben. Jeder Eintrag ist an einem echten Modell verifiziert.
Fachwissen deiner Branche hängst du daneben:
```bat
set OPEN_MCP_CAD_KNOWLEDGE=C:\mein-katalog\knowledge
```
Ein solcher Ordner darf enthalten:
| Datei | Wirkung |
|---|---|
| `rules.md` | Regeln, die **jedem** Auftrag mitgegeben werden. Kurz halten — sie kosten bei jedem Aufruf Tokens. |
| `known_issues.json` | `{"issues": [...]}` — wird angehängt |
| `working_examples.json` | `{"examples": [...]}` — wird angehängt |
| `detail_catalog.json` | `{"details": [...]}` — wird angehängt, versorgt `get_detail` |
Mehrere Ordner mit `;` trennen (Windows). Ein Ordner, den es nicht gibt, wird
**gemeldet** und übersprungen — still schlucken hiesse, man merkt monatelang
nicht, dass die eigenen Regeln nie angekommen sind.
## Installation
**Voraussetzungen:** Windows, Cadwork 3D 2026 (Plugins laufen dort mit
Python 3.14), Python 3.10–3.13 für den MCP-Server.
**Als Anwender:** das Paket bauen (oder das ZIP aus den Releases nehmen),
entpacken, `install.cmd` doppelklicken. Es kopiert das Plugin ins neueste
Cadwork-Profil, richtet den Server in einem eigenen Python ein und zeigt den
Eintrag für das KI-Programm an. Details: [`verteilung/ANLEITUNG.md`](verteilung/ANLEITUNG.md).
```bash
python scripts/paket_bauen.py # -> dist/Open-MCP-CAD-<version>.zip
```
**Als Entwickler:**
```bash
git clone https://github.com/sebastiankoukoui/open-mcp-cad
cd open-mcp-cad
pip install -e .
```
Den Ordner `cad_plugin/Open MCP CAD/` ins Cadwork-Benutzerprofil kopieren:
```
C:\Users\Public\Documents\cadwork\userprofil_<JAHR>\3d\API.x64\Open MCP CAD\
```
> Nur ins Benutzerprofil, **nicht** zusätzlich nach `ProgramData` — sonst
> erscheint das Plugin in Cadwork doppelt.
Gegenprobe, ob Repo und Benutzerprofil übereinstimmen:
```bash
python scripts/deployment_pruefen.py
```
Host-Konfiguration (Beispiel Claude Desktop; unter Windows `pythonw` statt
`python`, sonst blitzt bei jedem Start ein Konsolenfenster auf):
```json
{
"mcpServers": {
"open-mcp-cad": { "command": "pythonw", "args": ["-m", "open_mcp_cad.server"] }
}
}
```
Mehrere Cadwork-Fenster: einen Eintrag je Instanz, mit
`"env": { "OPEN_MCP_CAD_PORT": "53128" }` oder `"env": { "OPEN_MCP_CAD_DOC": "Seeblick" }`.
**Verwechslungsschutz:** `OPEN_MCP_CAD_EXPECT_DOC` auf einen Teil des
Dateinamens setzen — dann prüft der Server vor **jedem** Aufruf, ob wirklich
das erwartete Dokument offen ist, statt Code in der falschen Instanz auszuführen.
## Prüfen
Alles ohne CAD-Installation — Cadwork wird dabei nie gestartet:
```bash
python tests/test_offline.py # Zustände, Pause, Beenden, Schreiblizenz, Dokumentschutz
python tests/test_wissen.py # Fachwissen-Lader
python tests/test_a_prototyp.py # Dashboard und Chat ohne Qt
python tests/test_registry.py # Registry und Ports (bindet echte Ports 53127–53199)
python tests/test_bootstrap.py # Datei-Bootstrap
python tests/test_paket.py # Verteilpaket
python scripts/plugins_generieren.py --pruefen
```
Mit PyQt6 kommt `tests/test_a_live.py` dazu — es baut die Oberfläche
wirklich und bedient sie, mit Attrappen statt Cadwork.
## Stand und Grenzen
**Was läuft:** die Brücke, beliebig viele Cadwork-Fenster über einen
Menüeintrag, das Dashboard mit Verbindungen, Verlauf, Prüfhinweisen und
Briefkasten, der Chat gegen Claude Code, der Datei-Bootstrap, alle Gates.
**Was noch nicht:**
- **Freie Modellwahl ist in Arbeit.** Der Chat startet heute das
Claude-Code-CLI als Kindprozess. Ein eigener Agenten-Loop über eine
OpenAI-kompatible Schnittstelle (Ollama, LM Studio, vLLM, OpenRouter, ...)
ist geplant und noch nicht gebaut.
- **Lokale Modelle: mit Vorbehalt.** `execute_cadwork_command` lässt das
Modell Python **generieren**. Kleine Modelle (7B/8B) beherrschen das und
zuverlässiges Tool-Calling in der Regel nicht. Die Anbindung wird gehen —
brauchbare Ergebnisse brauchen ein starkes Modell.
- **Nur Cadwork 3D.** Die Architektur (Warteschlange, Hauptthread-Zwang,
Freigaben) liesse sich auf andere CAD-Systeme mit Python-API übertragen;
getan ist es nicht.
- Die Type-Stubs stammen aus Cadwork 2025. Neuere Funktionen kennt
`get_cadwork_api_help` unter Umständen nicht; die echten Aufrufe laufen
über die eingebauten Module des CAD und sind davon unberührt.
## Sicherheit
- Die Brücke horcht ausschliesslich auf `127.0.0.1` — von aussen nicht
erreichbar.
- Ausgeführter Code wird gegen Import von `os`, `subprocess`, `shutil`,
`socket`, `urllib`, `requests` und `__import__` gefiltert. Das ist eine
Sperrliste nach bestem Wissen, **keine Sandbox**: wer dem Modell Zugriff auf
sein CAD gibt, gibt ihm Zugriff auf sein CAD.
- Werkzeuge, die das Modell anfassen, kommen in jeder Freigabestufe als Karte —
ausser in der einen Stufe, die man ausdrücklich wählen muss. Auch dort steht
jeder Aufruf im Verlauf: eine Automatik, die nichts hinterlässt, wäre
schlimmer als die Fragerei.
- Fällt die Freigabe aus, wird **nicht** ausgeführt. Das Gate fällt zu, nicht auf.
## Lizenz
[AGPL-3.0](LICENSE). Wer open-mcp-cad verändert weitergibt oder als Dienst
betreibt, gibt die Änderungen unter derselben Lizenz weiter.
Beiträge brauchen ein [CLA](CLA.md).
**Name und Logo sind nicht Teil der Lizenz.** Forken ist ausdrücklich erlaubt;
den Fork "Open MCP CAD" zu nennen, nicht.
*Cadwork ist eine Marke der cadwork informatik AG. Open MCP CAD ist ein
unabhängiges Projekt und steht in keiner Verbindung zu cadwork.*
TDQS
Scored across 15 tools
Each tool has a clearly distinct purpose: document info, code execution, connection status, note reporting/clearing, message retrieval, drawing toggle, API help, examples, details, session storage, and file bootstrap operations. There is no functional overlap or ambiguity between any pair.
All 15 tools follow a consistent verb_noun snake_case pattern (e.g., get_document_info, execute_cadwork_command, clear_check_notes, set_fast_draw). Verbs are clear and descriptive, and the naming convention is uniform throughout.
The 15 tools are well-scoped for the CAD integration domain, covering file management, connection handling, execution, knowledge retrieval, and user feedback. Each tool earns its place, and the count sits at the upper bound of the ideal range without feeling bloated.
The tool surface covers the full lifecycle: file bootstrap (create, open, wait), generic execution via execute_cadwork_command, connection status, session storage, user notes/messages, and knowledge support. The generic executor handles any missing specific operation, and no obvious gaps cause dead ends.