Release wordcraft-mcp and gridcraft-mcp 0.3.0: client-neutral skills, Cursor plugins.

This commit is contained in:
Dominic Gundel committed 2026-10-19 23:27:06 +02:00
1 parent debdf92877
commit 4c7e3ff720
26 files changed
+1008 -236

No files matched your search

+29 -69
View File
@@ -1,13 +1,13 @@
# Mitarbeiten
Einen Skill ohne Git installieren: ZIP aus der Tabelle in der [README](README.md) laden und in Claude hochladen. Dieser Text ist für alle, die einen Skill anlegen oder aktualisieren.
Einen Skill ohne Git installieren: ZIP aus der Tabelle in der [README](README.md) laden und in Claude hochladen; für Cursor das Cursor-Plugin-ZIP. Dieser Text ist für alle, die einen Skill anlegen oder aktualisieren.
## Aufbau eines Skills
```
skills/<name>/
├── SKILL.md Pflicht – Anweisungen für Claude (liegt im ZIP)
├── README.md Pflicht – Doku für Menschen (nicht im ZIP)
├── SKILL.md Pflicht – Anweisungen für den Agenten (liegt im ZIP; clientneutral)
├── README.md Pflicht – Doku für Menschen (nicht im ZIP; Client-Details hier)
├── CHANGELOG.md Pflicht – Versionen (nicht im ZIP)
├── extension/ optional – Claude-Desktop-Erweiterung (.mcpb)
│ ├── manifest.json
@@ -15,12 +15,14 @@ skills/<name>/
│ ├── upstream.json von scripts/fetch-cli geschrieben
│ ├── LICENSES/ Upstream-Lizenztexte
│ └── server/ CLI-exe nur beim Bauen (nicht committen)
├── scripts/ optional – Hilfsskripte, die Claude ausführen kann
├── references/ optional – Nachschlagematerial, das Claude bei Bedarf liest
├── scripts/ optional – Hilfsskripte, die der Agent ausführen kann
├── references/ optional – Nachschlagematerial
└── assets/ optional – Vorlagen, Bilder usw.
```
`README.md` hat dieselben Abschnitte wie [templates/skill/README.md](templates/skill/README.md): Zweck, Voraussetzungen, Installation, Einrichtung, Stolpersteine, Test, Deinstallation/Update, Link zum Changelog. Skills mit `extension/` beschreiben die Installation über `.mcpb` + ZIP und verweisen auf [docs/INSTALLATION.md](docs/INSTALLATION.md).
**Grundsatz:** `SKILL.md` enthält keine clientspezifischen Anweisungen (kein Claude Desktop, Cursor, Store-Pfad, Erweiterungs-UI, ToolSearch-Details). Solche Hinweise gehören in die Skill-README oder `docs/`. So nutzen Claude und Cursor dieselbe `SKILL.md`.
`README.md` hat dieselben Abschnitte wie [templates/skill/README.md](templates/skill/README.md). Skills mit `extension/` beschreiben die Claude-Installation über `.mcpb` + ZIP ([docs/INSTALLATION.md](docs/INSTALLATION.md)) und verweisen für Cursor auf die Wurzel-README / [docs/CURSOR.md](docs/CURSOR.md). Sinnvolle Abschnitte in der SKILL.md: Rezepte, Abschlussprüfung, Datenschutz (Ampel), wenn der Skill MCP-Werkzeuge steuert.
## Regeln
@@ -30,91 +32,49 @@ skills/<name>/
```yaml
---
name: <name>
description: "Wann dieser Skill verwendet werden soll – ein Satz."
description: "Wann dieser Skill verwendet werden soll – Auslöser und Abgrenzung."
---
```
`name` muss dem Ordnernamen entsprechen. `description` ist Pflicht, höchstens 1024 Zeichen, ohne spitze Klammern. Sie entscheidet, wann Claude den Skill benutzt – also beschreiben, *wann* er gebraucht wird, nicht nur *was* er ist. Enthält sie „: “, in Anführungszeichen setzen. Dieselbe `description` erscheint als Kurzbeschreibung in der Tabelle der Wurzel-README.
`name` muss dem Ordnernamen entsprechen. `description` ist Pflicht, höchstens 1024 Zeichen, ohne spitze Klammern. Keine clientspezifischen Zusatzfelder. Dieselbe `description` erscheint in der Tabelle der Wurzel-README.
- **Kodierung:** UTF-8 ohne BOM, Zeilenenden LF (regelt `.gitattributes`).
- **CHANGELOG.md:** Einträge als `## x.y.z (YYYY-MM-DD)`, neuester oben. Der oberste Eintrag ist die aktuelle Version.
- **CHANGELOG.md:** Einträge als `## x.y.z (YYYY-MM-DD)`, neuester oben.
## Cursor
Jedes Skill mit `extension/` bekommt beim Build **automatisch ein eigenes Cursor-Plugin** (`dist/<name>-cursor-v<ver>.zip`) und eine Tabellenzeile inkl. 1-Klick-Deeplink. 1:1 zur Claude-Seite: eine `.mcpb` ↔ ein Cursor-Plugin. **Keine Sammel-Plugins.** Build: `scripts/build-cursor` (von `package-all` aufgerufen). Nur `cursor/plugin-template/` liegt im Git; Ausgaben unter `dist/cursor/`.
## Neuer Skill
1. Ordner aus der Vorlage anlegen:
`scripts/new-skill.sh <name>` bzw. `scripts\new-skill.ps1 -Name <name>`
2. `SKILL.md` und `README.md` ausfüllen.
3. Prüfen:
`scripts/validate.sh <name>` bzw. `scripts\validate.ps1 -Name <name>`
4. Tabelle in der Wurzel-README neu erzeugen:
`scripts/update-index.sh` bzw. `scripts\update-index.ps1`
5. Committen und nach `main` pushen.
6. Tag setzen und pushen. Bestehende Tags nicht verschieben und nicht löschen. Der Push allein legt kein Release an.
```sh
git tag <name>/v<version>
git push origin main <name>/v<version>
```
7. Release anlegen (siehe unten): Pakete bauen und dem Tag als Anhänge hinzufügen.
1. `scripts/new-skill.sh <name>` bzw. `scripts\new-skill.ps1 -Name <name>`
2. `SKILL.md` und `README.md` ausfüllen (SKILL clientneutral).
3. `scripts/validate` und `scripts/update-index`
4. Committen, Taggen, Release (ZIP, ggf. `.mcpb`, Cursor-ZIP).
## Update eines Skills
1. `SKILL.md` und `README.md` ändern.
2. Im `CHANGELOG.md` einen neuen Eintrag `## x.y.z (YYYY-MM-DD)` oben einfügen.
3. Prüfen (`validate`), dann `update-index` ausführen.
4. Committen und nach `main` pushen.
5. Neuen Tag `<name>/v<version>` setzen und pushen. Der Tag muss exakt zur obersten CHANGELOG-Version passen. Danach das Release vom eigenen Rechner anlegen.
1. `SKILL.md` / `README.md` / ggf. `extension/` ändern.
2. CHANGELOG-Eintrag oben.
3. `validate`, `update-index`, committen, neuen Tag, Release.
## Versionen
- **Patch** (0.1.0 → 0.1.1): Korrekturen, Tippfehler, präzisere Formulierungen, Doku
- **Minor** (0.1.0 → 0.2.0): neue Abschnitte, neue bekannte Fallen, neue Beispiele
- **Major** (0.x → 1.0.0): geänderte Voraussetzungen oder Arbeitsweise, die bestehende Einrichtungen betreffen
- **Patch:** Korrekturen, Doku
- **Minor:** neue Abschnitte, Fallen, Beispiele, Cursor-/Claude-Auslieferung
- **Major:** geänderte Voraussetzungen oder Arbeitsweise
## Release
Ein Paket pro Skill, Dateiname `dist/<name>-v<version>.zip`. Im ZIP liegt der Ordner `<name>/` mit `SKILL.md` auf oberster Ebene. `README.md` und `CHANGELOG.md` werden nicht eingepackt.
Pakete: `dist/<name>-v<version>.zip` (nur SKILL.md), ggf. `dist/<name>-v<version>.mcpb`, `dist/<name>-cursor-v<version>.zip`.
Skills mit `extension/` liefern zusätzlich `dist/<name>-v<version>.mcpb`. Die `.mcpb` enthält **keine** CLI-EXE: sie zeigt auf die Installation aus dem ArtCraft-Launcher (`C:\Program Files\…`). `scripts/fetch-cli` prüft nur, dass die EXE lokal vorhanden ist, und aktualisiert `upstream.json` sowie die Lizenztexte. Als `entry_point` dient `server/README.txt`: die MCPB-Prüfung verlangt eine Datei im Paket; gestartet wird der Befehl aus `mcp_config.command`. `mcpb validate` besteht damit, und die Erweiterung startet so. Die `.mcpb` bleibt unsigniert, solange kein Code-Signing-Zertifikat vorliegt (`mcpb sign` braucht `--cert` / `--key`; `--self-signed` hilft nicht gegen Defender).
```sh
scripts/package.sh # nur Skill-ZIPs
scripts/package.sh <name>
scripts/package-mcpb.sh <name> # eine .mcpb
scripts/package-all.sh # ZIP + .mcpb wo extension/ existiert
```
Die `.mcpb` enthält **keine** CLI-EXE: sie zeigt auf den ArtCraft-Launcher (`C:\Program Files\…`). Als `entry_point` dient `server/README.txt` (MCPB-Prüfung verlangt eine Datei im Paket; gestartet wird `mcp_config.command`).
```powershell
powershell -ExecutionPolicy Bypass -File scripts\package.ps1
powershell -ExecutionPolicy Bypass -File scripts\package.ps1 -Name <name>
powershell -ExecutionPolicy Bypass -File scripts\package-mcpb.ps1 -Name <name>
powershell -ExecutionPolicy Bypass -File scripts\package-all.ps1
```
### Release veröffentlichen
Der Tag `<name>/v<version>` muss lokal und remote existieren. Danach entweder:
**Skript** (baut ZIP/`.mcpb` und hängt sie ans Release; nutzt dieselbe Anmeldung wie `git push`):
```powershell
powershell -ExecutionPolicy Bypass -File scripts\release.ps1 -Name <name>
```
```sh
scripts/release.sh <name>
```
**Oder manuell** in der Release-Oberfläche des Remotes:
1. Paket bauen (Befehle oben). Prüfen, dass `dist/<name>-v<version>.zip` die Einträge `<name>/` und `<name>/SKILL.md` enthält und weder `README.md` noch `CHANGELOG.md`.
2. Neues Release zum Tag `<name>/v<version>` anlegen, Titel `<name> <version>`.
3. Als Text den Abschnitt dieser Version aus `skills/<name>/CHANGELOG.md` einfügen.
4. `dist/<name>-v<version>.zip` und – falls vorhanden – `dist/<name>-v<version>.mcpb` anhängen.
## Hinweise zu den Skripten
- Für jedes Skript gibt es eine Bash- (`.sh`) und eine PowerShell-Variante (`.ps1`). Die Bash-Skripte brauchen `zip` und `unzip`, die PowerShell-Skripte laufen ohne Zusatztools unter Windows PowerShell 5.1 und PowerShell 7. `release.sh` braucht zusätzlich `curl` und `python3`; unter Windows genügt `release.ps1`.
- `.ps1`-Dateien enthalten nur ASCII-Zeichen. Windows PowerShell 5.1 liest UTF-8 ohne BOM als ANSI; Umlaute oder Gedankenstriche können ein Skript dort unbrauchbar machen.
- `package.ps1` baut ZIPs mit `System.IO.Compression` statt `Compress-Archive`, weil `Compress-Archive` unter 5.1 Pfade mit `\` schreibt.
- Unter Windows bei gesperrter Ausführungsrichtlinie: `powershell -ExecutionPolicy Bypass -File scripts\<skript>.ps1`
- Bash- und PowerShell-Varianten; `.ps1` nur ASCII; Dateien über `lib.ps1` als UTF-8 ohne BOM.
- Unter Windows: `powershell -ExecutionPolicy Bypass -File scripts\<skript>.ps1`
+20 -7
View File
@@ -1,22 +1,35 @@
# claude-skills
Sammlung von Skills für Claude. Jeder Skill ist ein abgeschlossener Ordner: `SKILL.md` für Claude, `README.md` für Menschen. Fertige Pakete liegen unter [Releases](https://git.gundel.dev/dg/claude-skills/releases).
Sammlung von Skills für Claude und Cursor. Jeder Skill ist ein abgeschlossener Ordner: `SKILL.md` für den Agenten (clientneutral), `README.md` für Menschen. Fertige Pakete liegen unter [Releases](https://git.gundel.dev/dg/claude-skills/releases).
Schritt-für-Schritt-Installation: [docs/INSTALLATION.md](docs/INSTALLATION.md).
**Für Kollegen (Claude Desktop):** [docs/INSTALLATION.md](docs/INSTALLATION.md).
**Cursor:** Kurz unten, Details in [docs/CURSOR.md](docs/CURSOR.md).
## Skills
<!-- skills:start -->
| Skill | Kurzbeschreibung | Version | Doku | Download | Erweiterung (.mcpb) |
|---|---|---|---|---|---|
| [gridcraft-mcp](skills/gridcraft-mcp/) | Excel-Arbeitsmappen (.xlsx, .csv) über den GridCraft-MCP-Server erstellen, öffnen, ändern, berechnen, formatieren und prüfen – Kalkulationen, Stücklisten, Listen, Diagramme, PDF-Export. | 0.2.0 | [README](skills/gridcraft-mcp/README.md) | [gridcraft-mcp-v0.2.0.zip](https://git.gundel.dev/dg/claude-skills/releases/download/gridcraft-mcp%2Fv0.2.0/gridcraft-mcp-v0.2.0.zip) | [gridcraft-mcp-v0.2.0.mcpb](https://git.gundel.dev/dg/claude-skills/releases/download/gridcraft-mcp%2Fv0.2.0/gridcraft-mcp-v0.2.0.mcpb) |
| [wordcraft-mcp](skills/wordcraft-mcp/) | Word-Dokumente (.docx, .odt, .md, PDF) über den WordCraft-MCP-Server erstellen, bearbeiten und prüfen, inkl. Nachverfolgung – mit erprobten Fallen aus WordCraft 0.8.0. | 0.2.0 | [README](skills/wordcraft-mcp/README.md) | [wordcraft-mcp-v0.2.0.zip](https://git.gundel.dev/dg/claude-skills/releases/download/wordcraft-mcp%2Fv0.2.0/wordcraft-mcp-v0.2.0.zip) | [wordcraft-mcp-v0.2.0.mcpb](https://git.gundel.dev/dg/claude-skills/releases/download/wordcraft-mcp%2Fv0.2.0/wordcraft-mcp-v0.2.0.mcpb) |
| Skill | Kurzbeschreibung | Version | Doku | Download | Erweiterung (.mcpb) | Cursor-Plugin | Cursor 1-Klick |
|---|---|---|---|---|---|---|---|
| [gridcraft-mcp](skills/gridcraft-mcp/) | Excel-Arbeitsmappen (.xlsx, .csv) mit dem GridCraft-MCP-Server erstellen, öffnen, ändern, berechnen und prüfen. Verwenden, wenn GridCraft-Werkzeuge verbunden sind oder der Nutzer GridCraft nennt; typisch für Kalkulationen, Stücklisten (BOM), Listen, Diagramme, PDF-Export. Nicht für eingebaute xlsx-Hilfen ohne GridCraft-Server. | 0.3.0 | [README](skills/gridcraft-mcp/README.md) | [gridcraft-mcp-v0.3.0.zip](https://git.gundel.dev/dg/claude-skills/releases/download/gridcraft-mcp%2Fv0.3.0/gridcraft-mcp-v0.3.0.zip) | [gridcraft-mcp-v0.3.0.mcpb](https://git.gundel.dev/dg/claude-skills/releases/download/gridcraft-mcp%2Fv0.3.0/gridcraft-mcp-v0.3.0.mcpb) | [gridcraft-mcp-cursor-v0.3.0.zip](https://git.gundel.dev/dg/claude-skills/releases/download/gridcraft-mcp%2Fv0.3.0/gridcraft-mcp-cursor-v0.3.0.zip) | [Add to Cursor](cursor://anysphere.cursor-deeplink/mcp/install?name=gridcraft&config=eyJncmlkY3JhZnQiOnsiYXJncyI6WyJtY3AiXSwiY29tbWFuZCI6IkM6XFxQcm9ncmFtIEZpbGVzXFxHcmlkQ3JhZnRcXGdyaWRjcmFmdC1jbGkuZXhlIn19) |
| [wordcraft-mcp](skills/wordcraft-mcp/) | Word-Dokumente (.docx, .odt, .md, PDF) mit dem WordCraft-MCP-Server erstellen, bearbeiten und prüfen (inkl. Nachverfolgung). Verwenden, wenn WordCraft-Werkzeuge verbunden sind oder der Nutzer WordCraft nennt; typisch für Angebote, Briefe, Betriebsanleitungen, Arbeitsanweisungen, 8D-Reports, Vorlagen. Nicht für eingebaute docx-Hilfen ohne WordCraft-Server. | 0.3.0 | [README](skills/wordcraft-mcp/README.md) | [wordcraft-mcp-v0.3.0.zip](https://git.gundel.dev/dg/claude-skills/releases/download/wordcraft-mcp%2Fv0.3.0/wordcraft-mcp-v0.3.0.zip) | [wordcraft-mcp-v0.3.0.mcpb](https://git.gundel.dev/dg/claude-skills/releases/download/wordcraft-mcp%2Fv0.3.0/wordcraft-mcp-v0.3.0.mcpb) | [wordcraft-mcp-cursor-v0.3.0.zip](https://git.gundel.dev/dg/claude-skills/releases/download/wordcraft-mcp%2Fv0.3.0/wordcraft-mcp-cursor-v0.3.0.zip) | [Add to Cursor](cursor://anysphere.cursor-deeplink/mcp/install?name=wordcraft&config=eyJ3b3JkY3JhZnQiOnsiYXJncyI6WyJtY3AiLCItLWF1dGhvciIsIkNsYXVkZSIsIi0tYXV0b21hdGlvbi1yZWFkLXJvb3QiLCIke3VzZXJIb21lfS9Eb2N1bWVudHMiLCItLWF1dG9tYXRpb24td3JpdGUtcm9vdCIsIiR7dXNlckhvbWV9L0RvY3VtZW50cy9DbGF1ZGUiXSwiY29tbWFuZCI6IkM6XFxQcm9ncmFtIEZpbGVzXFxXb3JkQ3JhZnRcXHdvcmRjcmFmdC1jbGkuZXhlIn19) |
<!-- skills:end -->
## Skill installieren
## Skill installieren (Claude)
1. In der Tabelle das ZIP des Skills laden.
2. In Claude **„+“ → „Skill erstellen“ → „Skill hochladen“** wählen und das ZIP hochladen.
3. Zusätzlich die `.mcpb`-Erweiterung installieren und einschalten (siehe [INSTALLATION.md](docs/INSTALLATION.md)).
## In Cursor installieren
1. Voraussetzung: ArtCraft-Launcher mit der jeweiligen App ([Abschnitt 1](docs/INSTALLATION.md#1-artcraft-launcher-und-apps-installieren)).
2. Cursor-Plugin-ZIP aus der Tabelle laden → nach `~/.cursor/plugins/local/<skill>` entpacken → **Developer: Reload Window**. Jedes Werkzeug einzeln, wie in Claude.
3. Alternativ: „Add to Cursor“ (1-Klick) für den MCP-Server und den Skill-Ordner nach `~/.cursor/skills/` kopieren.
4. WordCraft: Lese-/Schreib-Ordner in Plugin-Einstellungen bzw. `~/.cursor/mcp.json` prüfen (Standard: Lese = Dokumente, Schreib = Dokumente\Claude).
5. Test: im Agent „Sind die WordCraft-Werkzeuge verfügbar?“
6. Auch Cursor sendet Inhalte an Cloud-Modelle → Datenschutz-Ampel in den Skills beachten.
Mehr: [docs/CURSOR.md](docs/CURSOR.md).
## Mitarbeiten
@@ -0,0 +1,9 @@
{
"name": "SKILL_NAME",
"version": "0.0.0",
"description": "SKILL_DESCRIPTION",
"author": {
"name": "Dominic Gundel"
},
"license": "MIT"
}
+4
View File
@@ -0,0 +1,4 @@
# Cursor plugin template
Build output is generated by `scripts/build-cursor` into `dist/cursor/plugins/<skill>/`.
Do not hand-edit packages under `dist/`.
+73
View File
@@ -0,0 +1,73 @@
# Cursor: WordCraft und GridCraft
Kurzfassung in der [Wurzel-README](../README.md). Für Claude Desktop: [INSTALLATION.md](INSTALLATION.md).
Jedes Werkzeug ist ein **eigenes** Cursor-Plugin (1:1 zur Claude-`.mcpb`). Keine Sammel-Plugins.
## Voraussetzung
1. [ArtCraft-Launcher](https://getartcraft.com/apps) und darin WordCraft bzw. GridCraft (Standardpfad `C:\Program Files\…`).
2. Cursor Desktop.
## Plugin installieren (empfohlen)
1. `<skill>-cursor-vX.Y.Z.zip` aus dem Release laden (Spalte „Cursor-Plugin“ in der README-Tabelle).
2. Nach `~/.cursor/plugins/local/<skill>` entpacken (Windows: `%USERPROFILE%\.cursor\plugins\local\<skill>`). Der Ordner muss `.cursor-plugin/plugin.json`, `skills/` und ggf. `mcp.json` enthalten.
3. **Developer: Reload Window**.
4. Unter Customize prüfen, dass Skill und MCP-Server sichtbar sind.
WordCraft: Lese-/Schreib-Ordner in den Plugin-Variablen (Configure) oder in `mcp.json` prüfen. Standard: Lese = `${userHome}/Documents`, Schreib = `${userHome}/Documents/Claude`.
## Alternativ: nur MCP + Skill
1. Spalte „Cursor 1-Klick“ / „Add to Cursor“ für den MCP-Server.
2. Skill-Ordner aus `dist/cursor/skills/<skill>/` (oder dem Plugin-ZIP unter `skills/<skill>/`) nach `~/.cursor/skills/<skill>/` kopieren.
Manuelle `~/.cursor/mcp.json` (Ausschnitt WordCraft):
```json
{
"mcpServers": {
"wordcraft": {
"command": "C:\\Program Files\\WordCraft\\wordcraft-cli.exe",
"args": [
"mcp",
"--author", "Claude",
"--automation-read-root", "${userHome}/Documents",
"--automation-write-root", "${userHome}/Documents/Claude"
]
}
}
}
```
GridCraft:
```json
{
"mcpServers": {
"gridcraft": {
"command": "C:\\Program Files\\GridCraft\\gridcraft-cli.exe",
"args": ["mcp"]
}
}
}
```
Unterstützte Variablen in `mcp.json`: `${userHome}`, `${env:NAME}`, `${workspaceFolder}`, `${pathSeparator}` (siehe Cursor-MCP-Doku). In Plugin-`mcp.json` zusätzlich Plugin-Variablen (`${READ_ROOT}`, …) und `${CURSOR_PLUGIN_ROOT}` (hier unnötig, keine gebündelte EXE).
## Test
Im Agent: „Sind die WordCraft-Werkzeuge verfügbar?“ bzw. GridCraft. Kleines Testdokument im Schreib-Ordner anlegen.
## Probleme
| Problem | Lösung |
|---|---|
| Keine Werkzeuge | Plugin unter `plugins/local/<skill>`? Reload? CLI unter `C:\Program Files\…`? |
| WordCraft path rejected | Schreib-Ordner prüfen (`WRITE_ROOT` / mcp.json). |
| Doppelte Server | Alten Eintrag in `~/.cursor/mcp.json` entfernen, wenn das Plugin denselben Namen (`wordcraft` / `gridcraft`) registriert. |
## Datenschutz
Auch Cursor sendet Inhalte an Cloud-Modelle. Ampel wie in den Skills: personenbezogene und NDA-Daten nicht in die Cloud-KI.
+9 -7
View File
@@ -17,7 +17,7 @@ Ohne Erweiterung kann Claude nichts tun, ohne Skill macht es mehr Fehler. Instal
- Windows 10 oder 11
- **Claude Desktop** installiert und angemeldet (die App, nicht nur der Browser)
- Ein eigener Ordner, in den Claude speichern darf, z. B. `Dokumente\Claude-Ausgabe`. Leg ihn jetzt an.
- Ein eigener **Schreib-Ordner**, z. B. `Dokumente\Claude`. Leg ihn jetzt an (eng halten). Der **Lese-Ordner** darf weit sein (z. B. ganzer Ordner Dokumente).
---
@@ -31,10 +31,10 @@ Installiere den [ArtCraft-Launcher](https://getartcraft.com/apps) und darin **Wo
## 2. Dateien herunterladen
Lade jeweils die Version **0.2.0** herunter:
Lade jeweils die Version **0.3.0** herunter:
- [wordcraft-mcp-v0.2.0.mcpb](https://git.gundel.dev/dg/claude-skills/releases/download/wordcraft-mcp%2Fv0.2.0/wordcraft-mcp-v0.2.0.mcpb) und [wordcraft-mcp-v0.2.0.zip](https://git.gundel.dev/dg/claude-skills/releases/download/wordcraft-mcp%2Fv0.2.0/wordcraft-mcp-v0.2.0.zip)
- [gridcraft-mcp-v0.2.0.mcpb](https://git.gundel.dev/dg/claude-skills/releases/download/gridcraft-mcp%2Fv0.2.0/gridcraft-mcp-v0.2.0.mcpb) und [gridcraft-mcp-v0.2.0.zip](https://git.gundel.dev/dg/claude-skills/releases/download/gridcraft-mcp%2Fv0.2.0/gridcraft-mcp-v0.2.0.zip)
- [wordcraft-mcp-v0.3.0.mcpb](https://git.gundel.dev/dg/claude-skills/releases/download/wordcraft-mcp%2Fv0.3.0/wordcraft-mcp-v0.3.0.mcpb) und [wordcraft-mcp-v0.3.0.zip](https://git.gundel.dev/dg/claude-skills/releases/download/wordcraft-mcp%2Fv0.3.0/wordcraft-mcp-v0.3.0.zip)
- [gridcraft-mcp-v0.3.0.mcpb](https://git.gundel.dev/dg/claude-skills/releases/download/gridcraft-mcp%2Fv0.3.0/gridcraft-mcp-v0.3.0.mcpb) und [gridcraft-mcp-v0.3.0.zip](https://git.gundel.dev/dg/claude-skills/releases/download/gridcraft-mcp%2Fv0.3.0/gridcraft-mcp-v0.3.0.zip)
Die ZIP-Dateien **nicht entpacken**.
@@ -49,8 +49,8 @@ Für jede `.mcpb`-Datei:
*Klappt beides nicht:* Einstellungen → Erweiterungen → Erweiterte Einstellungen → „Erweiterung installieren…“ → Datei auswählen.
3. Es öffnet sich ein Installationsfenster. Angaben prüfen und bestätigen.
4. **Nur bei WordCraft for Claude** fragt Claude nach zwei Ordnern:
- **Lese-Ordner:** Hier darf Claude Dokumente lesen, z. B. `Dokumente`.
- **Schreib-Ordner:** Nur hier darf Claude speichern – deinen Ordner `Dokumente\Claude-Ausgabe` wählen. Nicht denselben wie den Lese-Ordner, dann bleiben deine Originale sicher.
- **Lese-Ordner (weit):** z. B. `Dokumente` oder der Benutzerordner. Lesen ist per Freigabe-Dialog kontrollierbar.
- **Schreib-Ordner (eng):** nur hier darf Claude speichern – z. B. `Dokumente\Claude`. Nicht denselben wie den Lese-Ordner.
5. Installieren. Die Erweiterung erscheint unter Einstellungen → Erweiterungen.
**Danach unter Einstellungen → Erweiterungen prüfen, dass beide Erweiterungen eingeschaltet sind.** Frisch installierte Erweiterungen können ausgeschaltet sein.
@@ -85,6 +85,8 @@ Einen **neuen** Chat öffnen (offene Chats sehen neue Werkzeuge evtl. erst spät
Claude sollte beide Werkzeuge finden und eine `.xlsx`-Datei im Ausgabeordner speichern. Beim ersten Mal fragt Claude, ob es die Werkzeuge benutzen darf – erlauben. Die Werkzeuge heißen mit Präfix `…WordCraft_for_Claude…` bzw. `…GridCraft_for_Claude…`.
Lass bei WordCraft `open_document` / `save_document` und bei GridCraft `open_workbook` / `save_workbook` / `execute_command` auf **„Immer fragen“**, wenn du Pfade mitkontrollieren willst.
---
## Sicher arbeiten – bitte lesen
@@ -109,7 +111,7 @@ Claude sollte beide Werkzeuge finden und eine `.xlsx`-Datei im Ausgabeordner spe
## Aktualisieren
Neue Version von der Releases-Seite laden, `.mcpb` erneut installieren und die neue Skill-ZIP hochladen. Fragt Claude, ob die bestehende Version ersetzt werden soll: ja. Danach Claude neu starten.
Neue Version laden, `.mcpb` erneut installieren und die neue Skill-ZIP hochladen. Fragt Claude, ob die bestehende Version ersetzt werden soll: ja. Danach Claude neu starten.
## Entfernen
+197
View File
@@ -0,0 +1,197 @@
# Builds dist\cursor\ from skills\: flat skill copies, mcp snippets, one plugin per skill.
# Usage: scripts\build-cursor.ps1 [-Name <skill-name>]
param([string]$Name)
. (Join-Path $PSScriptRoot 'lib.ps1')
. (Join-Path $PSScriptRoot 'cursor-deeplink.ps1')
$CursorDist = Join-Path $DistDir 'cursor'
$ServerKeys = @{
'wordcraft-mcp' = 'wordcraft'
'gridcraft-mcp' = 'gridcraft'
}
function Get-McpServerKey([string]$SkillName) {
if ($ServerKeys.ContainsKey($SkillName)) { return $ServerKeys[$SkillName] }
# fallback: strip trailing -mcp
if ($SkillName -match '^(.+)-mcp$') { return $Matches[1] }
return $SkillName
}
function Convert-ClaudeArgsToCursor([object[]]$CliArgs) {
$out = New-Object System.Collections.Generic.List[string]
foreach ($a in $CliArgs) {
$s = [string]$a
if ($s -eq '${user_config.author}') { $out.Add('${AUTHOR}'); continue }
if ($s -eq '${user_config.read_root}') { $out.Add('${READ_ROOT}'); continue }
if ($s -eq '${user_config.write_root}') { $out.Add('${WRITE_ROOT}'); continue }
$out.Add($s)
}
return , $out.ToArray()
}
function Convert-ArgsToUserHomeDefaults([object[]]$CliArgs) {
$out = New-Object System.Collections.Generic.List[string]
foreach ($a in $CliArgs) {
$s = [string]$a
if ($s -eq '${user_config.author}' -or $s -eq '${AUTHOR}') { $out.Add('Claude'); continue }
if ($s -eq '${user_config.read_root}' -or $s -eq '${READ_ROOT}') { $out.Add('${userHome}/Documents'); continue }
if ($s -eq '${user_config.write_root}' -or $s -eq '${WRITE_ROOT}') { $out.Add('${userHome}/Documents/Claude'); continue }
$out.Add($s)
}
return , $out.ToArray()
}
function Build-OneSkill([string]$N) {
$dir = Join-Path $SkillsDir $N
if (-not (Test-Path $dir -PathType Container)) {
Write-Host "skills/$N fehlt."
return $false
}
$ver = Get-SkillVersion $dir
if (-not $ver) {
Write-Host "CHANGELOG von $N hat keine Version."
return $false
}
$skillPath = Join-Path $dir 'SKILL.md'
$fm = Get-Frontmatter $skillPath
if ($null -eq $fm) {
Write-Host "${N}: kein Frontmatter."
return $false
}
$fmName = Get-FmValue $fm 'name'
$desc = Get-FmValue $fm 'description'
if ($fmName -cne $N) {
Write-Host "${N}: Frontmatter name '$fmName' != Ordner."
return $false
}
if (-not $desc -or $desc.Length -gt 1024) {
Write-Host "${N}: description fehlt oder > 1024."
return $false
}
# Flat skill copy
$flatDir = Join-Path (Join-Path $CursorDist 'skills') $N
New-Item -ItemType Directory -Force -Path $flatDir | Out-Null
Copy-Item -LiteralPath $skillPath -Destination (Join-Path $flatDir 'SKILL.md') -Force
$extManPath = Join-Path $dir 'extension\manifest.json'
$hasExt = Test-Path $extManPath
$pluginRoot = Join-Path (Join-Path $CursorDist 'plugins') $N
if (Test-Path $pluginRoot) { Remove-Item $pluginRoot -Recurse -Force }
New-Item -ItemType Directory -Force -Path (Join-Path $pluginRoot '.cursor-plugin') | Out-Null
$pluginSkillDir = Join-Path (Join-Path $pluginRoot 'skills') $N
New-Item -ItemType Directory -Force -Path $pluginSkillDir | Out-Null
Copy-Item -LiteralPath $skillPath -Destination (Join-Path $pluginSkillDir 'SKILL.md') -Force
$displayDesc = $desc
$authorName = 'Dominic Gundel'
$pluginVars = $null
$mcpForPlugin = $null
$mcpStandalone = $null
$serverKey = Get-McpServerKey $N
if ($hasExt) {
$man = (Read-Text $extManPath) | ConvertFrom-Json
if ($man.version -cne $ver) {
Write-Host "${N}: manifest version '$($man.version)' != CHANGELOG '$ver'."
return $false
}
$dn = [string]$man.display_name
if ($dn -match ' for Claude$') {
$displayDesc = ($dn -replace ' for Claude$', ' for Cursor') + '. ' + $desc
}
elseif ($man.description) {
$displayDesc = [string]$man.description
}
if ($man.author -and $man.author.name) { $authorName = [string]$man.author.name }
$cmd = [string]$man.server.mcp_config.command
$argsRaw = @($man.server.mcp_config.args)
$argsPlugin = Convert-ClaudeArgsToCursor $argsRaw
$argsHome = Convert-ArgsToUserHomeDefaults $argsRaw
$transportPlugin = @{ command = $cmd; args = @($argsPlugin) }
$transportHome = @{ command = $cmd; args = @($argsHome) }
$mcpForPlugin = @{ mcpServers = @{ $serverKey = $transportPlugin } }
$mcpStandalone = @{ mcpServers = @{ $serverKey = $transportHome } }
if ($man.user_config) {
$props = @{}
$required = @()
if ($man.user_config.read_root) {
$props['READ_ROOT'] = @{
type = 'string'
title = 'Lese-Ordner'
description = 'Weit fassen (Standard: Dokumente).'
default = '${userHome}/Documents'
}
$required += 'READ_ROOT'
}
if ($man.user_config.write_root) {
$props['WRITE_ROOT'] = @{
type = 'string'
title = 'Schreib-Ordner'
description = 'Eng halten (Standard: Dokumente/Claude).'
default = '${userHome}/Documents/Claude'
}
$required += 'WRITE_ROOT'
}
if ($man.user_config.author) {
$props['AUTHOR'] = @{
type = 'string'
title = 'Autorname'
description = 'Name fuer nachverfolgte Aenderungen.'
default = 'Claude'
}
}
if ($props.Count -gt 0) {
$pluginVars = @{
type = 'object'
properties = $props
}
if ($required.Count -gt 0) { $pluginVars['required'] = $required }
}
}
$mcpDir = Join-Path $CursorDist 'mcp'
New-Item -ItemType Directory -Force -Path $mcpDir | Out-Null
$snippetPath = Join-Path $mcpDir "$N.json"
Write-Text $snippetPath (($mcpStandalone | ConvertTo-Json -Depth 20) + "`n")
}
$pluginJson = @{
name = $N
version = $ver
description = $displayDesc
author = @{ name = $authorName }
license = 'MIT'
homepage = 'https://git.gundel.dev/dg/claude-skills'
repository = 'https://git.gundel.dev/dg/claude-skills.git'
}
if ($pluginVars) { $pluginJson['variables'] = $pluginVars }
Write-Text (Join-Path $pluginRoot '.cursor-plugin\plugin.json') (($pluginJson | ConvertTo-Json -Depth 20) + "`n")
if ($mcpForPlugin) {
Write-Text (Join-Path $pluginRoot 'mcp.json') (($mcpForPlugin | ConvertTo-Json -Depth 20) + "`n")
}
# Validate JSON round-trip
$null = (Read-Text (Join-Path $pluginRoot '.cursor-plugin\plugin.json')) | ConvertFrom-Json
if ($mcpForPlugin) {
$null = (Read-Text (Join-Path $pluginRoot 'mcp.json')) | ConvertFrom-Json
}
Write-Host "OK cursor plugin $N $ver"
return $true
}
if ($Name) { $names = @($Name) } else { $names = @(Get-SkillNames) }
New-Item -ItemType Directory -Force -Path $CursorDist | Out-Null
$ok = $true
foreach ($n in $names) {
if (-not (Build-OneSkill $n)) { $ok = $false }
}
if (-not $ok) { exit 1 }
exit 0
+199
View File
@@ -0,0 +1,199 @@
#!/usr/bin/env bash
# Builds dist/cursor/ from skills/: flat skill copies, mcp snippets, one plugin per skill.
# Usage: scripts/build-cursor.sh [skill-name]
set -euo pipefail
source "$(dirname "$0")/lib.sh"
name_filter="${1:-}"
CURSOR_DIST="$DIST_DIR/cursor"
python3 - "$ROOT" "$SKILLS_DIR" "$CURSOR_DIST" "$name_filter" <<'PY'
import json, os, re, shutil, sys
from pathlib import Path
root, skills_dir, cursor_dist, name_filter = Path(sys.argv[1]), Path(sys.argv[2]), Path(sys.argv[3]), sys.argv[4]
SERVER_KEYS = {"wordcraft-mcp": "wordcraft", "gridcraft-mcp": "gridcraft"}
def skill_names():
names = sorted([p.name for p in skills_dir.iterdir() if p.is_dir()], key=lambda s: s)
if name_filter:
names = [n for n in names if n == name_filter]
return names
def skill_version(d: Path) -> str:
p = d / "CHANGELOG.md"
if not p.exists():
return ""
for line in p.read_text(encoding="utf-8").splitlines():
m = re.match(r"^## (\d+\.\d+\.\d+) \(\d{4}-\d{2}-\d{2}\)\s*$", line)
if m:
return m.group(1)
return ""
def frontmatter(path: Path):
text = path.read_text(encoding="utf-8").replace("\r", "")
lines = text.split("\n")
if not lines or lines[0] != "---":
return None
out = []
for line in lines[1:]:
if line == "---":
return out
out.append(line)
return None
def fm_value(lines, key):
for line in lines:
m = re.match(rf"^{re.escape(key)}\s*:(.*)$", line)
if m:
v = m.group(1).strip()
if (v.startswith('"') and v.endswith('"')) or (v.startswith("'") and v.endswith("'")):
v = v[1:-1]
return v
return None
def server_key(name):
if name in SERVER_KEYS:
return SERVER_KEYS[name]
m = re.match(r"^(.+)-mcp$", name)
return m.group(1) if m else name
def map_args_plugin(args):
out = []
for a in args:
s = str(a)
if s == "${user_config.author}":
out.append("${AUTHOR}")
elif s == "${user_config.read_root}":
out.append("${READ_ROOT}")
elif s == "${user_config.write_root}":
out.append("${WRITE_ROOT}")
else:
out.append(s)
return out
def map_args_home(args):
out = []
for a in args:
s = str(a)
if s in ("${user_config.author}", "${AUTHOR}"):
out.append("Claude")
elif s in ("${user_config.read_root}", "${READ_ROOT}"):
out.append("${userHome}/Documents")
elif s in ("${user_config.write_root}", "${WRITE_ROOT}"):
out.append("${userHome}/Documents/Claude")
else:
out.append(s)
return out
ok = True
cursor_dist.mkdir(parents=True, exist_ok=True)
for name in skill_names():
d = skills_dir / name
ver = skill_version(d)
skill = d / "SKILL.md"
fm = frontmatter(skill)
if not ver or fm is None:
print(f"FEHLER {name}: Version/Frontmatter", file=sys.stderr)
ok = False
continue
if fm_value(fm, "name") != name:
print(f"FEHLER {name}: name mismatch", file=sys.stderr)
ok = False
continue
desc = fm_value(fm, "description") or ""
if not desc or len(desc) > 1024:
print(f"FEHLER {name}: description", file=sys.stderr)
ok = False
continue
flat = cursor_dist / "skills" / name
flat.mkdir(parents=True, exist_ok=True)
shutil.copy2(skill, flat / "SKILL.md")
plugin = cursor_dist / "plugins" / name
if plugin.exists():
shutil.rmtree(plugin)
(plugin / ".cursor-plugin").mkdir(parents=True)
(plugin / "skills" / name).mkdir(parents=True)
shutil.copy2(skill, plugin / "skills" / name / "SKILL.md")
display_desc = desc
author = "Dominic Gundel"
variables = None
man_path = d / "extension" / "manifest.json"
sk = server_key(name)
if man_path.exists():
man = json.loads(man_path.read_text(encoding="utf-8"))
if man.get("version") != ver:
print(f"FEHLER {name}: manifest version != CHANGELOG", file=sys.stderr)
ok = False
continue
dn = man.get("display_name") or ""
if dn.endswith(" for Claude"):
display_desc = dn.replace(" for Claude", " for Cursor") + ". " + desc
elif man.get("description"):
display_desc = man["description"]
if man.get("author", {}).get("name"):
author = man["author"]["name"]
cmd = man["server"]["mcp_config"]["command"]
args = list(man["server"]["mcp_config"].get("args") or [])
mcp_plugin = {"mcpServers": {sk: {"command": cmd, "args": map_args_plugin(args)}}}
mcp_home = {"mcpServers": {sk: {"command": cmd, "args": map_args_home(args)}}}
(cursor_dist / "mcp").mkdir(parents=True, exist_ok=True)
(cursor_dist / "mcp" / f"{name}.json").write_text(
json.dumps(mcp_home, indent=2, ensure_ascii=False) + "\n", encoding="utf-8"
)
(plugin / "mcp.json").write_text(
json.dumps(mcp_plugin, indent=2, ensure_ascii=False) + "\n", encoding="utf-8"
)
uc = man.get("user_config") or {}
props = {}
required = []
if "read_root" in uc:
props["READ_ROOT"] = {
"type": "string",
"title": "Lese-Ordner",
"description": "Weit fassen (Standard: Dokumente).",
"default": "${userHome}/Documents",
}
required.append("READ_ROOT")
if "write_root" in uc:
props["WRITE_ROOT"] = {
"type": "string",
"title": "Schreib-Ordner",
"description": "Eng halten (Standard: Dokumente/Claude).",
"default": "${userHome}/Documents/Claude",
}
required.append("WRITE_ROOT")
if "author" in uc:
props["AUTHOR"] = {
"type": "string",
"title": "Autorname",
"description": "Name fuer nachverfolgte Aenderungen.",
"default": "Claude",
}
if props:
variables = {"type": "object", "properties": props}
if required:
variables["required"] = required
plugin_json = {
"name": name,
"version": ver,
"description": display_desc,
"author": {"name": author},
"license": "MIT",
"homepage": "https://git.gundel.dev/dg/claude-skills",
"repository": "https://git.gundel.dev/dg/claude-skills.git",
}
if variables:
plugin_json["variables"] = variables
(plugin / ".cursor-plugin" / "plugin.json").write_text(
json.dumps(plugin_json, indent=2, ensure_ascii=False) + "\n", encoding="utf-8"
)
print(f"OK cursor plugin {name} {ver}")
sys.exit(0 if ok else 1)
PY
+38
View File
@@ -0,0 +1,38 @@
# Builds a Cursor MCP install deeplink from a server name and config object (hashtable/JSON).
# Usage: . scripts\cursor-deeplink.ps1; New-CursorDeeplink -Name wordcraft -Config @{ command='...'; args=@(...) }
# Or: scripts\cursor-deeplink.ps1 -Name wordcraft -ConfigJson '{...}'
param(
[string]$Name,
[string]$ConfigJson
)
. (Join-Path $PSScriptRoot 'lib.ps1')
function New-CursorDeeplink([string]$ServerName, $Config) {
# Config = server transport object (command/args/...) OR { serverName = transport }.
# Deeplink uses name= + base64(JSON of the transport object keyed by name), per Cursor docs.
if ($Config -is [string]) {
$obj = $Config | ConvertFrom-Json
}
else {
$obj = $Config
}
# Normalize to { name: transport }
$props = @($obj.PSObject.Properties.Name)
if ($props.Count -eq 1 -and $props[0] -eq $ServerName) {
$payload = $obj
}
elseif ($obj.command -or $obj.PSObject.Properties['command']) {
$payload = @{ $ServerName = $obj }
}
else {
$payload = $obj
}
$json = ($payload | ConvertTo-Json -Compress -Depth 20)
$bytes = $Utf8NoBom.GetBytes($json)
$b64 = [Convert]::ToBase64String($bytes).TrimEnd('=').Replace('+', '-').Replace('/', '_')
return "cursor://anysphere.cursor-deeplink/mcp/install?name=$([Uri]::EscapeDataString($ServerName))&config=$b64"
}
if ($Name -and $ConfigJson) {
Write-Output (New-CursorDeeplink -ServerName $Name -Config $ConfigJson)
}
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/env bash
# Prints a Cursor MCP install deeplink.
# Usage: scripts/cursor-deeplink.sh <server-name> '<transport-json>'
# transport-json = {"command":"...","args":[...]}
set -euo pipefail
name="${1:-}"
config="${2:-}"
if [[ -z "$name" || -z "$config" ]]; then
echo "Aufruf: scripts/cursor-deeplink.sh <server-name> '<transport-json>'" >&2
exit 1
fi
python3 -c '
import base64, json, sys, urllib.parse
name, raw = sys.argv[1], sys.argv[2]
transport = json.loads(raw)
payload = {name: transport}
b64 = base64.urlsafe_b64encode(json.dumps(payload, separators=(",", ":")).encode("utf-8")).decode("ascii").rstrip("=")
print(f"cursor://anysphere.cursor-deeplink/mcp/install?name={urllib.parse.quote(name)}&config={b64}")
' "$name" "$config"
+37 -1
View File
@@ -1,7 +1,10 @@
# Builds ZIP for every skill and .mcpb when skills\<name>\extension\ exists.
# Builds ZIP for every skill, .mcpb when extension/ exists, and Cursor plugin ZIPs.
# Usage: scripts\package-all.ps1
. (Join-Path $PSScriptRoot 'lib.ps1')
Add-Type -AssemblyName System.IO.Compression
Add-Type -AssemblyName System.IO.Compression.FileSystem
& (Join-Path $PSScriptRoot 'package.ps1')
if ($LASTEXITCODE -ne 0) { exit 1 }
@@ -12,3 +15,36 @@ foreach ($n in (Get-SkillNames)) {
if ($LASTEXITCODE -ne 0) { exit 1 }
}
}
& (Join-Path $PSScriptRoot 'build-cursor.ps1')
if ($LASTEXITCODE -ne 0) { exit 1 }
foreach ($n in (Get-SkillNames)) {
$pluginDir = Join-Path $DistDir "cursor\plugins\$n"
if (-not (Test-Path $pluginDir)) { continue }
$ver = Get-SkillVersion (Join-Path $SkillsDir $n)
$out = Join-Path $DistDir "$n-cursor-v$ver.zip"
if (Test-Path $out) { Remove-Item $out -Force }
$src = (Get-Item $pluginDir).FullName
$files = @(Get-ChildItem -Path $src -Recurse -File -Force | ForEach-Object { $_.FullName })
[Array]::Sort($files, [StringComparer]::Ordinal)
$zip = [IO.Compression.ZipFile]::Open($out, [IO.Compression.ZipArchiveMode]::Create)
try {
[void]$zip.CreateEntry("$n/")
foreach ($f in $files) {
$rel = $f.Substring($src.Length).TrimStart('\', '/') -replace '\\', '/'
[void][IO.Compression.ZipFileExtensions]::CreateEntryFromFile($zip, $f, "$n/$rel")
}
}
finally { $zip.Dispose() }
Write-Host ''
Write-Host "dist/$n-cursor-v$ver.zip"
$read = [IO.Compression.ZipFile]::OpenRead($out)
try {
foreach ($e in $read.Entries) { Write-Host ('{0,9} {1}' -f $e.Length, $e.FullName) }
}
finally { $read.Dispose() }
}
+16 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
# Builds ZIP for every skill and .mcpb when skills/<name>/extension/ exists.
# Builds ZIP for every skill, .mcpb when extension/ exists, and Cursor plugin ZIPs.
# Usage: scripts/package-all.sh
set -euo pipefail
source "$(dirname "$0")/lib.sh"
@@ -12,3 +12,18 @@ while IFS= read -r name; do
bash "$(dirname "$0")/package-mcpb.sh" "$name"
fi
done < <(skill_names)
bash "$(dirname "$0")/build-cursor.sh"
while IFS= read -r name; do
[[ -z "$name" ]] && continue
plugin="$DIST_DIR/cursor/plugins/$name"
[[ -d "$plugin" ]] || continue
ver="$(skill_version "$SKILLS_DIR/$name")"
out="$DIST_DIR/$name-cursor-v$ver.zip"
rm -f "$out"
(cd "$DIST_DIR/cursor/plugins" && zip -r "$out" "$name")
echo
echo "dist/$name-cursor-v$ver.zip"
unzip -l "$out"
done < <(skill_names)
+31
View File
@@ -135,7 +135,38 @@ if (Test-Path (Join-Path (Join-Path $dir 'extension') 'manifest.json')) {
}
}
$cursorName = "$Name-cursor-v$ver.zip"
$cursorPath = Join-Path $DistDir $cursorName
$cursorAsset = $null
if (-not (Test-Path $cursorPath)) {
& (Join-Path $PSScriptRoot 'build-cursor.ps1') -Name $Name
if ($LASTEXITCODE -eq 0) {
$pluginDir = Join-Path $DistDir "cursor\plugins\$Name"
if (Test-Path $pluginDir) {
Add-Type -AssemblyName System.IO.Compression
Add-Type -AssemblyName System.IO.Compression.FileSystem
$src = (Get-Item $pluginDir).FullName
$files = @(Get-ChildItem -Path $src -Recurse -File -Force | ForEach-Object { $_.FullName })
[Array]::Sort($files, [StringComparer]::Ordinal)
$zip = [IO.Compression.ZipFile]::Open($cursorPath, [IO.Compression.ZipArchiveMode]::Create)
try {
[void]$zip.CreateEntry("$Name/")
foreach ($f in $files) {
$rel = $f.Substring($src.Length).TrimStart('\', '/') -replace '\\', '/'
[void][IO.Compression.ZipFileExtensions]::CreateEntryFromFile($zip, $f, "$Name/$rel")
}
}
finally { $zip.Dispose() }
}
}
}
if (Test-Path $cursorPath) {
$cursorUrl = "$RepoApi/releases/$($created.id)/assets?name=$([Uri]::EscapeDataString($cursorName))"
$cursorAsset = Invoke-ReleaseApi 'POST' $cursorUrl ([IO.File]::ReadAllBytes($cursorPath)) 'application/octet-stream' | ConvertFrom-Json
}
if ($created.html_url) { Write-Host $created.html_url }
if ($asset.browser_download_url) { Write-Host $asset.browser_download_url }
if ($mcpbAsset -and $mcpbAsset.browser_download_url) { Write-Host $mcpbAsset.browser_download_url }
if ($cursorAsset -and $cursorAsset.browser_download_url) { Write-Host $cursorAsset.browser_download_url }
Write-Host "Release $tag angelegt."
+12
View File
@@ -121,5 +121,17 @@ if [[ -f "$dir/extension/manifest.json" ]]; then
fi
fi
cursor_name="$name-cursor-v$version.zip"
cursor_path="$DIST_DIR/$cursor_name"
if [[ ! -f "$cursor_path" ]]; then
bash "$(dirname "$0")/package-all.sh" >/dev/null 2>&1 || bash "$(dirname "$0")/build-cursor.sh" "$name" || true
if [[ -d "$DIST_DIR/cursor/plugins/$name" ]]; then
(cd "$DIST_DIR/cursor/plugins" && zip -r "$cursor_path" "$name")
fi
fi
if [[ -f "$cursor_path" ]]; then
upload_asset "$cursor_path" "$cursor_name"
fi
[[ -n "$html" ]] && echo "$html"
echo "Release $tag angelegt."
+36 -3
View File
@@ -3,6 +3,7 @@
# Aufruf: scripts\update-index.ps1 [-Check]
param([switch]$Check)
. (Join-Path $PSScriptRoot 'lib.ps1')
. (Join-Path $PSScriptRoot 'cursor-deeplink.ps1')
$RepoWeb = 'https://git.gundel.dev/dg/claude-skills'
$readme = Join-Path $Root 'README.md'
@@ -15,7 +16,21 @@ if ($start -lt 0 -or $end -lt $start) {
exit 1
}
$table = @('| Skill | Kurzbeschreibung | Version | Doku | Download | Erweiterung (.mcpb) |', '|---|---|---|---|---|---|')
$ServerKeys = @{
'wordcraft-mcp' = 'wordcraft'
'gridcraft-mcp' = 'gridcraft'
}
function Get-McpServerKey([string]$SkillName) {
if ($ServerKeys.ContainsKey($SkillName)) { return $ServerKeys[$SkillName] }
if ($SkillName -match '^(.+)-mcp$') { return $Matches[1] }
return $SkillName
}
$table = @(
'| Skill | Kurzbeschreibung | Version | Doku | Download | Erweiterung (.mcpb) | Cursor-Plugin | Cursor 1-Klick |',
'|---|---|---|---|---|---|---|---|'
)
foreach ($n in (Get-SkillNames)) {
$dir = Join-Path $SkillsDir $n
$desc = ''
@@ -32,10 +47,28 @@ foreach ($n in (Get-SkillNames)) {
$tagEnc = [Uri]::EscapeDataString("$n/v$ver")
$zipLink = "[{0}-v{1}.zip]({2}/releases/download/{3}/{0}-v{1}.zip)" -f $n, $ver, $RepoWeb, $tagEnc
$mcpb = ''
if (Test-Path (Join-Path $dir 'extension\manifest.json')) {
$cursorZip = ''
$deeplink = ''
$extPath = Join-Path $dir 'extension\manifest.json'
if (Test-Path $extPath) {
$mcpb = "[{0}-v{1}.mcpb]({2}/releases/download/{3}/{0}-v{1}.mcpb)" -f $n, $ver, $RepoWeb, $tagEnc
$cursorZip = "[{0}-cursor-v{1}.zip]({2}/releases/download/{3}/{0}-cursor-v{1}.zip)" -f $n, $ver, $RepoWeb, $tagEnc
$man = (Read-Text $extPath) | ConvertFrom-Json
$serverKey = Get-McpServerKey $n
$cmd = [string]$man.server.mcp_config.command
$argsList = New-Object System.Collections.Generic.List[string]
foreach ($a in @($man.server.mcp_config.args)) {
$s = [string]$a
if ($s -eq '${user_config.author}') { $argsList.Add('Claude'); continue }
if ($s -eq '${user_config.read_root}') { $argsList.Add('${userHome}/Documents'); continue }
if ($s -eq '${user_config.write_root}') { $argsList.Add('${userHome}/Documents/Claude'); continue }
$argsList.Add($s)
}
$table += ('| [{0}](skills/{0}/) | {1} | {2} | [README](skills/{0}/README.md) | {3} | {4} |' -f $n, $desc, $ver, $zipLink, $mcpb)
$transport = @{ command = $cmd; args = @($argsList) }
$link = New-CursorDeeplink -ServerName $serverKey -Config $transport
$deeplink = "[Add to Cursor]($link)"
}
$table += ('| [{0}](skills/{0}/) | {1} | {2} | [README](skills/{0}/README.md) | {3} | {4} | {5} | {6} |' -f $n, $desc, $ver, $zipLink, $mcpb, $cursorZip, $deeplink)
}
$newLines = @()
+33 -5
View File
@@ -18,8 +18,8 @@ fi
table="$(mktemp)"
trap 'rm -f "$table"' EXIT
{
echo "| Skill | Kurzbeschreibung | Version | Doku | Download | Erweiterung (.mcpb) |"
echo "|---|---|---|---|---|---|"
echo '| Skill | Kurzbeschreibung | Version | Doku | Download | Erweiterung (.mcpb) | Cursor-Plugin | Cursor 1-Klick |'
echo '|---|---|---|---|---|---|---|---|'
while IFS= read -r name; do
[[ -z "$name" ]] && continue
desc=""
@@ -31,11 +31,40 @@ trap 'rm -f "$table"' EXIT
tag_enc="$(python3 -c 'import urllib.parse,sys; print(urllib.parse.quote(sys.argv[1], safe=""))' "$name/v$ver")"
zip_link="[${name}-v${ver}.zip](${REPO_WEB}/releases/download/${tag_enc}/${name}-v${ver}.zip)"
mcpb=""
cursor_zip=""
deeplink=""
if [[ -f "$SKILLS_DIR/$name/extension/manifest.json" ]]; then
mcpb="[${name}-v${ver}.mcpb](${REPO_WEB}/releases/download/${tag_enc}/${name}-v${ver}.mcpb)"
cursor_zip="[${name}-cursor-v${ver}.zip](${REPO_WEB}/releases/download/${tag_enc}/${name}-cursor-v${ver}.zip)"
deeplink="$(python3 - "$SKILLS_DIR/$name/extension/manifest.json" "$name" <<'PY'
import json, base64, sys, urllib.parse, re
man = json.load(open(sys.argv[1], encoding="utf-8"))
name = sys.argv[2]
sk = {"wordcraft-mcp":"wordcraft","gridcraft-mcp":"gridcraft"}.get(name)
if not sk:
m = re.match(r"^(.+)-mcp$", name)
sk = m.group(1) if m else name
cmd = man["server"]["mcp_config"]["command"]
args = []
for a in man["server"]["mcp_config"].get("args") or []:
s = str(a)
if s == "${user_config.author}":
args.append("Claude")
elif s == "${user_config.read_root}":
args.append("${userHome}/Documents")
elif s == "${user_config.write_root}":
args.append("${userHome}/Documents/Claude")
else:
args.append(s)
payload = {sk: {"command": cmd, "args": args}}
b64 = base64.urlsafe_b64encode(json.dumps(payload, separators=(",", ":")).encode()).decode().rstrip("=")
link = f"cursor://anysphere.cursor-deeplink/mcp/install?name={urllib.parse.quote(sk)}&config={b64}"
print(f"[Add to Cursor]({link})")
PY
)"
fi
printf '| [%s](skills/%s/) | %s | %s | [README](skills/%s/README.md) | %s | %s |\n' \
"$name" "$name" "$desc" "$ver" "$name" "$zip_link" "$mcpb"
printf '| [%s](skills/%s/) | %s | %s | [README](skills/%s/README.md) | %s | %s | %s | %s |\n' \
"$name" "$name" "$desc" "$ver" "$name" "$zip_link" "$mcpb" "$cursor_zip" "$deeplink"
done < <(skill_names)
} > "$table"
@@ -51,7 +80,6 @@ if [[ $check -eq 1 ]]; then
fi
echo "README.md ist aktuell."
else
# Explizit UTF-8 schreiben (Locale kann sonst die README verfaelschen).
python3 -c 'import sys; open(sys.argv[1],"w",encoding="utf-8",newline="\n").write(sys.stdin.read())' "$readme" <<< "$new"
echo "README.md aktualisiert."
fi
+7 -1
View File
@@ -1,11 +1,17 @@
# Changelog – gridcraft-mcp
## 0.3.0 (2026-10-19)
- Skill clientneutral: Claude-/Cursor-Details nur noch in README/docs; schärfere `description`.
- Praxiserkenntnisse: `range.fill` und aktive Zelle, `alreadyOpen`, Parameter-Beispiele (Validation, Conditional Format, Layout), Rezepte (Kalkulation / BOM / Vorlage füllen), Abschlussprüfung, Datenschutz.
- Neu: Cursor-Plugin je Skill (`gridcraft-mcp-cursor-v0.3.0.zip`) inkl. Deeplink.
## 0.2.0 (2026-10-19)
- Erweiterung (`.mcpb`) als Standardweg; `display_name` ohne Umlaut („GridCraft for Claude“, Werkzeug-Präfix jetzt `…_for_Claude`).
- Allgemeine Werkzeugnamen im Skill (Präfix hängt vom Client und vom Erweiterungsnamen ab).
- Doku: ArtCraft-Voraussetzung und „Erweiterung einschalten“; UTF-8-Fix in Manifest und README.
- Apostroph-Falle für Text mit führendem `=` (Beschriftungen wie `= Materialkosten`).
- Apostroph-Falle für Text mit führendem `=`.
## 0.1.0 (2026-10-19)
+21 -31
View File
@@ -4,74 +4,66 @@
## Zweck
Erstellt und bearbeitet Excel-Arbeitsmappen (`.xlsx`, `.csv`) über den MCP-Server von GridCraft. GridCraft ist der Open-Source-Excel-Nachbau aus der ArtCraft-Suite, getestet mit 0.8.0. Die Anweisungen für Claude stehen in [SKILL.md](SKILL.md).
Erstellt und bearbeitet Excel-Arbeitsmappen (`.xlsx`, `.csv`) über den MCP-Server von GridCraft. Getestet mit 0.8.0. Die Anweisungen für den Agenten stehen in [SKILL.md](SKILL.md) (clientneutral).
## Voraussetzungen
- Claude Desktop (die App)
- **GridCraft** über den ArtCraft-Launcher (`C:\Program Files\GridCraft\gridcraft-cli.exe`)
- Die Erweiterung `gridcraft-mcp-….mcpb` und dieses Skill-ZIP (siehe [Installation](#installation))
- Claude Desktop **oder** Cursor (siehe unten)
- Die Erweiterung bzw. das Plugin sowie dieses Skill-ZIP
**Keine Ordnerbeschränkung.** Anders als WordCraft kennt GridCraft keine Lese-/Schreib-Roots. Der Server kann jede Datei lesen und schreiben, die der Windows-Benutzer lesen und schreiben darf. In Claude bei den GridCraft-Werkzeugen `open_workbook`, `save_workbook` und `execute_command` auf „Immer fragen“ lassen.
**Keine Ordnerbeschränkung.** In Claude bei `open_workbook`, `save_workbook` und `execute_command` auf „Immer fragen“ lassen.
## Installation
**Cursor:** siehe [Wurzel-README](../../README.md) und [docs/CURSOR.md](../../docs/CURSOR.md).
## Installation (Claude Desktop)
Schritt-für-Schritt: [docs/INSTALLATION.md](../../docs/INSTALLATION.md). Kurz:
1. `gridcraft-mcp-v0.2.0.mcpb` und `gridcraft-mcp-v0.2.0.zip` aus dem [Release](https://git.gundel.dev/dg/claude-skills/releases/download/gridcraft-mcp%2Fv0.2.0/gridcraft-mcp-v0.2.0.mcpb) laden.
1. `gridcraft-mcp-v0.3.0.mcpb` und `gridcraft-mcp-v0.3.0.zip` aus dem [Release](https://git.gundel.dev/dg/claude-skills/releases/download/gridcraft-mcp%2Fv0.3.0/gridcraft-mcp-v0.3.0.mcpb) laden.
2. Die `.mcpb` doppelklicken (oder über Einstellungen → Erweiterungen installieren).
3. Unter Einstellungen → Erweiterungen prüfen, dass **GridCraft for Claude** eingeschaltet ist.
4. Skill-ZIP in Claude hochladen: **„+“ → „Skill erstellen“ → „Skill hochladen“**.
5. Claude komplett beenden (auch Taskleiste) und neu starten.
4. Skill-ZIP hochladen: **„+“ → „Skill erstellen“ → „Skill hochladen“**.
5. Claude komplett beenden (auch Taskleiste) und neu starten. **Neuen** Chat öffnen.
Wer v0.1.0 installiert hat: alte Erweiterung unter Einstellungen → Erweiterungen entfernen, v0.2.0 installieren, einschalten, Skill-ZIP v0.2.0 hochladen (ersetzt den alten Skill). Alte Skills `wordcraft-dokumente` bitte löschen.
Wer v0.1.0 oder v0.2.0 installiert hat: alte Erweiterung entfernen, v0.3.0 installieren, einschalten, Skill-ZIP v0.3.0 hochladen. Alte Skills `wordcraft-dokumente` bitte löschen.
**Umsteigen von der manuellen Config:** Wer den Server früher in `claude_desktop_config.json` eingetragen hat: Eintrag `gridcraft` unter `mcpServers` vor der Installation der Erweiterung entfernen (vorher Sicherungskopie der Datei anlegen), sonst gibt es die Werkzeuge doppelt.
**Umsteigen von der manuellen Config:** Eintrag `gridcraft` unter `mcpServers` vor der Installation der Erweiterung entfernen.
## Enthaltene Software
Die Erweiterung steuert [GridCraft](https://github.com/storytold/gridcraft) (MIT oder Apache-2.0) aus dem ArtCraft-Launcher; die CLI wird **nicht** mitgeliefert. Lizenztexte des Upstreams liegen in der `.mcpb` unter `LICENSES/`.
Die Erweiterung steuert [GridCraft](https://github.com/storytold/gridcraft) (MIT oder Apache-2.0) aus dem ArtCraft-Launcher; die CLI wird **nicht** mitgeliefert.
## Im Test geprüft
Formeln, Tabellen, Zahlenformate und der PDF-Export. Beim Öffnen und Speichern einer bestehenden `.xlsx` blieben erhalten: verbundene Zellen, Kommentare, bedingte Formatierung, Datenüberprüfung, Namen, blattübergreifende Formeln, Fixierung, A4 quer und die Kopfzeile.
Formeln, Tabellen, Zahlenformate, PDF-Export, Stückliste/BOM mit `range.fill`, Datenüberprüfung und bedingte Formatierung. Beim Öffnen/Speichern bestehender `.xlsx` blieben u. a. verbundene Zellen, Kommentare und A4 quer erhalten.
## Bekannte Grenzen
Kurzfassung, die Einzelheiten stehen in [SKILL.md](SKILL.md):
- Formeln nur englisch und mit Komma als Trenner.
- Deutsche Zahlen und Datumsangaben als Text werden nicht erkannt und rechnen nicht mit.
- Diagramme nur aus einem zusammenhängenden Bereich.
- CSV-Export ist komma-getrennt und schreibt das Anzeigeformat.
- Keine Makros.
Kurzfassung in [SKILL.md](SKILL.md): englische Formeln, Apostroph bei Text mit `=`, Diagramme nur aus zusammenhängendem Bereich, CSV ungeeignet für deutsches Excel, keine Makros.
## Test
Neuen Chat öffnen und fragen: „Sind die GridCraft-Tools verfügbar? Lies A1:E10 aus \<Pfad zu einer Test-xlsx\>.“
Neuen Chat öffnen und fragen: „Sind die GridCraft-Tools verfügbar? Lies A1:E10 aus \<Pfad zu einer Test-xlsx\>.“ Präfix `…GridCraft_for_Claude…`.
Fehlen die Tools: Einstellungen → Erweiterungen – ist die Erweiterung eingeschaltet? Dann Claude komplett neu starten.
Fehlen die Tools: Erweiterung eingeschaltet? CLI unter `C:\Program Files\GridCraft\gridcraft-cli.exe`? Neu starten, neuer Chat.
## Stolpersteine
- Erweiterungen sind nicht signiert; nur installieren, wenn du der Quelle vertraust.
- Formeln mit deutschen Namen ergeben `#NAME?` – englische Funktionsnamen verlangen.
- Erweiterungen sind nicht signiert.
- Formeln mit deutschen Namen ergeben `#NAME?`.
## Deinstallation/Update
Deinstallation: Einstellungen → Erweiterungen → entfernen; Skill in der Skill-Liste löschen.
Update: neue `.mcpb` und Skill-ZIP installieren, bestehende Version ersetzen lassen, Claude neu starten.
Einstellungen → Erweiterungen → entfernen; Skill löschen. Update: neue `.mcpb` und Skill-ZIP.
## Alternative: manuell (für Entwickler)
Statt der Erweiterung kann der MCP-Server in `claude_desktop_config.json` eingetragen werden. Gemeinsame Stolpersteine: [MCP unter Windows einrichten](../../docs/windows-mcp-einrichtung.md).
Statt der Erweiterung in `claude_desktop_config.json` eintragen. Stolpersteine: [MCP unter Windows einrichten](../../docs/windows-mcp-einrichtung.md).
- Claude-Installer: `%APPDATA%\Claude\claude_desktop_config.json`
- Microsoft-Store-App: `%LOCALAPPDATA%\Packages\Claude_pzs8sxrjxfjjc\LocalCache\Roaming\Claude\claude_desktop_config.json`
GridCraft muss über den ArtCraft-Launcher installiert sein (`C:\Program Files\GridCraft\gridcraft-cli.exe`).
```json
{
"mcpServers": {
@@ -83,8 +75,6 @@ GridCraft muss über den ArtCraft-Launcher installiert sein (`C:\Program Files\G
}
```
Auffinden der EXE:
```powershell
Get-ChildItem "$env:ProgramFiles","$env:LOCALAPPDATA" -Recurse -Filter "gridcraft-cli.exe" -ErrorAction SilentlyContinue
```
+97 -34
View File
@@ -1,6 +1,6 @@
---
name: gridcraft-mcp
description: Excel-Arbeitsmappen (.xlsx, .csv) über den GridCraft-MCP-Server erstellen, öffnen, ändern, berechnen, formatieren und prüfen – Kalkulationen, Stücklisten, Listen, Diagramme, PDF-Export.
description: "Excel-Arbeitsmappen (.xlsx, .csv) mit dem GridCraft-MCP-Server erstellen, öffnen, ändern, berechnen und prüfen. Verwenden, wenn GridCraft-Werkzeuge verbunden sind oder der Nutzer GridCraft nennt; typisch für Kalkulationen, Stücklisten (BOM), Listen, Diagramme, PDF-Export. Nicht für eingebaute xlsx-Hilfen ohne GridCraft-Server."
---
# Tabellen mit GridCraft (MCP)
@@ -9,15 +9,11 @@ GridCraft ist eine Open-Source-Tabellenkalkulation (Rust), die Excel-Parität an
## Voraussetzung
Die Werkzeuge heißen `write_range`, `read_range`, `execute_command` … mit einem Präfix, der vom Client und vom Namen der Erweiterung abhängt (z. B. `mcp__…__GridCraft_for_Claude__write_range`). Sind sie zurückgestellt, per ToolSearch nach dem Werkzeugnamen ohne Präfix suchen (z. B. `write_range`) und alle benötigten in einem Aufruf laden. Fehlen sie, dem Nutzer sagen, dass der Server nicht läuft, statt auf etwas anderes auszuweichen.
Die Werkzeuge `write_range`, `read_range`, `execute_command` … müssen verbunden sein. Ihr Präfix hängt vom Client und vom Namen der Erweiterung bzw. des Servers ab (z. B. `mcp__…__GridCraft_for_Claude__write_range`). Sind sie zurückgestellt, nach dem Werkzeugnamen ohne Präfix suchen und alle benötigten auf einmal laden. Fehlen sie, dem Nutzer sagen, dass der Server nicht verbunden ist (Einrichtung siehe README), statt auf etwas anderes auszuweichen.
**Standardweg:** GridCraft aus dem ArtCraft-Launcher und die Claude-Desktop-Erweiterung „GridCraft for Claude“ sind installiert und eingeschaltet (siehe `docs/INSTALLATION.md`). Fehlen die Tools: ArtCraft-Installation und Einstellungen → Erweiterungen prüfen, Claude komplett beenden (auch Taskleiste) und neu starten.
**Alternative (Entwickler):** Eintrag `gridcraft` in `claude_desktop_config.json`; die App kann ihn beim Speichern eigener Einstellungen überschreiben.
**Keine Ordnerbeschränkung:** Anders als WordCraft kennt GridCraft keine `--automation-read-root/-write-root`. Der Server kann jede Datei lesen und schreiben, die der Nutzer lesen und schreiben darf. Deshalb:
**Keine Ordnerbeschränkung:** Anders als WordCraft kann der Server jede Datei lesen und schreiben, die der Nutzer lesen und schreiben darf. Deshalb:
- Nur Dateien öffnen, die der Nutzer genannt hat.
- Nie über ein Original speichern. Immer unter neuem Namen speichern (z. B. `<name>_bearbeitet.xlsx` im selben Ordner oder in einem vom Nutzer genannten Ausgabeordner) und den Pfad nennen.
- Nie über ein Original speichern. Immer unter neuem Namen speichern und den Pfad nennen.
- Vor jedem `save_workbook` / `file.export*` den Zielpfad prüfen.
## Tools
@@ -38,48 +34,115 @@ Die Werkzeuge heißen `write_range`, `read_range`, `execute_command` … mit ein
| `new_workbook` / `open_workbook` / `save_workbook` | Dateien (.xlsx, .csv, .tsv, .json, .html) |
| `undo` / `redo` | Verlauf |
| `list_functions` | verfügbare Tabellenfunktionen |
| `screenshot` | nur im Remote-Modus (`--connect`) |
| `screenshot` | nur mit verbundener Desktop-App |
Bereiche mit Blatt: `"Kalkulation!A3:E8"`.
## Arbeitsweise
1. **Befehls-IDs nie raten:** `list_commands {search: "…"}` (z. B. `column width`, `freeze`, `page`, `rename`, `chart.`).
1. **Befehls-IDs nie raten:** `list_commands {search: "…"}` (z. B. `column width`, `freeze`, `page`, `rename`, `chart.`, `range.fill`).
2. **Daten in einem Rutsch:** `write_range` mit ganzer Tabelle inkl. Formeln statt vieler `set_cell`.
3. **Formeln statt fester Werte** für alles Berechnete (Summen, MwSt, Aufschläge), damit der Nutzer in Excel weiterrechnen kann. Parameter (Aufschlag, MwSt-Satz) in eigene Zellen und per absolutem Bezug (`$B$1`) verwenden.
4. **Prüfen:** `read_range` (berechnete Werte), `read_range {formulas: true}` (Formeln), `read_range {formatted: true}` (Anzeige), `inspect_workbook` (Struktur). Beim PDF-Export das Ergebnis ansehen.
5. **Speichern** als .xlsx unter neuem Namen; zur Kontrolle mit `open_workbook` wieder öffnen und Formeln lesen.
3. **Formeln statt fester Werte** für alles Berechnete. Parameter in eigene Zellen und per absolutem Bezug (`$B$1`).
4. Vor dem Massenbefüllen Formel-Syntax mit `evaluate_formula` testen.
5. **Prüfen:** `read_range`, `read_range {formulas: true}`, `read_range {formatted: true}`, `inspect_workbook`.
6. **Speichern** als .xlsx unter neuem Namen.
## Deutsche Eingaben – wichtigste Fallen (im Test bestätigt)
## Deutsche Eingaben – wichtigste Fallen
- **Formeln nur englisch und mit Komma:** `=SUM(E2:E5)`, `=ROUND(E8,2)`, `=VLOOKUP(…,FALSE)`, `=IF(…)`. Deutsche Namen (`=SUMME(…)`) ergeben `#NAME?`, Semikolon als Trenner ergibt einen Formelfehler. Excel zeigt die Formeln beim Öffnen trotzdem auf Deutsch an.
- **Zahlen als JSON-Zahl mit Punkt** übergeben (`0.75`, nicht `"0,75"`). Ein String mit Komma wird **als Text** gespeichert und rechnet nicht mit.
- **Datumswerte als ISO** (`"2026-10-19"`) oder `=DATE(2026,10,19)`. `"19.10.2026"` wird zu Text. Danach Zahlenformat setzen: `numberFormat: "DD.MM.YYYY"`.
- **Zahlenformate sind sprachneutral:** `"#,##0.00 €"` erscheint in GridCraft als `1,114.10 €`, in einem deutschen Excel aber korrekt als `1.114,10 €`. Nicht „reparieren“.
- **Neue Mappe = US-Letter, Blatt heißt `Sheet1`:** für deutsche Dokumente `pageLayout.size {paper: "A4"}` und `sheet.rename {sheet: "Sheet1", name: "…"}`.
- **Text, der mit `=` beginnt, wird als Formel gelesen.** Beschriftungen wie `= Materialkosten` ergeben `#NAME?`. Wie in Excel einen Apostroph voranstellen: `"'= Materialkosten"` – gespeichert wird reiner Text.
- **Formeln nur englisch und mit Komma:** `=SUM(E2:E5)`, `=ROUND(E8,2)`, `=VLOOKUP(…,FALSE)`, `=IF(…)`. Deutsche Namen ergeben `#NAME?`.
- **Zahlen als JSON-Zahl mit Punkt** (`0.75`, nicht `"0,75"`).
- **Datumswerte als ISO** (`"2026-10-19"`) oder `=DATE(2026,10,19)`. Danach `numberFormat: "DD.MM.YYYY"`.
- **Zahlenformate sind sprachneutral:** `"#,##0.00 €"` erscheint in GridCraft als `1,114.10 €`, in deutschem Excel korrekt. Nicht „reparieren“.
- **Neue Mappe = US-Letter, Blatt heißt `Sheet1`:** `pageLayout.size {paper: "A4"}` und `sheet.rename`.
- **Text, der mit `=` beginnt, wird als Formel gelesen.** Apostroph voranstellen: `"'= Materialkosten"`.
## range.fill und aktive Zelle
`range.fill {input}` interpretiert relative Bezüge **relativ zur aktiven Zelle**, nicht zur ersten Zelle des Bereichs (aus `C12` wurde fälschlich `O23`). Richtig:
1. `select {range:"M12:M111", active:"M12"}`
2. `execute_command` mit `range.fill {input:"=…C12…"}` **ohne** `range` im fill-Aufruf
Vor dem Massenbefüllen Formel mit `evaluate_formula` testen.
## open_workbook und alreadyOpen
`open_workbook` auf eine bereits offene Datei liefert nur `{"alreadyOpen": true}` und lädt **nicht** neu – für die Kontrolle der gespeicherten Datei ungeeignet. Andere Mappe aktivieren/schließen oder Datei extern prüfen.
## Parameter-Beispiele (im Test bestätigt)
Datenüberprüfung:
```json
{"command":"data.validation","params":{"range":"E12:E100","type":"list","formula1":"\"A,B,C\"","dropdown":true,"errorStyle":"warning","errorTitle":"Eingabe","errorMessage":"Wert aus der Liste wählen"}}
```
```json
{"command":"data.validation","params":{"range":"N12:N100","type":"whole","operator":"between","formula1":"1","formula2":"9"}}
```
```json
{"command":"data.validation","params":{"range":"F12:F100","type":"decimal","operator":"greaterOrEqual","formula1":"0"}}
```
Bedingte Formatierung:
```json
{"command":"home.conditionalFormat","params":{"range":"A12:N111","rule":{"type":"expression","formula":"AND($E12<>\"\",$N12=\"\")","preset":"lightRedFill"}}}
```
```json
{"command":"home.conditionalFormat","params":{"range":"A12:A111","rule":{"type":"expression","formula":"$A12=\"x\"","style":{"font":{"bold":true}}}}}
```
Layout:
```json
{"command":"home.columnWidth","params":{"cols":"E:E","chars":36}}
{"command":"view.freezePanes","params":{"cell":"F12"}}
{"command":"pageLayout.printTitles","params":{"rows":"11:11"}}
{"command":"pageLayout.headerFooter","params":{"header":"&L&F&R&A","footer":"&LStand: &D&RSeite &P von &N"}}
```
## Weitere Fallen
- **Diagramme nur aus zusammenhängendem Bereich:** `insert_chart {range: "B1:B5,E1:E5"}` liefert ein leeres Diagramm über den Daten. Kategorie und Werte nebeneinander anordnen (oder Hilfsbereich anlegen) und `range: "A1:B5"` nutzen. Immer `at` setzen (z. B. `"H2"`), damit das Diagramm keine Daten verdeckt.
- **PDF-Export** (`file.exportPdf {path}`) schneidet breite Inhalte ab: vorher `home.autofitColumnWidth {cols: "A:E"}`, ggf. `pageLayout.orientation {orientation: "landscape"}` und `pageLayout.scaleToFit {width: 1}`.
- **Spaltenbreiten** werden nicht automatisch angepasst: nach dem Befüllen `home.autofitColumnWidth`.
- **CSV-Export** (`save_workbook` mit `.csv`) schreibt Komma-getrennt und die **formatierte Anzeige** (`412.50 €`). Für deutsches Excel oder ERP-Import ungeeignet – lieber .xlsx liefern oder vor dem CSV-Export Zahlenformate entfernen und den Nutzer auf das Trennzeichen hinweisen.
- **`open_workbook` öffnet eine weitere Mappe** und macht sie aktiv; Befehle wirken auf die aktive Mappe. Bei mehreren Mappen mit `inspect_workbook` prüfen, welche aktiv ist.
- `undo` nach `open_workbook` hat keinen Verlauf; Fehler vor dem Speichern beheben.
- **Diagramme nur aus zusammenhängendem Bereich;** immer `at` setzen.
- **PDF-Export** schneidet breite Inhalte ab: vorher `home.autofitColumnWidth`, ggf. Querformat und `pageLayout.scaleToFit {width: 1}`.
- **CSV-Export** ist komma-getrennt und schreibt die formatierte Anzeige – für deutsches Excel oft ungeeignet.
- **`open_workbook` öffnet eine weitere Mappe** und macht sie aktiv.
- `undo` nach `open_workbook` hat keinen Verlauf.
## Bestehende Mappen bearbeiten
Im Test blieben beim Öffnen und Speichern einer Excel-Datei erhalten: verbundene Zellen, Schrift, Zahlenformate, Kommentare, bedingte Formatierung, Datenüberprüfung, benannte Bereiche, blattübergreifende Formeln, fixierte Bereiche, Spaltenbreiten, Seitenformat (A4 quer) und Kopfzeile.
1. `open_workbook` → `inspect_workbook` → relevante Bereiche mit `read_range {formulas: true}` lesen.
2. Nur gewünschte Zellen ändern; Formeln anderer Zellen nicht durch Werte ersetzen.
3. Ergebnis gegenlesen, unter neuem Namen speichern.
4. Dem Nutzer kurz sagen, was geändert wurde.
Ablauf:
1. `open_workbook` → `inspect_workbook` → relevante Bereiche mit `read_range {formulas: true}` lesen, bevor etwas geändert wird.
2. Nur die gewünschten Zellen ändern; Formeln anderer Zellen nicht durch Werte ersetzen.
3. Ergebnis gegenlesen (`read_range`), unter neuem Namen speichern.
4. Dem Nutzer kurz sagen, was geändert wurde (Zellen, alter → neuer Wert), und vorschlagen, die Datei einmal in Excel zu öffnen.
## Rezepte
### Kalkulation / Zuschlagskalkulation
Parameterblatt mit Werten und absoluten Bezügen (`$B$1`). Skonto/Rabatt im Hundert korrekt formeln. Datenblatt mit `write_range`, Summen/MwSt als Formeln. A4, Zahlenformate, speichern unter neuem Namen.
### Stückliste / BOM
Kopfzeile und Zusammenfassung → Datenzeilen schreiben → Formeln per `select` + `range.fill` nachziehen → Auswahllisten (`data.validation`) → bedingte Formatierung → Freeze/PrintTitles → Revisionsblatt → speichern.
### Vorlage füllen
Vorlage öffnen → Zeilen ab Startzeile mit `write_range` schreiben → bei Bedarf `home.insertRows` → Formeln per `range.fill` nachziehen → prüfen → unter neuem Namen speichern.
## Abschlussprüfung
- `read_range` / `read_range {formulas: true}` auf Kernbereiche.
- Bei PDF: Ergebnis ansehen (Breite, Seitenumbruch).
- Gespeicherte Datei nicht mit `open_workbook` auf dieselbe Mappe „neu laden“ erwarten (`alreadyOpen`); externe Prüfung oder andere Mappe.
- Pfad dem Nutzer nennen.
## Datenschutz
- Grün: allgemeine/technische Inhalte ohne Kundenbezug.
- Gelb: Projekt-/Geschäftsinfos, Preise nur nach Abwägung oder anonymisiert.
- Rot: personenbezogene Daten und NDA-Inhalte nicht in die Cloud-KI.
- GridCraft hat keine Ordnersperre – nur Dateien öffnen/speichern, die der Nutzer genannt hat.
## Grenzen
- Keine Netzwerkfunktionen (`WEBSERVICE` liefert `#VALUE!`), keine Makros/VBA.
- Funktionsumfang mit `list_functions` prüfen, bevor exotische Funktionen genutzt werden.
- Im Remote-Modus (`--connect`) steuert der Server die geöffnete Desktop-App; das ist ebenfalls nicht auf Ordner beschränkt.
- Funktionsumfang mit `list_functions` prüfen.
- Mit verbundener Desktop-App entfällt jede Ordnerbeschränkung ebenfalls.
+1 -1
View File
@@ -2,7 +2,7 @@
"manifest_version": "0.3",
"name": "gridcraft-mcp",
"display_name": "GridCraft for Claude",
"version": "0.2.0",
"version": "0.3.0",
"description": "Excel-Arbeitsmappen (.xlsx, .csv) erstellen und bearbeiten. Getestet mit GridCraft 0.8.0. Benötigt GridCraft aus dem ArtCraft-Launcher unter C:\\Program Files\\GridCraft\\. Ohne Ordnersperre – GridCraft kann alle Dateien lesen und schreiben, auf die der Benutzer Zugriff hat.",
"author": {
"name": "Dominic Gundel"
+7
View File
@@ -1,5 +1,12 @@
# Changelog – wordcraft-mcp
## 0.3.0 (2026-10-19)
- Skill clientneutral: Claude-/Cursor-Details nur noch in README/docs; schärfere `description`.
- Praxiserkenntnisse: batch inkl. Markieren, Fallen (format.set, Nummerierung, Löschen von unten, Highlight, UTF-8-Bytes), Rezepte (neues Dokument / Vorlage / füllen), Abschlussprüfung, Datenschutz-Ampel.
- Ordner-Empfehlung in der Erweiterung: Lese weit, Schreib eng.
- Neu: Cursor-Plugin je Skill (`wordcraft-mcp-cursor-v0.3.0.zip`) inkl. Deeplink.
## 0.2.0 (2026-10-19)
- Erweiterung (`.mcpb`) als Standardweg; `display_name` ohne Umlaut („WordCraft for Claude“, Werkzeug-Präfix jetzt `…_for_Claude`).
+25 -23
View File
@@ -4,59 +4,61 @@
## Zweck
Erstellt, bearbeitet und prüft Word-Dokumente über den MCP-Server von WordCraft – inklusive Nachverfolgung von Änderungen und der Fallen, die beim Praxistest mit WordCraft 0.8.0 aufgefallen sind. Die Anweisungen für Claude stehen in [SKILL.md](SKILL.md).
Erstellt, bearbeitet und prüft Word-Dokumente über den MCP-Server von WordCraft – inklusive Nachverfolgung und der Fallen aus dem Praxistest mit WordCraft 0.8.0. Die Anweisungen für den Agenten stehen in [SKILL.md](SKILL.md) (clientneutral).
## Voraussetzungen
- Claude Desktop (die App)
- **WordCraft** über den ArtCraft-Launcher (`C:\Program Files\WordCraft\wordcraft-cli.exe`)
- Die Erweiterung `wordcraft-mcp-….mcpb` und dieses Skill-ZIP (siehe [Installation](#installation))
- Claude Desktop **oder** Cursor (siehe unten)
- Die Erweiterung bzw. das Plugin sowie dieses Skill-ZIP
Falls der Plugin-Skill `wordcraft-dokumente` installiert ist: deaktivieren, damit Claude `wordcraft-mcp` verwendet.
Falls der Plugin-Skill `wordcraft-dokumente` installiert ist: deaktivieren bzw. löschen.
## Installation
**Cursor:** siehe [Wurzel-README](../../README.md) und [docs/CURSOR.md](../../docs/CURSOR.md).
## Installation (Claude Desktop)
Schritt-für-Schritt: [docs/INSTALLATION.md](../../docs/INSTALLATION.md). Kurz:
1. `wordcraft-mcp-v0.2.0.mcpb` und `wordcraft-mcp-v0.2.0.zip` aus dem [Release](https://git.gundel.dev/dg/claude-skills/releases/download/wordcraft-mcp%2Fv0.2.0/wordcraft-mcp-v0.2.0.mcpb) laden.
2. Die `.mcpb` doppelklicken (oder über Einstellungen → Erweiterungen installieren). Lese- und Schreib-Ordner setzen; Schreibordner vorher anlegen und nicht gleich dem Leseordner wählen.
1. `wordcraft-mcp-v0.3.0.mcpb` und `wordcraft-mcp-v0.3.0.zip` aus dem [Release](https://git.gundel.dev/dg/claude-skills/releases/download/wordcraft-mcp%2Fv0.3.0/wordcraft-mcp-v0.3.0.mcpb) laden.
2. Die `.mcpb` doppelklicken (oder über Einstellungen → Erweiterungen installieren). **Lese-Ordner weit** (z. B. Dokumente oder Benutzerordner), **Schreib-Ordner eng** (eigener Ordner, z. B. `Dokumente\Claude`).
3. Unter Einstellungen → Erweiterungen prüfen, dass **WordCraft for Claude** eingeschaltet ist.
4. Skill-ZIP in Claude hochladen: **„+“ → „Skill erstellen“ → „Skill hochladen“**.
5. Claude komplett beenden (auch Taskleiste) und neu starten.
4. Skill-ZIP hochladen: **„+“ → „Skill erstellen“ → „Skill hochladen“**.
5. Claude komplett beenden (auch Taskleiste) und neu starten. **Neuen** Chat öffnen.
Wer v0.1.0 installiert hat: alte Erweiterung unter Einstellungen → Erweiterungen entfernen, v0.2.0 installieren, einschalten, Skill-ZIP v0.2.0 hochladen (ersetzt den alten Skill). Alte Skills `wordcraft-dokumente` bitte löschen.
Bei `open_document` / `save_document` in Claude „Immer fragen“ lassen, wenn du Pfade mitkontrollieren willst.
**Umsteigen von der manuellen Config:** Wer den Server früher in `claude_desktop_config.json` eingetragen hat: Eintrag `wordcraft` unter `mcpServers` vor der Installation der Erweiterung entfernen (vorher Sicherungskopie der Datei anlegen), sonst gibt es die Werkzeuge doppelt.
Wer v0.1.0 oder v0.2.0 installiert hat: alte Erweiterung entfernen, v0.3.0 installieren, einschalten, Skill-ZIP v0.3.0 hochladen. Alte Skills `wordcraft-dokumente` bitte löschen.
**Umsteigen von der manuellen Config:** Eintrag `wordcraft` unter `mcpServers` vor der Installation der Erweiterung entfernen (vorher Sicherungskopie), sonst gibt es die Werkzeuge doppelt.
## Enthaltene Software
Die Erweiterung steuert [WordCraft](https://github.com/storytold/wordcraft) (MIT oder Apache-2.0) aus dem ArtCraft-Launcher; die CLI wird **nicht** mitgeliefert. Lizenztexte des Upstreams liegen in der `.mcpb` unter `LICENSES/`.
Die Erweiterung steuert [WordCraft](https://github.com/storytold/wordcraft) (MIT oder Apache-2.0) aus dem ArtCraft-Launcher; die CLI wird **nicht** mitgeliefert. Lizenztexte liegen in der `.mcpb` unter `LICENSES/`.
## Test
Neuen Chat öffnen und fragen: „Sind die WordCraft-Tools verfügbar?“
Neuen Chat öffnen und fragen: „Sind die WordCraft-Tools verfügbar?“ Die Werkzeuge heißen mit Präfix `…WordCraft_for_Claude…`.
Fehlen die Tools: Einstellungen → Erweiterungen – ist die Erweiterung eingeschaltet? Dann Claude komplett neu starten.
Fehlen die Tools: Einstellungen → Erweiterungen – eingeschaltet? CLI unter `C:\Program Files\WordCraft\wordcraft-cli.exe` vorhanden? Dann Claude neu starten und neuen Chat öffnen.
## Stolpersteine
- Speichern mit „path rejected“: Ziel lag außerhalb des Schreib-Ordners. Einstellungen → Erweiterungen → WordCraft for Claude → Einstellungen prüfen.
- Speichern mit „path rejected“: Ziel lag außerhalb des Schreib-Ordners. Einstellungen → Erweiterungen → WordCraft for Claude → Einstellungen.
- Erweiterungen sind nicht signiert; nur installieren, wenn du der Quelle vertraust.
## Deinstallation/Update
Deinstallation: Einstellungen → Erweiterungen → entfernen; Skill in der Skill-Liste löschen.
Update: neue `.mcpb` und Skill-ZIP installieren, bestehende Version ersetzen lassen, Claude neu starten.
Einstellungen → Erweiterungen → entfernen; Skill löschen. Update: neue `.mcpb` und Skill-ZIP, ersetzen lassen, neu starten.
## Alternative: manuell (für Entwickler)
Statt der Erweiterung kann der MCP-Server in `claude_desktop_config.json` eingetragen werden. Gemeinsame Stolpersteine: [MCP unter Windows einrichten](../../docs/windows-mcp-einrichtung.md).
Statt der Erweiterung den MCP-Server in `claude_desktop_config.json` eintragen. Stolpersteine: [MCP unter Windows einrichten](../../docs/windows-mcp-einrichtung.md).
- Claude-Installer: `%APPDATA%\Claude\claude_desktop_config.json`
- Microsoft-Store-App: `%LOCALAPPDATA%\Packages\Claude_pzs8sxrjxfjjc\LocalCache\Roaming\Claude\claude_desktop_config.json` (der Suffix `pzs8sxrjxfjjc` ist der Herausgeber-Hash und bei allen Store-Installationen gleich)
- Microsoft-Store-App: `%LOCALAPPDATA%\Packages\Claude_pzs8sxrjxfjjc\LocalCache\Roaming\Claude\claude_desktop_config.json` (Herausgeber-Hash `pzs8sxrjxfjjc`, bei allen Store-Installationen gleich)
WordCraft muss über den ArtCraft-Launcher installiert sein (`C:\Program Files\WordCraft\wordcraft-cli.exe`). Der Schreibordner muss vorher existieren.
Die App kann den Eintrag beim Speichern eigener Einstellungen überschreiben – dann neu eintragen und **sofort** neu starten.
```json
{
@@ -67,14 +69,14 @@ WordCraft muss über den ArtCraft-Launcher installiert sein (`C:\Program Files\W
"mcp",
"--author", "Claude",
"--automation-read-root", "C:\\Pfad\\zu\\Dokumente",
"--automation-write-root", "C:\\Pfad\\zu\\Dokumente\\claude_out"
"--automation-write-root", "C:\\Pfad\\zu\\Dokumente\\Claude"
]
}
}
}
```
Auffinden der EXE:
Laufende App steuern (nicht auf Ordner beschränkt): `wordcraft --control 7981` und `wordcraft-cli mcp --connect 127.0.0.1:7981`.
```powershell
Get-ChildItem "$env:ProgramFiles","$env:LOCALAPPDATA" -Recurse -Filter "wordcraft-cli.exe" -ErrorAction SilentlyContinue
+66 -43
View File
@@ -1,6 +1,6 @@
---
name: wordcraft-mcp
description: Word-Dokumente (.docx, .odt, .md, PDF) über den WordCraft-MCP-Server erstellen, bearbeiten und prüfen, inkl. Nachverfolgung – mit erprobten Fallen aus WordCraft 0.8.0.
description: "Word-Dokumente (.docx, .odt, .md, PDF) mit dem WordCraft-MCP-Server erstellen, bearbeiten und prüfen (inkl. Nachverfolgung). Verwenden, wenn WordCraft-Werkzeuge verbunden sind oder der Nutzer WordCraft nennt; typisch für Angebote, Briefe, Betriebsanleitungen, Arbeitsanweisungen, 8D-Reports, Vorlagen. Nicht für eingebaute docx-Hilfen ohne WordCraft-Server."
---
# Dokumente mit WordCraft (MCP)
@@ -9,25 +9,11 @@ WordCraft ist ein Open-Source-Textverarbeitungsprogramm (Rust), das Word-Paritä
## Voraussetzung
Die Werkzeuge heißen `list_commands`, `execute`, `render_page` … mit einem Präfix, der vom Client und vom Namen der Erweiterung abhängt (z. B. `mcp__…__WordCraft_for_Claude__list_commands`). Sind sie zurückgestellt, per ToolSearch nach dem Werkzeugnamen ohne Präfix suchen (z. B. `list_commands`) und alle benötigten in einem Aufruf laden. Fehlen sie auch dann, dem Nutzer den Grund nennen statt auszuweichen.
**Standardweg:** WordCraft aus dem ArtCraft-Launcher und die Claude-Desktop-Erweiterung „WordCraft for Claude“ sind installiert und eingeschaltet (siehe `docs/INSTALLATION.md`). Fehlen die Tools: ArtCraft-Installation und Einstellungen → Erweiterungen prüfen, Claude komplett beenden (auch Taskleiste) und neu starten – nicht auf ein anderes Programm ausweichen.
**Alternative (Entwickler):** Eintrag `wordcraft` in `claude_desktop_config.json` mit `wordcraft-cli.exe mcp --author Claude --automation-read-root <Ordner> --automation-write-root <Ordner>\claude_out`. Store-Pfad: `%LOCALAPPDATA%\Packages\Claude_pzs8sxrjxfjjc\LocalCache\Roaming\Claude\`. Die App kann den Eintrag beim Speichern eigener Einstellungen überschreiben – dann neu eintragen und sofort neu starten.
Alternativ laufende App steuern (nicht auf Ordner beschränkt): `wordcraft --control 7981` und `wordcraft-cli mcp --connect 127.0.0.1:7981`.
Die Werkzeuge `list_commands`, `execute`, `render_page` … müssen verbunden sein. Ihr Präfix hängt vom Client und vom Namen der Erweiterung bzw. des Servers ab (z. B. `mcp__…__WordCraft_for_Claude__list_commands`). Sind sie zurückgestellt, nach dem Werkzeugnamen ohne Präfix suchen und alle benötigten auf einmal laden. Fehlen sie, dem Nutzer sagen, dass der Server nicht verbunden ist (Einrichtung siehe README), statt auf ein anderes Programm auszuweichen.
## Freigaben
Der eigentliche Schutz sind `--automation-read-root` und `--automation-write-root`, nicht die Freigabe-Dialoge. Empfohlene Tool-Berechtigungen im Connector:
- Immer erlauben: `list_commands`, `get_text`, `inspect_document`, `render_page`, `open_document`, `select_text`, `new_document`, `parity`, `execute`, `batch`, `type_text`
- Optional nachfragen: `save_document` (nur bedingt wirksam, da `execute` mit `file.saveAs`/`file.exportPdf` ebenfalls speichern kann)
- Nie: `screenshot`, `click`, `key`, `ui_inspect` (nur für `--connect`, dort ohne Ordnergrenzen)
„Immer erlauben“ ist nur sicher, solange die Config die Root-Argumente enthält und kein `--connect` verwendet. Nach jedem Neueintrag prüfen.
Aufrufe sparen: genaue Dateipfade vom Nutzer erfragen statt zu raten, zusammenhängende Schritte immer als `batch`.
Schutz durch Lese- und Schreib-Root (nicht die Freigabe-Dialoge). Lesen weit, Schreiben eng. Zusammenhängende Schritte immer als `batch`. Genau Dateipfade vom Nutzer erfragen statt zu raten.
## Tools
@@ -43,23 +29,24 @@ Aufrufe sparen: genaue Dateipfade vom Nutzer erfragen statt zu raten, zusammenh
| `get_text` / `inspect_document` | Dokument zurücklesen (Struktur als JSON, inkl. Kopf-/Fußzeilen unter `parts`) |
| `render_page` | Seite als PNG |
| `parity` | Funktionsabdeckung gegenüber Word |
| `screenshot`, `click`, `key`, `ui_inspect` | nur mit `--connect` |
| `screenshot`, `click`, `key`, `ui_inspect` | nur mit verbundener Desktop-App |
## Arbeitsweise
1. **Befehls-IDs nie raten.** Vor jedem unbekannten Befehl `list_commands` mit `query` aufrufen (z. B. `table.`, `insert.`, `layout.`, `styles.`, `review`, `caret.`). Präfix mit Punkt filtert gezielter.
2. **Formatvorlagen statt Direktformatierung.** `styles.modify` an Normal/Heading1/Heading2/Title; Absätze nur per `para.set {"props":{"style":"Heading1"}}` zuweisen.
3. **Gebündelt arbeiten.** Zusammenhängende Schritte als `batch`.
4. **Prüfen, bevor gespeichert wird.** `inspect_document` für Inhalt/Struktur/Kopf-Fußzeilen, `render_page` für Layout.
1. **Befehls-IDs nie raten.** Vor jedem unbekannten Befehl `list_commands` mit `query` aufrufen (z. B. `table.`, `insert.`, `layout.`, `styles.`, `review`, `caret.`, `select.`).
2. **Alles im batch.** Auch Markieren: `select.text {text, occurrence?}`, `select.range {anchor: Pos, focus: Pos}`, `select.collapse`. `text.insert` ersetzt eine bestehende Markierung. Damit lassen sich ganze Dokumente in wenigen Aufrufen umbauen.
3. **Formatvorlagen statt Direktformatierung.** `styles.modify` an Normal/Heading1/Heading2/Title; Absätze nur per `para.set {"props":{"style":"Heading1"}}` zuweisen.
4. **Prüfen, bevor gespeichert wird.** `inspect_document`, `render_page`.
5. **Speichern** mit `save_document` in den Schreibordner; PDF per Endung `.pdf`.
6. **Rundreise prüfen:** gespeicherte Datei neu öffnen und `inspect_document`/`render_page` bzw. `review.changes` erneut aufrufen.
6. **Rundreise prüfen:** gespeicherte Datei neu öffnen und erneut prüfen.
## Dateien finden
## Dateien finden und Zugriff
Es gibt **keinen Befehl zum Auflisten von Ordnern**. `open_document` auf einen Pfad:
- `os error 5 (Zugriff verweigert)` → Pfad ist ein existierender Ordner
- `os error 2 (nicht gefunden)` → existiert nicht
Damit lassen sich Ordner bestätigen, aber keine Dateinamen ermitteln. Bei Unklarheit den Nutzer nach dem genauen Dateinamen fragen statt viele Namen zu raten.
Liegt eine Datei **außerhalb des Lese-Ordners**, wird sie abgelehnt. Dann: (a) Nutzer bitten, den Lese-Ordner in den Einstellungen weiter zu fassen, oder (b) – wenn der Client Dateizugriff mit Nutzerfreigabe hat – die Datei mit Freigabe in den Arbeitsordner **kopieren** und nur mit der Kopie arbeiten. Original nie überschreiben.
## Neues Dokument – Grundeinrichtung (DE)
@@ -72,12 +59,24 @@ Damit lassen sich Ordner bestätigen, aber keine Dateinamen ermitteln. Bei Unkla
```
Ohne de-DE zeigt `render_page` deutsche Wörter mit roten Wellenlinien.
Text aufbauen: `para.set {style}` → `text.insert` → `text.newParagraph`, Stil für jeden Absatz explizit setzen. Aufzählung: `para.bullets {"kind":"bullet"}` vor dem ersten Punkt, `para.bullets {"off":true}` danach (hinterlässt `numbering num 0` am nächsten Absatz – harmlos).
Text aufbauen: `para.set {style}` → `text.insert` → `text.newParagraph`, Stil für jeden Absatz explizit setzen.
## Fallen (im Test bestätigt)
- **`format.set` ohne Markierung** wirkt nicht auf den gerade eingefügten Text, sondern auf den folgenden Absatz. Immer erst markieren (`select.text` / `select.range`), dann formatieren.
- **Nummerierte Listen:** `para.numbering {"kind":"numbered"}` (auch `numberedParen`, `upperLetter`, `lowerLetter`, `lowerRoman`, `outline`). `para.bullets {"kind":"decimal"}` nimmt „decimal“ still als Aufzählungszeichen. Ende: `para.numbering {"off":true}`. Aufzählung: `para.bullets {"kind":"bullet"}` … `para.bullets {"off":true}`.
- **`table.insertRowBelow`** übernimmt Ausrichtung und Fettdruck der Nachbarzeile nicht → danach `para.set {align}` und `format.set` setzen.
- **Absätze mit gemischtem Format** (z. B. fettes Label + Tab + Wert): nicht den ganzen Absatz ersetzen (sonst übernimmt alles das Format des ersten Laufs), sondern nur den Wertteil per `select.text`.
- **`inspect_document`:** `len` und alle `off` sind **UTF-8-Bytes** (ä/ö/ü/ß = 2). Für Textstellen mit Umlauten lieber `select.text` als selbst berechnete Offsets.
- **Absätze löschen:** von **unten nach oben** arbeiten; `select.range` vom Ende (`off = len`) des letzten verbleibenden Absatzes bis zum Ende des letzten zu löschenden Absatzes, dann `text.delete`. Indizes danach neu berechnen.
- **Hinweiskasten:** `para.set {"props":{"shading":[r,g,b],"borders":{"top":{…},"bottom":{…},"left":{…},"right":{…}}}}`; im nächsten Absatz zurücksetzen (`shading` weiß, `borders` style none).
- **Abstand vor einem Absatz:** `para.set {"props":{"style":"Normal","spaceBefore":24}}`.
- **Gelbe Platzhalter-Markierung** (`format.set {"props":{"highlight":"yellow"}}`) bleibt beim Überschreiben erhalten – Nutzer bei Vorlagen darauf hinweisen (Word: Strg+A → Texthervorhebung „Keine Farbe“).
## Kopf- und Fußzeile, Seitenzahl
- Nach `insert.header` / `insert.footer` **sofort** `insert.closeHeader`, sonst landet folgender Text in der Kopf-/Fußzeile.
- `insert.footer {"text": ...}` setzt die Schreibmarke **an den Anfang** des Textes – nachfolgende Einfügungen landen davor. `preset: "blank"` legt einen Platzhalter „[Type here]“ an. Deshalb **ohne Parameter** öffnen und dann tippen:
- `insert.footer {"text": ...}` setzt die Schreibmarke **an den Anfang** des Textes. `preset: "blank"` legt „[Type here]“ an. Deshalb **ohne Parameter** öffnen und dann tippen:
```json
[{"command":"insert.footer"},
{"command":"text.insert","params":{"text":"Seite "}},
@@ -87,43 +86,67 @@ Text aufbauen: `para.set {style}` → `text.insert` → `text.newParagraph`, Sti
{"command":"para.set","params":{"props":{"align":"center"}}},
{"command":"insert.closeHeader"}]
```
- Für reinen Text in der Kopfzeile ist `insert.header {"text": ...}` + `insert.closeHeader` in Ordnung.
- Kontrolle: `inspect_document` → `parts[]` mit `kind: header/footer`. Fehler korrigieren mit `insert.removeFooter` und neu aufbauen.
- Kontrolle: `inspect_document` → `parts[]` mit `kind: header/footer`.
## Tabellen
- `insert.table {"rows":n,"cols":n,"style":"TableGrid"}` liefert `{"table":[index]}` = Blockindex.
- Zellen **nicht per Tab** füllen, sondern anspringen: `caret.set {"pos":{"path":[tabelle, zeile, spalte, 0],"off":0,"story":"body"}}` dann `text.insert`.
- Kopfzeile: Caret in Zeile 0 → `table.properties {"headerRow":true}`, `table.selectRow`, `table.shading {"color":"D9E2F3"}`, `format.set {"props":{"bold":true}}`.
- `table.columnWidth` ändert **nur die Spalte der Schreibmarke**; die Tabelle wird dadurch schmaler/breiter. Alle Spalten so setzen, dass die Summe = Satzspiegel (pageW − marginLeft − marginRight; A4 mit 2,5/2 cm ≈ 467,7 pt).
## Positionen
- `off` in Positionen zählt **UTF-8-Bytes**, nicht Zeichen (ä/ö/ü/ß = 2, ▬ oder – = 3). Für Textstellen mit Umlauten lieber `select_text` als selbst berechnete Offsets.
- Kommentaranker und andere Objekte belegen Positionen im Absatz; nach `review.newComment` Offsets neu ermitteln.
- `table.columnWidth` ändert **nur die Spalte der Schreibmarke**. Alle Spalten so setzen, dass die Summe = Satzspiegel (A4 mit 2,5/2 cm ≈ 467,7 pt).
## Überarbeitung fremder Dokumente (Nachverfolgung)
1. Original nur öffnen, nie darauf speichern; erste Speicherung sofort mit neuem Namen in den Schreibordner.
2. `file.setAuthor {"name":"Claude"}` und `review.trackChanges {"value": true}` – **immer mit value**; ohne schaltet der Befehl um und kann die Nachverfolgung ausschalten.
3. Ersetzen: `select_text` → `type_text`. Ergebnis ist Einfügung + Löschung (ganzes Wort).
4. **`select_text` findet auch bereits nachverfolgt gelöschten Text.** Nach einer Ersetzung nicht erneut nach dem alten Wortlaut suchen; zum Markieren das neue Wort verwenden.
2. `file.setAuthor {"name":"…"}` und `review.trackChanges {"value": true}` – **immer mit value**.
3. Ersetzen: `select_text` → `type_text`. Ergebnis ist Einfügung + Löschung.
4. **`select_text` findet auch bereits nachverfolgt gelöschten Text.** Nach einer Ersetzung nicht erneut nach dem alten Wortlaut suchen.
5. Begründungen als Kommentar: Text markieren, `review.newComment {"text": ...}`.
6. Prüfen: `review.changes` (Liste mit author, kind, text) und `review.comments` – auch nach dem Neuöffnen der gespeicherten Datei.
6. Prüfen: `review.changes` und `review.comments` – auch nach dem Neuöffnen.
## Rezepte
Platzhalter-Konvention: `{{Feldname}}` (Jinja2-kompatibel).
### 1. Neues Dokument
A4, Ränder, de-DE, Formatvorlagen Title/Heading1/Heading2/Normal anpassen → Inhalt aufbauen → Kopfzeile → Fußzeile „Seite x von y“ → Tabelle mit Kopfzeile → nummerierte Liste (`para.numbering`) → ggf. Hinweiskasten → `render_page` → speichern.
### 2. Vorlage aus bestehendem Dokument
Kopie im Lese-Ordner öffnen → `inspect_document` → Löschungen von unten nach oben → Ersetzungen per `select.range` (Absatzindex) bzw. `select.text` (Teilstücke) → Platzhalter `{{Feldname}}` gelb markieren → `get_text` prüfen, dass keine Ursprungsdaten (Namen, Adressen, Preise) übrig sind → unter neuem Namen speichern.
### 3. Vorlage füllen
Vorlage öffnen → Felder per `select.text "{{Feld}}"` + `text.insert` im batch ersetzen → wiederholbare Listenpunkte ergänzen/löschen → Markierung entfernen → `get_text` auf `{{` prüfen → rendern → unter neuem Namen speichern (.docx + .pdf).
## Abschlussprüfung
- Alle Seiten mit `render_page` ansehen; Seitenzahl plausibel.
- Bei Vorlagen/gefüllten Dokumenten: `get_text` auf `{{` bzw. Altdaten prüfen.
- Gespeicherte Datei neu öffnen und kurz gegenlesen.
- Pfad dem Nutzer nennen.
## Datenschutz
- Grün: allgemeine/technische Inhalte ohne Kundenbezug.
- Gelb: Projekt-/Geschäftsinfos, Preise (oft vertraulich) nur nach Abwägung oder anonymisiert.
- Rot: personenbezogene Daten (Ansprechpartner, E-Mail, Telefon) und NDA-Inhalte nicht in die Cloud-KI.
- Vorlagen aus **geschwärzten** Kopien erstellen; im Freitext Platzhalter statt echter Namen verwenden.
## Eigenschaften (Kurzreferenz)
Längen in Punkt, Farben als `"#RRGGBB"`, `[r,g,b]` oder `{"Rgb":[r,g,b]}`; bei Tabellenbefehlen `"RRGGBB"` ohne #. Unbekannte Feldnamen werden **still ignoriert**.
- Zeichen (`format.set {"props": …}`): `font`, `size`, `bold`, `italic`, `underline`, `color`, `highlight`, `vertAlign`, `lang`, `link`
- Absatz (`para.set {"props": …}`): `style`, `align`, `indentLeft`, `indentFirst`, `spaceBefore`, `spaceAfter`, `lineSpacing` (`{"rule":"multiple","value":1.15}`), `keepNext`, `keepLines`, `pageBreakBefore`, `outlineLevel`, `numbering`, `tabs`, `borders`
- Absatz (`para.set {"props": …}`): `style`, `align`, `indentLeft`, `indentFirst`, `spaceBefore`, `spaceAfter`, `lineSpacing` (`{"rule":"multiple","value":1.15}`), `keepNext`, `keepLines`, `pageBreakBefore`, `outlineLevel`, `numbering`, `tabs`, `borders`, `shading`
## Renderer-Grenzen (0.8.0)
Bekannte Darstellungsfehler von `render_page`, die **nicht** von eigenen Änderungen kommen:
- mehrzeilige Zellen in dunkel hinterlegten Tabellenköpfen zeigen nur die letzte Zeile
- Seitenzahlfelder in Fußzeilen importierter python-docx-Dokumente bleiben leer
Bei Auffälligkeiten erst das Original rendern und vergleichen, bevor man die eigene Änderung verdächtigt.
Bei Auffälligkeiten erst das Original rendern und vergleichen.
## Word-Kompatibilität
@@ -133,5 +156,5 @@ Bei Auffälligkeiten erst das Original rendern und vergleichen, bevor man die ei
## Grenzen
- Die Ordnerbeschränkung gilt nur headless; mit `--connect` ist die App nicht eingeschränkt.
- Die Ordnerbeschränkung gilt nur headless; mit verbundener Desktop-App entfällt sie.
- Befehle ohne Pfad wirken immer auf das zuletzt geöffnete Dokument. Vor dem Öffnen eines anderen Dokuments speichern.
+3 -3
View File
@@ -2,7 +2,7 @@
"manifest_version": "0.3",
"name": "wordcraft-mcp",
"display_name": "WordCraft for Claude",
"version": "0.2.0",
"version": "0.3.0",
"description": "Word-Dokumente (.docx, .odt, .md, PDF) erstellen und bearbeiten. Getestet mit WordCraft 0.8.0. Benötigt WordCraft aus dem ArtCraft-Launcher unter C:\\Program Files\\WordCraft\\.",
"author": {
"name": "Dominic Gundel"
@@ -105,14 +105,14 @@
"read_root": {
"type": "directory",
"title": "Lese-Ordner",
"description": "Hier darf Claude Dokumente lesen.",
"description": "Weit fassen (Standard: Dokumente, gern ganzer Benutzerordner). Lesen ist per Freigabe-Dialog kontrollierbar.",
"required": true,
"default": "${HOME}/Documents"
},
"write_root": {
"type": "directory",
"title": "Schreib-Ordner",
"description": "Nur hier darf Claude speichern. Eigenen Ordner wählen, z. B. Dokumente\\Claude-Ausgabe – nicht den Lese-Ordner.",
"description": "Eng halten: eigener Ordner, z. B. Dokumente\\Claude – nicht denselben wie den Lese-Ordner. Schreiben bleibt hart begrenzt.",
"required": true
},
"author": {
+2 -2
View File
@@ -4,7 +4,7 @@
## Zweck
Wofür ist dieser Skill da, und was kann Claude damit, was es ohne ihn nicht zuverlässig kann?
Wofür ist dieser Skill da, und was kann der Agent damit, was er ohne ihn nicht zuverlässig kann?
## Voraussetzungen
@@ -17,7 +17,7 @@ Git ist nicht nötig.
1. Das ZIP aus dem Release in der [Übersicht](../../README.md) laden.
2. In Claude **„+“ → „Skill erstellen“ → „Skill hochladen“** wählen und das ZIP hochladen.
Hat der Skill einen Ordner `extension/`, zusätzlich die `.mcpb` aus demselben Release installieren und auf [docs/INSTALLATION.md](../../docs/INSTALLATION.md) verweisen. Die manuelle Config gehört dann ans Ende unter „Alternative: manuell (für Entwickler)“.
Hat der Skill einen Ordner `extension/`, zusätzlich die `.mcpb` aus demselben Release installieren und auf [docs/INSTALLATION.md](../../docs/INSTALLATION.md) verweisen. Für Cursor: Cursor-Plugin-ZIP bzw. [docs/CURSOR.md](../../docs/CURSOR.md). Die manuelle Config gehört ans Ende unter „Alternative: manuell (für Entwickler)“. Client-Details (Store-Pfad, Erweiterungs-UI) nur hier in der README, nicht in der SKILL.md.
## Einrichtung
+17 -5
View File
@@ -1,19 +1,19 @@
---
name: SKILL_NAME
description: "Wann dieser Skill verwendet werden soll – ein Satz."
description: "Wann dieser Skill verwendet werden soll – Auslöser und Abgrenzung in einem Satz."
---
# SKILL_NAME
Ein, zwei Sätze: Wofür ist dieser Skill da, und was kann Claude damit, was es ohne ihn nicht zuverlässig kann?
Ein, zwei Sätze: Wofür ist dieser Skill da? **Keine clientspezifischen Anweisungen** (kein Claude Desktop, Cursor, Store-Pfad, Erweiterungs-UI). Solche Hinweise gehören in die README bzw. docs/.
## Voraussetzung
Was muss eingerichtet oder verbunden sein (MCP-Server, Programme, Zugänge)? Was soll Claude tun, wenn es fehlt?
Welche Werkzeuge/Server verbunden sein müssen (clientneutral: Namen ohne festen Präfix). Was tun, wenn sie fehlen (Nutzer auf README verweisen, nicht auf ein anderes Programm ausweichen).
## Arbeitsweise
Die Schritte in der Reihenfolge, in der Claude sie ausführen soll. Konkrete Befehle und Beispiele statt allgemeiner Ratschläge.
Die Schritte in der Reihenfolge, in der der Agent sie ausführen soll. Konkrete Befehle und Beispiele statt allgemeiner Ratschläge.
1. …
2. …
@@ -24,8 +24,20 @@ Was in der Praxis schiefgegangen ist und wie man es vermeidet. Jede Falle mit Sy
- …
## Rezepte
Kurze Abläufe für typische Aufgaben (optional, wenn der Skill MCP-Werkzeuge steuert).
## Abschlussprüfung
Checkliste vor dem Abschluss (optional).
## Datenschutz
Ampel oder kurze Regeln, wenn Inhalte in Cloud-Modelle gehen können (optional).
## Grenzen
Was der Skill nicht abdeckt oder wo Claude den Nutzer fragen bzw. warnen soll.
Was der Skill nicht abdeckt oder wo der Agent den Nutzer fragen bzw. warnen soll.
- …