Files
WP-LIT-MCP/docs/superpowers/notes/2026-09-26-etappe-2b-praxistest.md
2026-09-26 22:18:23 +02:00

13 KiB
Raw Permalink Blame History

WP-LIT-MCP Trial: „Tischlerei Holzwerk Berger“

Hands-on test of the LIT MCP server as a real MCP client would use it (initialize → tools/list → lit-guide → build), against the local DDEV site https://wordpress.ddev.site:8443 (Divi 5.2.1, WordPress 7.1.2, Pods inactive). Site was "Breva Map Dev" before this trial. All calls went through tests/Integration/lib.sh's connect/tool/ability helpers, run inside the DDEV web container via throwaway scripts under .superpowers/trial/ (deleted at the end; git-excluded). Nothing published.

What was built

All titled with the [Test] prefix, all left as drafts, as requested.

Type ID Title Notes
Page 839 [Test] Startseite Hero (heading+text+button+image), 3-Leistungen-Übersicht (blurbs), Kontakt-CTA
Page 834 [Test] Leistungen Hero, 3 service blurbs, CTA section
Page 837 [Test] Über uns Hero, Geschichte (image+text), 3 Werte (icon-lists; one duplicated to a 4th value)
Page 831 [Test] Kontakt Hero, Adresse+Kontaktformular, Öffnungszeiten (added afterwards via lit-divi-insert)
Post 854 [Test] Drei Tipps zur Pflege von Massivholzmöbeln
Post 856 [Test] Einblick in unsere Werkstatt text+image
Post 858 [Test] Nachhaltigkeit beginnt beim Holz
Menu 22 [Test] Hauptmenü assigned to primary-menu location in the same lit/menu-create call; 4 items (Startseite, Leistungen, Über uns, Kontakt) via lit/menu-set-items with allow_unpublished: true
Media 828, 829, 830 Werkstatt / Team / Massivholzmöbel (Platzhalter) imported via lit-media-upload-from-url from picsum.photos (public hotlink-friendly placeholder service — network egress from the container worked fine, no fallback to base64 needed)
Site settings – blogname → "Tischlerei Holzwerk Berger", blogdescription → "Massivholzmöbel, Innenausbau und Restaurierung aus Berlin" previous values (Breva Map Dev / empty) are in the tool's own previous response field if this needs reverting

Front page: not set. lit/wp-settings-update correctly refused page_on_front: 839 with "839 ist keine veröffentlichte Seite." — consistent with the server's own "Neue Website aufsetzen" workflow guide, which says to publish the homepage first. That step is fundamentally at odds with "don't publish anything," so I left show_on_front on posts and flagged it here instead of guessing which instruction should win.

Edits demonstrated with the Divi write tools (all on top of the pages above): a heading text change (lit-divi-update/set), a whole new section inserted (lit-divi-insert), a module moved across columns (lit-divi-move), a node duplicated and re-labelled (lit/divi-duplicate-node), and a site-wide text fix via lit/divi-replace-text with a dry run first, then a confirmed run (see friction log for what it was replacing).

