Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
13 KiB
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
-
Guide reading is thorough but not consolidated.
lit-guideoverview 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 separatelit-guidecalls. 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. -
Contact-form field
typecollision (real friction, not just reading fatigue). Thedivi-shortformfield table listscontact-field's shortform fields astitle, id, type, required— but a paragraph below the table saystypecan't actually be set this way at insert time because it collides with the node-schema keytype(the module type). I read the table, usedtype: "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 parsetypeas 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 omittingtypeon insert and setting it afterwards withlit-divi-update'sset(which is documented and worked first try). Suggestion: detect this specific case (acontact-field/social-media-follow-networkitem with atype/labelkey that isn't a valid child module name) and return a dedicated hint, e.g. "typeon 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)." -
A section can't mix
rowsandmodules. Tried a section with a top-levelmodules(for a heading) androws(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. -
No shortform way to link one page to another by ID. Draft pages get an empty
post_nameuntil 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'surlfield 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 therelated/attachment-ID idiom already used for images) that resolves throughget_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. -
contact-form's own title has no shortform heading-level control. After building the Kontakt page,lit-page-render-summaryflagged"2 Überschriften der Ebene h1 im Inhalt."— the contact-form module renders itstitleas a hard-codedh1, and unlikeheading/blurb(which both expose alevelshortform field),contact-formhas none. Fixed by falling back to the full form:lit-divi-catalogwithmodule: "divi/contact-form"to find the path, thenattrs: {"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: addleveltocontact-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. -
preview_urluseshttp://,edit_urluseshttps://, 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. -
Positive: error messages throughout were excellent.
validation_failedalways came with afieldsmap keyed by the exact dotted input path (e.g.divi[1].rows[0].modules[1][0].items[0].type);rev_mismatch,confirm_required, andunsupported(tried to overwrite a Divi page'scontentvialit-content-update) all had ahintthat 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. -
Positive:
tree_revchaining removed round trips. Every Divi write response carries the freshtree_rev, so a sequence of edits on the same page (change heading → move a module → insert a section) never needed an extralit-divi-outlineread 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. -
lit/menu-createacceptinglocationin the same call was a nice shortcut (no separatelit/menu-assign-locationround trip needed for a fresh menu). The one remaining unavoidable extra round trip in the menu flow was callinglit/menu-getimmediately afterlit/menu-createjust to obtainmenu_revfor the followinglit/menu-set-items—lit/menu-create's own response could include the initialmenu_revand save that call. -
lit-divi-catalog's result envelope ({modules: [...], notes: [...]}) isn't shown anywhere in the tool description or thedivi-attrs/divi-shortformguides (which do embed inline JSON examples for almost everything else). Self-inflicted (my firstjqfilter 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
- (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=Nis the only fallback. - (High) Give the
contact-formmodule's shortform alevelfield (matchingheading/blurb), and audit other title-bearing modules (cta,map,slider, …) for the same missing control — this is exactly the kind of heading-hierarchy mistakelit-page-render-summaryis built to catch, but the shortform currently can't fix it without discovering a full-form attrs path. - (Medium) Fix the
http://vshttps://scheme mismatch betweenpreview_urlandedit_urlin write-tool responses (see Bugs). - (Medium) When a shortform field name collides with a node-schema key (
typeon contact-field items,labelon social-media-follow-network items — both already called out in prose in thedivi-shortformguide), have the resultingvalidation_failederror 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. - (Low) Let
lit/menu-create's response include the new menu's initialmenu_rev, so a first-timelit/menu-set-itemsdoesn't need a precedinglit/menu-getpurely to fetch it. - (Low) Show a one-line example of
lit-divi-catalog's result shape (module list vs. single-module detail) in its tool description or thedivi-attrsguide, consistent with how other tools' guides already embed inline JSON examples. - (Nice-to-have) Consider a
lit-guidemode 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-createfor a page, or anylit-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 correctlyhttps. - Impact: a client that opens
preview_urlas 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-testapplication passwords created by repeatedconnect()calls during this trial were removed viacleanup_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.