# WP-LIT-MCP – Design-Spezifikation - **Datum:** 2026-09-25 - **Status:** Entwurf zur Freigabe - **Autor:** Jan-Niclas Loosen (Loosen-IT), erarbeitet mit Claude ## 1. Ziel und Kontext ### 1.1 Problem Die Pflege von Kunden-Websites (WordPress + Divi 5 + Pods) kostet viel Handarbeit: Seiten anlegen, in Menüs hängen, Divi-Abschnitte bauen, Corporate Designs in Divi übertragen, Custom-Post-Type-Einträge befüllen. Bestehende WordPress-MCP-Plugins erzeugen nur rohes HTML, das im Divi-Builder nicht weiterbearbeitet werden kann. Der Divi AI Agent (Divi 5) arbeitet nur im Builder, läuft über das kostenpflichtige AI Wallet und bietet (Stand 2026-09) keine MCP-Schnittstelle. ### 1.2 Ziel Ein WordPress-Plugin, das auf jeder Kundenseite einen MCP-Server bereitstellt, mit dem Claude (claude.ai-Connector) die Website pflegt – **so, dass alle Ergebnisse native Divi-Strukturen sind, die der Mensch im Divi Visual Builder weiter verfeinern kann.** ### 1.3 Erfolgskriterien 1. Ein claude.ai-Connector verbindet sich per OAuth mit einer Kundenseite; nur freigegebene Rollen können Tools nutzen. 2. Von Claude erzeugte oder geänderte Divi-Inhalte sind im Visual Builder vollständig bearbeitbar (manuell verifiziert pro Etappe). 3. Unangetastete Inhalte bleiben byte-identisch erhalten. Dokumentierte Ausnahme (Ruling S7): Divi selbst normalisiert Seiten mit eigenen HTML-/Attribut-Feldern beim Speichern (`AttributeSecurity`/`HtmlSecurity` auf `wp_insert_post_data`, laufen für jeden Benutzer und werden nie entfernt) – aber nur, wenn die Seite noch nicht in Divis `serialize_blocks()`-Form gespeichert war (z. B. Import, direkter DB-Schreibzugriff); über Builder oder LIT MCP gespeicherte Seiten bleiben unverändert (E2E Abschnitt 8a); die Antwort meldet das als Warnung „Inhalt beim Speichern verändert“ (`CHANGED_ON_SAVE`), die Seite bleibt gültig (E2E `divi-write-smoke.sh` Abschnitt 8). 4. Eine neue Website (Seitenstruktur, Menü, Einstellungen, Designsystem aus einem CD) lässt sich im Dialog aufsetzen. 5. Jede Änderung ist nachvollziehbar (Protokoll) und umkehrbar (Revision bzw. Snapshot). ### 1.4 Verifizierte Grundlagen - Handgeschriebenes Divi-5-Block-Markup (``) wird von Divi als native Module gerendert (`et_pb_section`, `et_pb_heading`, …) und ist im Visual Builder bearbeitbar (lokal getestet, 2026-09-25). - Divi liefert serverseitig alle Modul-Metadaten: `ModuleRegistration::get_all_core_modules_metadata()` (100 Module mit Attribut-Schemata), Default-Attribute über `ModuleRegistration::get_default_attrs()`. - WordPress 7.0 enthält die Abilities API im Kern. ## 2. Grundprinzipien 1. **Divi-nativ:** Es werden nur echte Divi-Blöcke erzeugt. Das Code-Modul ist erlaubt, wird aber nachrangig behandelt (Katalog-Hinweis „nur wenn kein natives Modul passt“, Warnung bei Verwendung). Jedes erzeugte Element erhält ein sprechendes Admin-Label. 2. **Designsystem an der Quelle:** Farben, Schriften, Variablen, Presets werden immer live aus Divi/WordPress gelesen; es gibt keine doppelte Pflege. Neue Inhalte nutzen Variablen und Presets statt fester Werte. 3. **Generisch vor fest verdrahtet:** Post-Typen, Taxonomien und Felder werden pro Installation erkannt. Spezifische Logik nur über generische Erweiterungspunkte. 4. **Integrationen nach Verfügbarkeit:** Jede Integration (Divi, Pods, …) registriert ihre Tools nur, wenn das Theme/Plugin aktiv ist. 5. **Status bleibt erhalten:** Schreib-Tools ändern nie den Veröffentlichungsstatus. Veröffentlichen/Zurückziehen/Planen sind eigene, explizite Tools. Veröffentlichte Inhalte werden live bearbeitet (mit Revision). 6. **Produktiv tauglich:** Jeder Aufruf läuft mit den Rechten des verbundenen WP-Benutzers; zusätzlich Rollen-Freigabe und Rechteprüfung pro Tool. 7. **Nichts geht verloren:** Revision oder Snapshot vor jeder Änderung, optimistische Sperre (`rev`) gegen das Überschreiben paralleler Handarbeit. ## 3. Umfang ### 3.1 v1 – Muss | # | Bereich | Inhalt | |---|---|---| | 1 | Anbindung | OAuth 2.1 für claude.ai (CIMD), Rollen-Gate, Verbindungsübersicht mit Widerruf | | 2 | Content generisch | Schema-Erkennung (Post-Typen, Taxonomien, WP-Meta, Pods-Felder); Einträge suchen/lesen/anlegen/bearbeiten; veröffentlichen/zurückziehen/planen; duplizieren und Kopie gegen Original tauschen; Papierkorb; Revisionen | | 3 | Menüs | anlegen, Einträge deklarativ setzen, Positionen zuweisen | | 4 | Medien | suchen, ansehen (inkl. Vorschaubild), Upload per URL und per Datei, Download, Metadaten/Alt-Texte (auch Stapel), Löschen mit Verwendungsprüfung | | 5 | Divi-Seiten | Seitenbaum, Modul-Katalog, einfügen/ändern/verschieben/löschen/duplizieren, seitenübergreifendes Ersetzen mit Dry-Run | | 6 | Divi Theme Builder | Vorlagen auflisten/anlegen/zuweisen, Layouts bearbeiten, Dynamic Content (Pods-Felder, Meta, Post-Daten) | | 7 | Divi Library / globale Module | speichern, einfügen (Kopie/global), zwischen Seiten kopieren, in globales Modul umwandeln, ähnliche Abschnitte finden | | 8 | Divi-Designsystem | globale Farben, Variablen, Presets lesen und schreiben; Snapshots | | 9 | Divi-Theme-Optionen | Schriften, Größen, Farben, Buttons, Layout-Maße, Logo, Divi-SEO – über Whitelist | | 10 | WP-Einstellungen | Allgemein, Lesen (Startseite), Permalinks, Diskussion, Website-Icon – über Whitelist | | 11 | Rückmeldung | einheitliches `ToolResult`; `page_render_summary` | | 12 | Protokoll | Änderungsprotokoll mit Aufbewahrungsdauer, Cron-Bereinigung, Leeren | | 13 | Anleitungen | Server-Instructions, Tool `lit/guide`, MCP-Prompts | ### 3.2 Kann - Google Fonts herunterladen und über Divis Font-Upload selbst hosten. - Pods-Strukturen (Pods, Felder) anlegen. - Signierte, zeitlich begrenzte Vorschau-Links für Entwürfe ohne Login. - Freitext-Hinweise pro Seite (z. B. Tonalität, Du/Sie) als Ergänzung der Server-Instructions. ### 3.3 Später - SEO-Plugins (Yoast, Rank Math) als eigene Integrationen. - „Fast gleich“-Erkennung von Abschnitten mit Detail-Unterschieden. - Tickets und wiederkehrende Termine (The Events Calendar Pro). - Umstieg auf MCP-Protokoll 2026-07-28 (sobald der Adapter es unterstützt, siehe §11). ### 3.4 Nicht im Umfang - Benutzerverwaltung (Sicherheitsrisiko; ggf. später mit eigenem Konzept). - Mehrsprachigkeit (WPML/Polylang). - Divi Premade Layouts. - Divi 4 / Shortcode-Inhalte (werden gelesen/erhalten, aber nicht bearbeitet). ## 4. Architektur ### 4.1 Bausteine auf der Kundenseite ``` claude.ai ──OAuth 2.1 (CIMD, PKCE)──▶ wp-media/mcp-oauth (Autorisierung, Token → WP-Benutzer) │ ▼ wordpress/mcp-adapter (MCP-Protokoll, Streamable HTTP) │ ▼ WP-LIT-MCP (Abilities, Server-Konfiguration, Admin) ``` - WP-LIT-MCP bindet `wp-media/mcp-oauth` und `wordpress/mcp-adapter` per Composer ein (Jetpack-Autoloader, `vendor/autoload_packages.php`). Ausgeliefert wird ein einzelnes Plugin. - WP-LIT-MCP enthält **keine eigene OAuth-Implementierung**. Die Anbindungsschicht ist austauschbar; Rückfalloption ist `akirk/mcp-connect` (separates Plugin, nutzt allerdings das inzwischen veraltete Dynamic Client Registration). - Versionen werden in `composer.lock` fixiert; jedes Update durchläuft den Konformitätstest (§11.4). ### 4.2 Anpassungen an wp-media/mcp-oauth Die Bibliothek (v1.1.x) hat Lücken, die WP-LIT-MCP schließt: | Lücke | Lösung | |---|---| | Kein Rollen-Gate (jeder eingeloggte Benutzer kann autorisieren) | Eigene Capability `lit_mcp_use`, vergeben an die in den Einstellungen freigegebenen Rollen. Gesetzt über die Adapter-Filter `mcp_adapter_{discover_abilities,get_ability_info,execute_ability}_capability` und zusätzlich in jeder Ability geprüft. | | Erzeugtes Application Password gilt für alle REST-Routen (Issue #62) | Code-Analyse (v1.1.2): Das Klartext-Passwort wird verworfen, die Token-Prüfung läuft nur in der MCP-Route – vermutlich nicht ausnutzbar. Etappe 0 prüft das per Ende-zu-Ende-Test (Bearer-Token gegen `/wp/v2/users/me` muss 401 liefern). Nur falls der Test fehlschlägt: Filter auf `rest_authentication_errors`, der Bearer-Requests außerhalb der MCP-Route abweist. | | Server fest mit drei Meta-Tools, keine direkten Tools | WP-LIT-MCP registriert den Server `mcp-oauth-server` auf `mcp_adapter_init` mit Priorität < 10 selbst, mit `OAuthHttpTransport` und eigener Tool-Liste. Folge bis upstream PR #63: harmloser „duplicate server“-Log-Eintrag. | | Adapter auf `^0.5` gepinnt | Akzeptiert; Beobachtung der Upstream-Entwicklung. | Ob dieser Aufbau stabil funktioniert, entscheidet Etappe 0 (§12). ### 4.3 Tool-Exposition (hybrid) - **Direkte Tools (~20):** mit vollem Schema sofort sichtbar; nur direkte Tools können Bilder (`ImageContent`) zurückgeben. Standard-Set: `lit/guide`, `lit/content-types`, `lit/content-query`, `lit/content-get`, `lit/content-create`, `lit/content-update`, `lit/post-publish`, `lit/media-search`, `lit/media-preview`, `lit/media-upload-from-url`, `lit/divi-outline`, `lit/divi-node-get`, `lit/divi-insert`, `lit/divi-update`, `lit/divi-move`, `lit/divi-delete`, `lit/divi-design-system`, `lit/divi-catalog`, `lit/library-insert`, `lit/page-render-summary`. - **Stand nach Etappe 2 (Entscheidung D2, 2026-09-26):** 21 direkte Tools – das Standard-Set oben ohne `lit/library-insert` (kommt mit Etappe 3), dazu `lit/site-status` (leeres Eingabeschema, Anker der Verbindungstests) und `lit/media-download` (eingebettete Ressource, funktioniert nur direkt). `lit/divi-duplicate-node` und `lit/divi-replace-text` sind indirekt. Mit Etappe 3 sind es 22; das Budget wird dort erneut geprüft (Kosten entstehen vor allem durch große Eingabeschemas, nicht durch die Zahl). - **Alle übrigen Abilities:** über die Meta-Tools des Adapters (`discover-abilities`, `get-ability-info`, `execute-ability`). - In den Einstellungen änderbar, welche Abilities direkt, indirekt oder deaktiviert sind. - Ability-Namen: `lit/-`. Der Adapter bildet daraus Tool-Namen (`lit--`). ### 4.4 Plugin-Struktur - Composer, PSR-4 (`LIT\MCP\` → `src/`), PHP ≥ 8.1, WordPress ≥ 6.9 (getestet mit 7.0). - Kein Acorn (Größe, Konfliktrisiko auf fremden Seiten, kein Nutzen für ein Plugin ohne UI-Schwerpunkt). ``` wp-lit-mcp.php Plugin-Header, Bootstrap src/ Core/ Plugin.php Start, Hooks, Abhängigkeitsprüfung IntegrationRegistry.php sammelt verfügbare Integrationen AbilityRegistrar.php registriert Abilities + Kategorien, Server-Konfiguration Access.php Rollen-Gate, Capability lit_mcp_use, App-Password-Scope-Filter ToolResult.php einheitliche Rückmeldung ToolError.php verwertbare Fehler ChangeLog/ Tabelle, Repository, Cron-Bereinigung Guides/ Guide-Loader, Server-Instructions, Prompts Admin/ Einstellungsseite, Protokoll-Ansicht (Settings API, WP_List_Table) Integrations/ Integration.php Interface: isAvailable(), abilities(), prompts() (Sonderfälle innerhalb einer Integration: abilities() lässt nicht nutzbare Tools einfach weg) WordPress/ Content, Schema, Status/Kopie, Revisionen, Menüs, Einstellungen Media/ Medien-Tools, Verwendungssuche Divi/ BlockTree/ Parser, Serializer, Node, Pfad-Adressierung (reines PHP) Schema/ Modul-Katalog, Attributpfad-Validierung Compose/ Kurzform → Blöcke, Platzhalter-Auflösung Pages/ Seiten-Tools, Speicher-Pipeline Library/ Library, globale Module, find_similar ThemeBuilder/ Vorlagen, Zuweisungen, Dynamic Content Design/ Farben, Variablen, Presets, Theme-Optionen, Snapshots Pods/ Feld-Adapter für die Schema-Erkennung, Schreiben via Pods-API docs/guides/*.md Anleitungen für lit/guide tests/Unit, tests/Integration, tests/Fixtures ``` ### 4.5 Rechte (dreistufig) 1. **Verbinden:** mcp-oauth-Autorisierung (jeder eingeloggte Benutzer). 2. **Nutzen:** Capability `lit_mcp_use` (nur freigegebene Rollen) – geprüft über Adapter-Filter und in jeder Ability. 3. **Handeln:** konkrete Prüfung pro Ability, z. B. `edit_post` für die Ziel-ID, `publish_post` fürs Veröffentlichen, `upload_files`, `edit_theme_options` für Divi-Designsystem und Menüs, `manage_options` für WP-Einstellungen, `edit_others_posts` für Theme Builder (Divi-Anforderung). ## 5. Divi-Kern ### 5.1 Grundidee Seiten, Theme-Builder-Layouts (`et_header_layout`, `et_body_layout`, `et_footer_layout`) und Library-Einträge (`et_pb_layout`) speichern Block-Markup in `post_content`. Alle Divi-Bearbeitungstools arbeiten auf jeder dieser Post-Arten über die `post_id`. ### 5.2 BlockTree - Parst `post_content` in einen Baum (auf Basis von `parse_blocks`, mit Sonderbehandlung für `divi/global-layout` und `globalModule`, die `parse_blocks` laut Divi-Code nicht korrekt verarbeitet). - Serialisiert den Baum zurück; unveränderte Knoten werden aus ihrem Original-Markup übernommen. - **Invariante:** Parse → Serialize ohne Änderung ergibt byte-identischen Inhalt. Fremde/unbekannte Blöcke bleiben unberührt. Ausnahme beim Speichern (nicht im BlockTree): Divi selbst normalisiert Seiten mit eigenen HTML-/Attribut-Feldern beim Speichern (`module.decoration.attributes`, `module.advanced.html` mit `htmlBefore`/`htmlAfter`/`elementType`) – Divi parst und serialisiert dann die ganze Seite neu, was nur Bytes ändert, die noch nicht in Divis `serialize_blocks()`-Form vorlagen; gemeldet als `CHANGED_ON_SAVE` (Ruling S7). - Reines PHP ohne WordPress-Abhängigkeit (vollständig unit-testbar). - Attributwerte mit `$variable(...)$` werden beim Serialisieren wie von Divi erwartet escaped (`"` → `"`). - Umsetzung (D3): eigener Tokenizer mit dem Delimiter-Muster von `WP_Block_Parser` statt `parse_blocks()` – ohne WordPress testbar, jedes Byte zwischen den Delimitern bleibt erhalten. Knoten mit `globalModule`, `divi/global-layout` oder nicht dekodierbaren Attributen sind undurchsichtig: sie werden nicht betreten, nur als Ganzes verschoben, dupliziert oder gelöscht (Bearbeitung ab Etappe 3). Unbalanciertes Markup wird abgelehnt, nie repariert. ### 5.3 Adressierung und optimistische Sperre - `lit/divi-outline` liefert den Baum mit Pfad-IDs (`s0`, `s0.r1`, `s0.r1.c0.m2`), Modultyp, Admin-Label, Textauszug und Preset-Namen. - Jede Antwort enthält `tree_rev` = Hash des aktuellen `post_content` (Sperre der Divi-Werkzeuge) und `rev` = Sperre des ganzen Eintrags (`Rev::ofPost`, dieselbe wie bei `lit/content-get` und `lit/content-update`; Ruling P16). - Jedes Divi-Schreib-Tool verlangt `tree_rev`. Weicht sie ab, wird abgelehnt (`rev_mismatch`), nichts geschrieben; Claude liest neu. Pfad-IDs gelten immer relativ zu einer `tree_rev`. Jede Schreib-Antwort liefert die neue `tree_rev` und die neuen Pfad-IDs der geänderten Knoten. - Buchstaben der Pfad-IDs: `s` Abschnitt, `r` Zeile (auch `row-inner`), `c` Spalte (auch `column-inner`), `m` Modul (auch Kind-Module und Gruppen), `g` globales Modul bzw. globales Layout, `x` fremder Block (z. B. Block-Editor); gezählt wird je Buchstabe innerhalb des Elternknotens, `divi/placeholder` ist transparent. ### 5.4 Modulbeschreibung **Kurzform** (kuratiertes Mapping für ~20 Module: Text, Heading, Button, Image, Blurb, CTA, Icon, Divider, Testimonial, Team Member, Accordion(+Item), Tabs(+Tab), Toggle, Gallery, Slider(+Slide), Contact Form(+Field), Map, Video, Number Counter, Social Media Follow(+Item), Icon List(+Item)): ```json { "type": "button", "text": "Termin buchen", "url": "/kontakt", "preset": "CTA primär", "label": "Hero – Button" } ``` **Vollform** (alle Module, alle Einstellungen, Divis Attributpfade): ```json { "type": "heading", "attrs": { "title.decoration.font.font": { "desktop": { "color": "{{color:primary}}" }, "phone": { "size": "28px" } } } } ``` - Attributpfade werden gegen den Katalog (`get_all_core_modules_metadata`) validiert; unbekannte Pfade → `invalid_attr_path` mit Vorschlägen. - Responsive-Werte über die Schlüssel `desktop` / `tablet` / `phone` (optional `hover`, `sticky`, wo das Modul es unterstützt). - Kurz- und Vollform sind kombinierbar (Kurzform + zusätzliche `attrs`). **Struktur:** Abschnitt → Zeilen (`"columns": "1_3,2_3"`) → Spalten → Module. Spezialabschnitte (fullwidth) über `"section_type"`. **Platzhalter** (vom Plugin in Divis `$variable(...)$`-Syntax übersetzt): | Platzhalter | Ergebnis | |---|---| | `{{color:primary}}`, `{{color:}}` | globale Farbe (`gcid-…`; Aliase primary/secondary/heading/body/link) | | `{{var:}}` | globale Variable (`gvid-…`), Suche über Label | | `{{font:heading}}`, `{{font:body}}` | Theme-Schriften (`--et_global_heading_font` / `--et_global_body_font`) | | `{{post:title}}`, `{{post:excerpt}}`, `{{post:date}}`, … | Dynamic Content (Post-Daten) | | `{{field:}}` | Dynamic Content `custom_meta_` (Pods/Meta) | | `"preset": ""` | `modulePreset: [""]` | Unbekannte Namen → Fehler mit Liste der vorhandenen. ### 5.5 Qualitätsregeln und Warnungen Jede Schreib-Rückmeldung enthält Warnungen zu: - festen Farben/Schriften, wenn eine passende Variable existiert, - Bildern ohne Alt-Text, - leeren Modulen, - Sprüngen in der Überschriftenhierarchie, - Verwendung des Code-Moduls, - ähnlichen, bereits existierenden Abschnitten (Hinweis auf `lit/library-find-similar`) – ab Etappe 3 zusammen mit `lit/library-find-similar` (D6). Kurzform setzt Admin-Labels automatisch (` – `), sofern nicht angegeben. ### 5.6 Speicher-Pipeline 1. Rechte prüfen (`edit_post`), `tree_rev` prüfen. 2. Änderung auf dem BlockTree ausführen, validieren (alles oder nichts). 3. Serialisieren, `wp_slash()`, `wp_update_post()` – Status unverändert, vorher Wiederherstellungspunkt (Revision). Für Benutzer ohne `unfiltered_html` wird kses für genau diesen Aufruf abgeschaltet: `filter_block_content()` würde sonst jeden unveränderten Block neu serialisieren (Byte-Identität, globale Module; in DDEV nachgewiesen). Das ist nur vertretbar, weil keine client-gelieferte Zeichenkette ungeprüft in `post_content` gelangt (D7): Klartext-Werte werden je Feldtyp bereinigt (Text: `sanitize_text_field`; Rich-Text: `wp_kses_post`, abhängig von `unfiltered_html`; URLs: `esc_url_raw`, geroutet über die Attribut-Metadaten des Katalogs, ersatzweise über den Schlüsselnamen). Werte mit `$variable(...)$` – ob aus Platzhaltern erzeugt oder unverändert aus `lit/divi-node-get` zurückgegeben – werden geparst, streng geprüft (zulässiger Typ, existierende gcid-/gvid-/Dynamic-Content-Quellennamen, whitelisted Settings-Schlüssel, String-Settings bereinigt) und vom Plugin neu serialisiert; alles andere wird mit `validation_failed` abgelehnt. Ob Divi das Dynamic-Content-`before`/`after` bei der Ausgabe selbst escaped, wird in Etappe 2b im Divi-Quellcode verifiziert; die Bereinigung gilt unabhängig davon (Verteidigung in der Tiefe, R2). 4. Post-Meta `_et_pb_use_divi_5=on`, `_et_pb_use_builder=on` setzen. 5. `ET_Core_PageResource::remove_static_resources($post_id, 'all', true)`; bei globalen Library-Elementen und Theme-Builder-Änderungen `('all', 'all', true)` sowie `et_theme_builder_clear_wp_cache('all')`. 6. Protokolleintrag, `ToolResult` zurückgeben. ### 5.7 Tools | Ability | Art | Beschreibung | |---|---|---| | `lit/divi-outline` | lesen | Baum mit IDs, Labels, Textauszügen, `rev` und `tree_rev` | | `lit/divi-node-get` | lesen | vollständige Attribute eines Knotens (Vollform) | | `lit/divi-catalog` | lesen | Module, Kurzform-Felder, wichtige Attributpfade; Detail pro Modul | | `lit/divi-design-system` | lesen | Farben, Variablen, Presets, Theme-Schriften/-Größen | | `lit/divi-dynamic-sources` | lesen | verfügbare Dynamic-Content-Quellen für einen Post-Typ (über `DynamicContentOptions::get_options` mit einem Beispiel-Post des Typs) – Etappe 3, mit dem Theme Builder (D6) | | `lit/page-render-summary` | lesen | gerenderte Seite als strukturierter Auszug (Überschriften, Texte, Links, Bilder+Alt); Inhaltsbereich, im Prozess über `the_content` gerendert (ohne Header/Footer/Theme Builder); Teil der WordPress-Integration, funktioniert auch ohne Divi (D5) | | `lit/divi-insert` | schreiben | Knoten (Kurz-/Vollform, auch ganze Abschnitte) an Position `parent`/`before`/`after` einfügen | | `lit/divi-update` | schreiben | Werte setzen/entfernen (Kurz- oder Vollform) | | `lit/divi-move` | schreiben | Knoten verschieben (auch zwischen Zeilen/Abschnitten) | | `lit/divi-delete` | schreiben, destruktiv | Knoten entfernen | | `lit/divi-duplicate-node` | schreiben | Knoten duplizieren | | `lit/divi-replace-text` | schreiben | Text seitenübergreifend (je Inhaltstyp) ersetzen, `dry_run` (Standard `true`) liefert Treffer je Seite mit `tree_rev`; ausgeführt wird nur auf diesen `targets` mit `confirm: true`, jede Seite mit eigener Revision (D10) | | `lit/library-list`, `lit/library-get` | lesen | Library-Einträge nach Typ (`layout_type`) und Scope | | `lit/library-save` | schreiben | Knoten als Library-Eintrag speichern (normal oder global) | | `lit/library-insert` | schreiben | Library-Eintrag als Kopie oder globale Instanz einfügen | | `lit/divi-node-copy` | schreiben | Knoten von Seite A nach Seite B kopieren | | `lit/library-make-global` | schreiben | Knoten in globales Modul umwandeln; optional gleichartige Vorkommen ersetzen | | `lit/library-find-similar` | lesen | ähnliche Abschnitte seitenübergreifend (Struktur-Fingerabdruck: Modultypen, Aufbau, Presets) | | `lit/tb-list` | lesen | Vorlagen, Bedingungen, Layouts | | `lit/tb-create-template` | schreiben | Vorlage mit Header/Body/Footer-Layouts anlegen (`et_theme_builder_insert_layout`, `et_theme_builder_store_template`, Meta `_et_template`) | | `lit/tb-assign` | schreiben | Bedingungen (`_et_use_on`/`_et_exclude_from`, z. B. `singular:post_type:person:all`) setzen | ## 6. WordPress-Basis ### 6.1 Schema-Erkennung (`lit/content-types`) - Post-Typen mit `show_ui`: Name, Labels, `supports`, hierarchisch, Divi-fähig, Anzahl. - Taxonomien pro Typ. - Felder pro Typ, zusammengeführt aus: - `get_registered_meta_keys()` (Kern), - **Pods-Adapter:** Feldtyp, Pflicht, Auswahlwerte, Beziehungsziel, Mehrfachwert (über Pods-API), - gefundenen Meta-Schlüsseln (Stichprobe; `_`-Schlüssel ausgeblendet, sofern kein Adapter sie kennt). - Status pro Feld: `writable`, `readonly`, `unknown` (Schreiben erlaubt, mit Warnung). ### 6.2 Content-Tools (jeder Post-Typ) | Ability | Beschreibung | |---|---| | `lit/content-query` | Filter: Typ, Status, Suche, Taxonomie, Feldwert, Datum; Cursor-Paginierung | | `lit/content-get` | Kerndaten, Terms, Felder, Beitragsbild; bei Divi-Inhalt Verweis auf `lit/divi-outline` | | `lit/content-create` | neuer Eintrag, **Standard: Entwurf**; Felder gegen Schema validiert; optional Divi-Inhalt in Kurzform | | `lit/content-update` | Kerndaten, Terms, Felder ändern (Status unverändert) | | `lit/post-publish`, `lit/post-unpublish`, `lit/post-schedule` | Statuswechsel, explizit | | `lit/post-duplicate` | Entwurfskopie inkl. Meta, Terms, Divi-Flags | | `lit/post-replace-with-copy` | Inhalt/Meta/Terms der Kopie ins Original übernehmen (ID, URL, Menüeinträge bleiben); Original erhält vorher Revision; Kopie → Papierkorb | | `lit/post-trash` | nur Papierkorb, nie endgültig löschen | | `lit/revisions-list`, `lit/revision-restore` | Revisionen | - Pods-Felder werden über die Pods-API geschrieben (Beziehungen, Caches), sonstige Felder über die Meta-API. - Erweiterungspunkt `lit_mcp_after_save` (Action): Integrationen können abgeleitete Felder nachberechnen (z. B. falls The Events Calendar dies erfordert – Prüfung in Etappe 0). ### 6.3 Medien | Ability | Beschreibung | |---|---| | `lit/media-search` | Text, MIME-Typ, Datum, `missing_alt`, `unused` | | `lit/media-get` | Metadaten, Größen, URLs, Verwendungsorte | | `lit/media-preview` | verkleinertes Bild als `ImageContent` (direktes Tool, kein `outputSchema`) | | `lit/media-upload-from-url` | Import via `wp_safe_remote_get` (SSRF-Schutz), MIME-Whitelist, Größenlimit | | `lit/media-upload` | Base64-Upload, Limit einstellbar (Standard 5 MB) | | `lit/media-download` | Original oder Größe als eingebettete Ressource (Blob) | | `lit/media-update` | Alt, Titel, Bildunterschrift, Beschreibung – auch Stapel | | `lit/media-delete` | nur mit `confirm: true`; bei Verwendung abgelehnt außer `force: true` | Verwendungssuche: Anhang-ID in Divi-Attributen, Beitragsbildern, Galerie-Feldern und Meta. Divi-Bildmodule, Hintergründe und Galerien referenzieren Bilder per Anhang-ID (plus URL, wie Divi es speichert). ### 6.4 Menüs `lit/menu-list`, `lit/menu-get` (Baum), `lit/menu-create`, `lit/menu-set-items` (deklarativer Gesamtbaum oder Einzeloperationen hinzufügen/verschieben/entfernen), `lit/menu-assign-location`. ### 6.5 WordPress-Einstellungen `lit/wp-settings-get`, `lit/wp-settings-update` über Whitelist: - Allgemein: `blogname`, `blogdescription`, `WPLANG`, `timezone_string`, `date_format`, `time_format` - Lesen: `show_on_front`, `page_on_front`, `page_for_posts`, `posts_per_page` - Diskussion: `default_comment_status`, `default_ping_status` - Permalinks: `permalink_structure` (danach `flush_rewrite_rules()`) - Website-Icon: `site_icon` Gesperrt: `admin_email`, `users_can_register`, `default_role`, `siteurl`, `home`. ## 7. Divi-Designsystem und Theme-Optionen | Ability | Beschreibung | |---|---| | `lit/divi-colors-set` | globale Farben anlegen/ändern inkl. der fünf Hauptfarben (über `GlobalData::set_global_colors`) | | `lit/divi-variables-set` | Variablen (numbers, strings, images, links, fonts) über `GlobalData::set_global_variables` | | `lit/divi-presets-set` | Modul- und Gruppen-Presets anlegen/ändern, per Name (über `GlobalPreset::save_data`) | | `lit/divi-theme-options-get`, `lit/divi-theme-options-update` | Whitelist mit Typ und Beschreibung pro Feld (s. u.) | | `lit/divi-design-snapshots`, `lit/divi-design-restore` | Snapshots auflisten und wiederherstellen | | `lit/divi-font-upload-google` (Kann) | Google-Schrift (TTF) laden, über `FontsUtility::font_add` ablegen | Theme-Options-Whitelist (Auszug, vollständige Liste in der Implementierung mit Typen): - Schriften: `heading_font`, `body_font`, `heading_font_weight`, `body_font_weight`, `primary_nav_font`, `secondary_nav_font`, `all_buttons_font` - Größen: `body_font_size`, `tablet_body_font_size`, `phone_body_font_size`, `body_header_size`, `tablet_header_font_size`, `phone_header_font_size`, `body_font_height`, `body_header_height`, `body_header_spacing`, `body_header_style` - Layout: `content_width`, `gutter_width`, `section_padding`, `row_padding` - Farben: `accent_color`, `secondary_accent_color`, `header_color`, `font_color`, `link_color` - Buttons: `all_buttons_*` inkl. `*_hover` - Logo: `divi_logo` - SEO: `divi_seo_home_*`, `divi_seo_single_*`, `divi_seo_index_*` Regeln: - Schreiben ausschließlich über Divis eigene Funktionen; danach `ET_Core_PageResource::remove_static_resources('all', 'all', true)`. - Vor jeder Änderung wird der betroffene Bereich (Farben, Variablen, Presets oder Theme-Optionen) als **Snapshot** gesichert (eigene Option, begrenzte Anzahl, Standard 20). Snapshot-ID im `ToolResult` und im Protokoll. - Voraussetzung: `edit_theme_options`; für Variablen zusätzlich Divis Rollen-Recht `variables_manager`. Ablauf „Corporate Design übernehmen“ (Prompt, §9.3): Claude liest das CD im Chat → `lit/divi-design-system` → schlägt Zuordnung vor → nach Bestätigung Schreiben über die Tools oben. ## 8. Rückmeldung, Fehler, Protokoll, Einstellungen ### 8.1 ToolResult ```json { "ok": true, "summary": "Button in 'Hero' aktualisiert", "changed": [{ "id": "s0.r0.c0.m2", "type": "divi/button", "action": "updated", "label": "Hero – Button" }], "outline": "…betroffener Abschnitt…", "rev": "a1b2c3", "tree_rev": "d4e5f6", "warnings": ["Feste Farbe #ff0000 – Variable 'Primär' ist ähnlich"], "revision_id": 812, "snapshot_id": null, "log_id": 4711, "preview_url": "…", "edit_url": "…&et_fb=1" } ``` Rückgabe als `structuredContent` plus kurze Text-Zusammenfassung. Listen immer mit `cursor`/`limit`. ### 8.2 Fehler - Fachliche Fehler → Tool-Ergebnis mit `isError: true` und `{ code, message, hint, fields? }`. Codes: `rev_mismatch`, `invalid_attr_path`, `validation_failed`, `forbidden`, `not_found`, `in_use`, `confirm_required`, `unsupported`. - Alles oder nichts pro Aufruf; Stapel-Tools melden Ergebnis pro Eintrag. - Ausnahmen aus WordPress/Divi werden abgefangen, protokolliert (PHP-Error-Log) und neutral gemeldet (kein Stacktrace an den Client). ### 8.3 Änderungsprotokoll - Tabelle `{prefix}lit_mcp_log`: `id`, `created_at`, `user_id`, `client` (Name aus OAuth), `ability`, `object_type`, `object_id`, `summary`, `revision_id`, `snapshot_id`, `result`. - Keine Inhalte, nur Verweise. - Aufbewahrung einstellbar (Standard 90 Tage), täglicher WP-Cron-Job, Button „Protokoll leeren“. - Admin-Ansicht (`WP_List_Table`), filterbar, Links zu Revision/Wiederherstellen. ### 8.4 Einstellungsseite (Einstellungen → LIT MCP) - **Verbindung:** Status Adapter/OAuth, MCP-Server-URL zum Kopieren, Site-Health-Test (Discovery-Dokumente erreichbar, 401 mit `WWW-Authenticate`). - **Zugriff:** erlaubte Rollen (Standard: Administrator); aktive Verbindungen je Benutzer mit Widerruf (über die von mcp-oauth erzeugten Application Passwords). - **Tools:** direkt / indirekt / deaktiviert je Ability. (Das Divi-Code-Modul ist immer erlaubt, nur nachrangig – keine Einstellung.) - **Limits:** Upload-Größe, Protokoll-Aufbewahrung, Anzahl Snapshots. - Umsetzung mit Settings API, ohne JS-Framework. ## 9. Anleitungen für Claude ### 9.1 Server-Instructions Dynamisch pro Seite erzeugt (Server-Beschreibung → `instructions`), ca. 15 Zeilen: - aktive Integrationen und Post-Typen, - Kernregeln: vor dem Schreiben `lit/divi-outline` und `lit/divi-design-system` lesen; Variablen/Presets vor festen Werten; native Module vor Code-Modul; Status nie ändern ohne ausdrücklichen Wunsch; immer `rev` (bei Divi-Änderungen `tree_rev`) mitgeben, - Verweis auf `lit/guide`. ### 9.2 `lit/guide(topic)` Direktes Tool; Anleitungen als Markdown in `docs/guides/`, mit dem Plugin versioniert, per Filter `lit_mcp_guides` erweiterbar. Themen: `overview`, `divi-structure`, `divi-shortform`, `divi-attrs`, `divi-placeholders`, `divi-design-system`, `theme-builder`, `content-types`, `workflows`. ### 9.3 MCP-Prompts `corporate-design-uebernehmen`, `neue-website-aufsetzen`, `seite-pruefen`, `globale-module-vorschlagen`, `custom-post-type-vorlage`. ## 10. Sicherheit - OAuth 2.1 mit PKCE über mcp-oauth; Tokens an den MCP-Server gebunden; kein Token-Passthrough an Dritte. - Rollen-Gate + Rechteprüfung pro Ability (§4.5). - App-Password-Scope auf die MCP-Route beschränkt (§4.2). - Whitelists für WP-Einstellungen und Divi-Theme-Optionen. - Uploads: `wp_safe_remote_get`, MIME-Whitelist, Größenlimits. - Destruktive Aktionen: `confirm: true` erforderlich; kein endgültiges Löschen von Posts. - Eingaben werden gegen JSON Schema und fachlich validiert; Bereinigung von Divi-Schreibwerten siehe §5.6/D7 (eine Quelle der Wahrheit): je Feldtyp (`sanitize_text_field`/`wp_kses_post`/`esc_url_raw`, URLs geroutet über Katalog-Metadaten bzw. Schlüsselname), `$variable(...)$`-Werte geparst/geprüft/neu serialisiert, sonst `validation_failed`. - HTTPS erforderlich (Hinweis im Admin, wenn nicht aktiv). ## 11. MCP-Konformität Referenz: https://modelcontextprotocol.io/specification ### 11.1 Zielversion - **Sofort:** Protokollversion **2025-11-25** (vom Adapter unterstützt). - **Später:** **2026-07-28** (zustandslos, `server/discover`, CIMD bevorzugt), sobald der Adapter sie unterstützt. Der Umstieg ist ein eigenes Arbeitspaket. ### 11.2 Verantwortung | Bereich | Zuständig | Sicherung | |---|---|---| | JSON-RPC, Transport (Streamable HTTP), Versionsverhandlung, Header, Origin-Prüfung | MCP Adapter | Versionen fixiert, Konformitätstest pro Update | | Autorisierung: OAuth 2.1, PKCE, RFC 9728/8414-Discovery, CIMD, Audience-Bindung | mcp-oauth | Etappe 0 prüft u. a. `WWW-Authenticate` bei 401, `resource`-Parameter (RFC 8707), `iss` (RFC 9207); Lücken upstream melden oder per Filter ergänzen | | Tools, Prompts, Ergebnisse | WP-LIT-MCP | §11.3 | ### 11.3 Anforderungen an WP-LIT-MCP - `inputSchema` für jedes Tool, `outputSchema` wo strukturiert (JSON Schema 2020-12); Ergebnisse als `structuredContent` + Text. - Fachliche Fehler als `isError: true`, Protokollfehler als JSON-RPC-Fehler. - Annotations korrekt: `readOnlyHint` (Lese-Tools), `destructiveHint` (Löschen, Ersetzen, Austausch), `idempotentHint`. - Zustandslos: kein serverseitiger Sitzungszustand; `rev`/`tree_rev` als explizite, servererzeugte Handles in Tool-Argumenten. - Deterministische Reihenfolge der Tool-Liste. - Cursor-Paginierung für Listen. - Tool-Namen spezifikationskonform und eindeutig (`lit-…`). - Bestätigungen vorerst über `confirm: true`; Multi-Round-Trip-Elicitation erst, wenn Adapter und claude.ai sie unterstützen. ### 11.4 Konformitätstests - MCP Inspector gegen den Server (Etappe 0 und bei jedem Update von Adapter/mcp-oauth). - Automatischer Test je Ability: Ergebnis gegen `outputSchema` validiert. - Ende-zu-Ende-Test mit echtem claude.ai-Connector. ## 12. Etappen | Etappe | Inhalt | Ergebnis | |---|---|---| | **0 – Anbindung testen** | Plugin-Gerüst, Composer, mcp-oauth + Adapter, Rollen-Gate, App-Password-Scope-Filter, eigener Server mit direkten Tools, `lit/guide` (overview), ein Test-Tool; claude.ai-Connector über `ddev share`/Staging; MCP Inspector; Test: The Events Calendar-Eintrag generisch anlegen | Entscheidung: mcp-oauth bleibt oder Wechsel zu mcp-connect; Events-Erweiterungspunkt nötig ja/nein | | **1 – WordPress-Basis** | Schema-Erkennung inkl. Pods, Content-Tools, Status/Kopie/Austausch, Revisionen, Medien, Menüs, WP-Einstellungen, `ToolResult`, Protokoll, Einstellungsseite | Seiten/Beiträge/Pods-Einträge pflegen, Medien verwalten, Websites mit Struktur und Menü aufsetzen | | **2 – Divi-Seiten** | BlockTree, Katalog, Kurz-/Vollform, Platzhalter, Outline/Insert/Update/Move/Delete/Duplicate/Replace, Warnungen, `page-render-summary`, Divi-Guides (umgesetzt in 2a: lesen, 2b: schreiben) | Divi-Seiten mit Claude bauen und pflegen | | **3 – Library & Theme Builder** | Library-Tools, Node-Copy, Make-Global, Find-Similar, Theme-Builder-Tools, Dynamic Content | CPT-Vorlagen bauen, globale Module einführen | | **4 – Designsystem** | Farben, Variablen, Presets, Theme-Optionen inkl. SEO, Snapshots, Prompts | Corporate Design in einem Rutsch übernehmen | | **U – Auslieferung & Updates** (nach Etappe 1) | **OFFEN – bewusst noch nicht spezifiziert.** Bekannt: Build mit `composer install --no-dev` (~3,3 MB vendor), Updates nur anzeigen (manueller Klick), `plugin-update-checker`; Hosting (Gitea / GitHub / eigene Subdomain mit `update.json`) und Signaturprüfung werden später entschieden | – | Kann-Kriterien nach Etappe 4 oder bei freier Kapazität. ## 13. Tests - **Unit (PHPUnit, Brain Monkey, Mockery):** BlockTree (Roundtrip-Invariante), Kurzform → Markup, Attributpfad-Validierung, Platzhalter, Schema-Merge, Whitelists, ToolResult. - **Fixtures:** echte, im Divi Builder gebaute Seiten (inkl. globaler Module, Presets, Variablen, Dynamic Content) als Roundtrip- und Änderungs-Testdaten. - **Integration (DDEV, WP-CLI/REST):** jede Ability gegen die lokale Installation; gerenderte Ausgabe enthält `et_pb_*`-Klassen. - **Konformität:** §11.4. - **Manuelle Abnahme pro Etappe:** Bearbeitbarkeit im Visual Builder, claude.ai-Ablauf. - Qualitätswerkzeuge: phpcs (WPCS), PHPCompatibilityWP. ## 14. Risiken | Risiko | Gegenmaßnahme | |---|---| | mcp-oauth jung, Lücken (Rollen, Scope, direkte Tools) | eigene Absicherungen (§4.2), Etappe 0 als Entscheidungspunkt, Rückfall mcp-connect | | Adapter 0.7 bricht API, rät vom Bundling ab | Versionen fixieren, Konformitätstest, Umstieg geplant | | Divi ändert Speicherformat | Divi-eigene Metadaten/Funktionen nutzen, Fixtures, Tests je Divi-Update, `builderVersion` setzen | | `.well-known`/POST auf `/wp-json/` durch Hoster/WAF blockiert | Site-Health-Test, Fehlersuche-Doku | | Design-Qualität neuer Abschnitte ohne Vorlagen | Library-first-Arbeitsweise, Designsystem-Platzhalter, Guides, Warnungen | | Parallele Bearbeitung im Builder | `tree_rev`-Sperre | | Datenformate Designsystem nur aus Code abgeleitet (lokal keine Daten) | vor Etappe 4 echte Daten im Builder anlegen und als Fixtures sichern | ## 15. Offene Punkte (in Etappen zu klären) - Etappe 0: Funktioniert der Workaround für direkte Tools mit mcp-oauth stabil? Erfüllt mcp-oauth `iss`/`resource`-Anforderungen? - Etappe 0: Erscheinen generisch angelegte The Events Calendar-Einträge korrekt? - Etappe 2: erledigt – Kurzform-Felder aus Divis Conversion-Outlines abgeleitet (`ShortformMap`), gegen den Live-Katalog geprüft (`tests/Integration/divi-shortform-check.php`), dokumentiert im Guide `divi-shortform`. - Etappe 4: Format der Presets/Variablen an echten Daten verifizieren.