Chronological friction log

  1. Guide reading is thorough but not consolidated. lit-guide overview lists 8 further topics (content-types, divi-attrs, divi-design-system, divi-placeholders, divi-shortform, divi-structure, media, workflows); getting the full picture before writing anything took 8 separate lit-guide calls. The content itself is excellent (dense, example-driven, in German matching the server's own error/hint language) — no complaints about quality, only that there's no single "give me everything" call for a first-time client that wants to front-load context once rather than discover topics interactively.

  2. Contact-form field type collision (real friction, not just reading fatigue). The divi-shortform field table lists contact-field's shortform fields as title, id, type, required — but a paragraph below the table says type can't actually be set this way at insert time because it collides with the node-schema key type (the module type). I read the table, used type: "email" in a contact-field item, and got: "unbekanntes Modul \"divi/input\"" / "divi/contact-form erlaubt nur divi/contact-field als Kind". The error is technically correct (it really did try to parse type as a child module name) but it doesn't say why — a reader has no way to connect "unknown module divi/input" back to the already-read caveat about reserved field names. Fixed by omitting type on insert and setting it afterwards with lit-divi-update's set (which is documented and worked first try). Suggestion: detect this specific case (a contact-field/social-media-follow-network item with a type/label key that isn't a valid child module name) and return a dedicated hint, e.g. "type on a contact field can't be set at insert — omit it here and set it afterwards with lit-divi-update, or use attrs (fieldItem.advanced.type)."

  3. A section can't mix rows and modules. Tried a section with a top-level modules (for a heading) and rows (for the 3-column blurbs) — got "divi[1]": "entweder rows oder modules angeben". Fully actionable, fixed in one edit by wrapping the heading in its own single-column row. Minor cost (one extra round trip), good error.

  4. No shortform way to link one page to another by ID. Draft pages get an empty post_name until published (confirmed via direct DB read — this is normal WordPress behaviour for draft/pending posts, not a plugin bug), so there's no stable pretty permalink to put in a button's url field yet. The placeholder table (divi-placeholders) only offers {{post:url}} etc. for the currently displayed post, not a way to point at an arbitrary other post/page by ID. I fell back to raw /?page_id=<ID> query links for the CTA/blurb/menu targets. That works for an admin/preview session but is fragile (changes once published) and dead for anonymous visitors before publish. Suggestion: a placeholder like {{link:<post_id>}} (or reusing the related/attachment-ID idiom already used for images) that resolves through get_permalink() at render/save time — draft-safe now, automatically correct after publishing. This would remove the single biggest gap between the shortform and how a real multi-page site actually gets built.

  5. contact-form's own title has no shortform heading-level control. After building the Kontakt page, lit-page-render-summary flagged "2 Überschriften der Ebene h1 im Inhalt." — the contact-form module renders its title as a hard-coded h1, and unlike heading/blurb (which both expose a level shortform field), contact-form has none. Fixed by falling back to the full form: lit-divi-catalog with module: "divi/contact-form" to find the path, then attrs: {"title.decoration.font.font": {"desktop": {"value": {"headingLevel": "h2"}}}} — which worked and cleared the warning. This was the one case where the shortform genuinely wasn't expressive enough for a normal homepage pattern (a contact form title next to a page's own h1). Suggestion: add level to contact-form's shortform fields (and check other title-bearing modules — e.g. cta, map, slider — for the same gap) so this doesn't require discovering the full-form path by trial and error.

  6. preview_url uses http://, edit_url uses https://, in the same response — bug. Every mutating tool response on this (https-only, port-8443) site shows this mismatch, e.g. the Kontakt page creation returned "preview_url":"http://wordpress.ddev.site:8443/?page_id=831&preview=true" next to "edit_url":"https://wordpress.ddev.site:8443/wp-admin/post.php?post=831&action=edit". See Bugs below for repro.

  7. Positive: error messages throughout were excellent. validation_failed always came with a fields map keyed by the exact dotted input path (e.g. divi[1].rows[0].modules[1][0].items[0].type); rev_mismatch, confirm_required, and unsupported (tried to overwrite a Divi page's content via lit-content-update) all had a hint that named the exact next tool to call, and following it worked first try every time — no case where the hint was misleading or where I had to guess.

  8. Positive: tree_rev chaining removed round trips. Every Divi write response carries the fresh tree_rev, so a sequence of edits on the same page (change heading → move a module → insert a section) never needed an extra lit-divi-outline read in between. This is the detail I'd worry the most about regressing — it's what makes multi-step page building on Divi tolerable turn-count-wise.

  9. lit/menu-create accepting location in the same call was a nice shortcut (no separate lit/menu-assign-location round trip needed for a fresh menu). The one remaining unavoidable extra round trip in the menu flow was calling lit/menu-get immediately after lit/menu-create just to obtain menu_rev for the following lit/menu-set-items — lit/menu-create's own response could include the initial menu_rev and save that call.

  10. lit-divi-catalog's result envelope ({modules: [...], notes: [...]}) isn't shown anywhere in the tool description or the divi-attrs/divi-shortform guides (which do embed inline JSON examples for almost everything else). Self-inflicted (my first jq filter assumed a bare array and errored), but a one-line example would remove the ambiguity the same way the other guides do.

Prioritized improvement suggestions

  1. (High) Add an internal-link placeholder for Divi shortform/full-form URL fields that resolves an arbitrary post/page ID to its current permalink (draft-safe), e.g. {{link:<post_id>}}. This is the most concrete gap: right now there is no supported way to cross-link draft pages that survives publishing, and /?page_id=N is the only fallback.
  2. (High) Give the contact-form module's shortform a level field (matching heading/blurb), and audit other title-bearing modules (cta, map, slider, …) for the same missing control — this is exactly the kind of heading-hierarchy mistake lit-page-render-summary is built to catch, but the shortform currently can't fix it without discovering a full-form attrs path.
  3. (Medium) Fix the http:// vs https:// scheme mismatch between preview_url and edit_url in write-tool responses (see Bugs).
  4. (Medium) When a shortform field name collides with a node-schema key (type on contact-field items, label on social-media-follow-network items — both already called out in prose in the divi-shortform guide), have the resulting validation_failed error say so directly instead of surfacing as "unknown module divi/". The current message is technically accurate but doesn't point back to the documented workaround.
  5. (Low) Let lit/menu-create's response include the new menu's initial menu_rev, so a first-time lit/menu-set-items doesn't need a preceding lit/menu-get purely to fetch it.
  6. (Low) Show a one-line example of lit-divi-catalog's result shape (module list vs. single-module detail) in its tool description or the divi-attrs guide, consistent with how other tools' guides already embed inline JSON examples.
  7. (Nice-to-have) Consider a lit-guide mode that returns all topics concatenated in one call for first-connection priming, alongside the existing per-topic calls (which remain useful for targeted lookups later in a session).

Bugs (with repro)

Bug: preview_url scheme mismatch (http:// vs. the site's actual https://).

  • Repro: on this DDEV site (https://wordpress.ddev.site:8443, HTTPS-only), call any tool that returns both URLs for a draft, e.g. lit-content-create for a page, or any lit-divi-* write. Example (Kontakt page, ID 831): response includes "preview_url":"http://wordpress.ddev.site:8443/?page_id=831&preview=true" while the same response's "edit_url":"https://wordpress.ddev.site:8443/wp-admin/post.php?post=831&action=edit" is correctly https.
  • Impact: a client that opens preview_url as given may hit a mixed-content warning, an unwanted http→https redirect, or fail outright depending on the site's HSTS/redirect configuration.

Divi shortform expressiveness verdict

For a typical small-business homepage (hero, services grid, testimonials/values, contact form, CTA, blog teaser text) the shortform covered essentially everything needed — section/row/column nesting, heading, text, button, image, blurb, cta, icon-list, contact-form, placeholders for the design system's colors — with only two genuine full-form fallbacks in this whole build: the contact-form title heading level (§5 above), and (not really a fallback, just a two-step shortform sequence) setting a contact-field's type after insert instead of at insert time. Column-width changes, presets, and $variable placeholders were never needed for this content but are documented clearly enough that I'd expect them to work the same way.

Cleanup performed

  • All 36 throwaway lit-mcp-integration-test application passwords created by repeated connect() calls during this trial were removed via cleanup_app_passwords_for (verified count 36 → 0).
  • .superpowers/trial/ (the scratch scripts used to drive this session) was deleted from the container.
  • No plugin source code was modified. No existing content (the 4 pre-existing pages, 1 existing post) was touched. Nothing was published.