# 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=` 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:}}` (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:}}`. 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.