@wootsup/yt-builder-mcp 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. package/README.md +15 -11
  2. package/dist/catalog/build-catalog.d.ts +63 -0
  3. package/dist/catalog/build-catalog.d.ts.map +1 -0
  4. package/dist/catalog/build-catalog.js +166 -0
  5. package/dist/catalog/build-catalog.js.map +1 -0
  6. package/dist/gateway/advanced-read-tool.d.ts +37 -0
  7. package/dist/gateway/advanced-read-tool.d.ts.map +1 -0
  8. package/dist/gateway/advanced-read-tool.js +156 -0
  9. package/dist/gateway/advanced-read-tool.js.map +1 -0
  10. package/dist/gateway/advanced-tool/domains.d.ts +18 -3
  11. package/dist/gateway/advanced-tool/domains.d.ts.map +1 -1
  12. package/dist/gateway/advanced-tool/domains.js +28 -9
  13. package/dist/gateway/advanced-tool/domains.js.map +1 -1
  14. package/dist/gateway/advanced-tool/register.d.ts.map +1 -1
  15. package/dist/gateway/advanced-tool/register.js +43 -11
  16. package/dist/gateway/advanced-tool/register.js.map +1 -1
  17. package/dist/gateway/essentials.d.ts +14 -4
  18. package/dist/gateway/essentials.d.ts.map +1 -1
  19. package/dist/gateway/essentials.js +41 -5
  20. package/dist/gateway/essentials.js.map +1 -1
  21. package/dist/gateway/test-support.d.ts +2 -2
  22. package/dist/gateway/test-support.js +2 -2
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +10 -0
  25. package/dist/index.js.map +1 -1
  26. package/dist/install-skill.js +1 -1
  27. package/dist/proxy/bridge.d.ts +36 -0
  28. package/dist/proxy/bridge.d.ts.map +1 -0
  29. package/dist/proxy/bridge.js +129 -0
  30. package/dist/proxy/bridge.js.map +1 -0
  31. package/dist/proxy/mode.d.ts +10 -0
  32. package/dist/proxy/mode.d.ts.map +1 -0
  33. package/dist/proxy/mode.js +20 -0
  34. package/dist/proxy/mode.js.map +1 -0
  35. package/dist/server.d.ts +5 -3
  36. package/dist/server.d.ts.map +1 -1
  37. package/dist/server.js +13 -3
  38. package/dist/server.js.map +1 -1
  39. package/dist/setup-wizard.d.ts.map +1 -1
  40. package/dist/setup-wizard.js +7 -0
  41. package/dist/setup-wizard.js.map +1 -1
  42. package/dist/sites/client-pool.d.ts.map +1 -1
  43. package/dist/sites/client-pool.js +21 -3
  44. package/dist/sites/client-pool.js.map +1 -1
  45. package/dist/sites/registry.d.ts +30 -0
  46. package/dist/sites/registry.d.ts.map +1 -1
  47. package/dist/sites/registry.js.map +1 -1
  48. package/dist/sites/store.d.ts +8 -1
  49. package/dist/sites/store.d.ts.map +1 -1
  50. package/dist/sites/store.js +17 -2
  51. package/dist/sites/store.js.map +1 -1
  52. package/dist/sites/tools/use-site.d.ts.map +1 -1
  53. package/dist/sites/tools/use-site.js +26 -6
  54. package/dist/sites/tools/use-site.js.map +1 -1
  55. package/dist/tools/bind-guidance.d.ts +80 -0
  56. package/dist/tools/bind-guidance.d.ts.map +1 -0
  57. package/dist/tools/bind-guidance.js +95 -0
  58. package/dist/tools/bind-guidance.js.map +1 -0
  59. package/dist/tools/elements/builders.d.ts.map +1 -1
  60. package/dist/tools/elements/builders.js +59 -11
  61. package/dist/tools/elements/builders.js.map +1 -1
  62. package/dist/tools/elements/handlers-write.d.ts +19 -2
  63. package/dist/tools/elements/handlers-write.d.ts.map +1 -1
  64. package/dist/tools/elements/handlers-write.js +179 -10
  65. package/dist/tools/elements/handlers-write.js.map +1 -1
  66. package/dist/tools/elements/handlers.d.ts +6 -1
  67. package/dist/tools/elements/handlers.d.ts.map +1 -1
  68. package/dist/tools/elements/handlers.js +74 -7
  69. package/dist/tools/elements/handlers.js.map +1 -1
  70. package/dist/tools/elements/layout-hierarchy-rules.d.ts +62 -0
  71. package/dist/tools/elements/layout-hierarchy-rules.d.ts.map +1 -0
  72. package/dist/tools/elements/layout-hierarchy-rules.js +154 -0
  73. package/dist/tools/elements/layout-hierarchy-rules.js.map +1 -0
  74. package/dist/tools/format/elements-format.d.ts +35 -0
  75. package/dist/tools/format/elements-format.d.ts.map +1 -1
  76. package/dist/tools/format/elements-format.js +124 -1
  77. package/dist/tools/format/elements-format.js.map +1 -1
  78. package/dist/tools/format/inspection-format.d.ts +18 -0
  79. package/dist/tools/format/inspection-format.d.ts.map +1 -1
  80. package/dist/tools/format/inspection-format.js +22 -1
  81. package/dist/tools/format/inspection-format.js.map +1 -1
  82. package/dist/tools/format/pages-format.d.ts.map +1 -1
  83. package/dist/tools/format/pages-format.js +7 -0
  84. package/dist/tools/format/pages-format.js.map +1 -1
  85. package/dist/tools/format/sources-format.d.ts +8 -0
  86. package/dist/tools/format/sources-format.d.ts.map +1 -1
  87. package/dist/tools/format/sources-format.js +10 -0
  88. package/dist/tools/format/sources-format.js.map +1 -1
  89. package/dist/tools/health.d.ts.map +1 -1
  90. package/dist/tools/health.js +24 -0
  91. package/dist/tools/health.js.map +1 -1
  92. package/dist/tools/index.d.ts.map +1 -1
  93. package/dist/tools/index.js +4 -0
  94. package/dist/tools/index.js.map +1 -1
  95. package/dist/tools/inspection.d.ts +24 -0
  96. package/dist/tools/inspection.d.ts.map +1 -1
  97. package/dist/tools/inspection.js +140 -41
  98. package/dist/tools/inspection.js.map +1 -1
  99. package/dist/tools/layout-flatten.d.ts +11 -8
  100. package/dist/tools/layout-flatten.d.ts.map +1 -1
  101. package/dist/tools/layout-flatten.js +17 -6
  102. package/dist/tools/layout-flatten.js.map +1 -1
  103. package/dist/tools/multi-items/builders.d.ts.map +1 -1
  104. package/dist/tools/multi-items/builders.js +11 -2
  105. package/dist/tools/multi-items/builders.js.map +1 -1
  106. package/dist/tools/multi-items/inspect-handler.d.ts +13 -0
  107. package/dist/tools/multi-items/inspect-handler.d.ts.map +1 -1
  108. package/dist/tools/multi-items/inspect-handler.js +147 -3
  109. package/dist/tools/multi-items/inspect-handler.js.map +1 -1
  110. package/dist/tools/pages/builders.d.ts.map +1 -1
  111. package/dist/tools/pages/builders.js +88 -25
  112. package/dist/tools/pages/builders.js.map +1 -1
  113. package/dist/tools/pages/handlers-read.d.ts +5 -1
  114. package/dist/tools/pages/handlers-read.d.ts.map +1 -1
  115. package/dist/tools/pages/handlers-read.js +192 -47
  116. package/dist/tools/pages/handlers-read.js.map +1 -1
  117. package/dist/tools/pages/handlers-write.d.ts +95 -1
  118. package/dist/tools/pages/handlers-write.d.ts.map +1 -1
  119. package/dist/tools/pages/handlers-write.js +137 -8
  120. package/dist/tools/pages/handlers-write.js.map +1 -1
  121. package/dist/tools/pages/index.d.ts +1 -1
  122. package/dist/tools/pages/index.d.ts.map +1 -1
  123. package/dist/tools/pages/index.js +1 -1
  124. package/dist/tools/pages/index.js.map +1 -1
  125. package/dist/tools/pages/schemas.d.ts +54 -0
  126. package/dist/tools/pages/schemas.d.ts.map +1 -1
  127. package/dist/tools/pages/schemas.js +199 -2
  128. package/dist/tools/pages/schemas.js.map +1 -1
  129. package/dist/tools/shared-schemas.d.ts.map +1 -1
  130. package/dist/tools/shared-schemas.js +15 -13
  131. package/dist/tools/shared-schemas.js.map +1 -1
  132. package/dist/tools/sources/builders.d.ts.map +1 -1
  133. package/dist/tools/sources/builders.js +64 -6
  134. package/dist/tools/sources/builders.js.map +1 -1
  135. package/dist/tools/sources/handlers-bind.d.ts +13 -1
  136. package/dist/tools/sources/handlers-bind.d.ts.map +1 -1
  137. package/dist/tools/sources/handlers-bind.js +163 -1
  138. package/dist/tools/sources/handlers-bind.js.map +1 -1
  139. package/dist/tools/sources/handlers.d.ts +3 -0
  140. package/dist/tools/sources/handlers.d.ts.map +1 -1
  141. package/dist/tools/sources/handlers.js +43 -6
  142. package/dist/tools/sources/handlers.js.map +1 -1
  143. package/dist/tools/sparse-fields.d.ts +23 -0
  144. package/dist/tools/sparse-fields.d.ts.map +1 -1
  145. package/dist/tools/sparse-fields.js +29 -0
  146. package/dist/tools/sparse-fields.js.map +1 -1
  147. package/dist/tools/sublayout/builders.d.ts +23 -0
  148. package/dist/tools/sublayout/builders.d.ts.map +1 -0
  149. package/dist/tools/sublayout/builders.js +54 -0
  150. package/dist/tools/sublayout/builders.js.map +1 -0
  151. package/dist/tools/sublayout/index.d.ts +13 -0
  152. package/dist/tools/sublayout/index.d.ts.map +1 -0
  153. package/dist/tools/sublayout/index.js +13 -0
  154. package/dist/tools/sublayout/index.js.map +1 -0
  155. package/dist/tools/sublayout/inspect-sublayout-handler.d.ts +95 -0
  156. package/dist/tools/sublayout/inspect-sublayout-handler.d.ts.map +1 -0
  157. package/dist/tools/sublayout/inspect-sublayout-handler.js +181 -0
  158. package/dist/tools/sublayout/inspect-sublayout-handler.js.map +1 -0
  159. package/dist/tools/tool-builder/results.d.ts +31 -0
  160. package/dist/tools/tool-builder/results.d.ts.map +1 -1
  161. package/dist/tools/tool-builder/results.js +95 -4
  162. package/dist/tools/tool-builder/results.js.map +1 -1
  163. package/manifest.json +1 -1
  164. package/package.json +4 -2
  165. package/skills/yt-builder-mcp/SKILL.md +146 -81
@@ -12,12 +12,17 @@ description: Drive the YOOtheme Pro Page Builder on WordPress or Joomla 5/6. Dis
12
12
  > WordPress and Joomla 5/6.
13
13
 
14
14
  This skill helps AI assistants drive the YOOtheme Pro Page Builder through the
15
- `@wootsup/yt-builder-mcp` server. The server exposes 30 typed, scoped, idempotent
16
- callable tools. 23 of them advertised as first-class entries in `tools/list`
17
- (20 essential L1 forwards + 2 direct L3 entries + 1 gateway), and 7 advanced
18
- tools reachable through the single `yootheme_builder_advanced` gateway. This
19
- 3-lane split keeps `tools/list` well below the ~40-tool Cursor cap while every
20
- catalogued tool stays fully reachable.
15
+ `@wootsup/yt-builder-mcp` server. The server catalogues 32 typed, scoped,
16
+ idempotent tools (34 callable end-to-end with the two gateways). 29 of them
17
+ advertised as first-class entries in `tools/list`
18
+ (25 essential L1 forwards + 2 direct L3 entries + 2 gateways), and 5 advanced
19
+ tools reachable through the gateways. The write-capable
20
+ `yootheme_builder_advanced` gateway routes all 5; the read-only
21
+ `yootheme_builder_advanced_read` gateway routes only the read-only subset
22
+ (page_get_schema, element_get_binding, inspect_sublayout) and is itself
23
+ read-only-annotated, so MCP hosts can auto-allow pure inspection without a
24
+ per-call write-approval prompt. This 3-lane split keeps `tools/list` well below
25
+ the ~40-tool Cursor cap while every catalogued tool stays fully reachable.
21
26
 
22
27
  ## How to use this MCP server
23
28
 
@@ -48,8 +53,10 @@ Some clients (notably Claude Desktop with the `.dxt` bundle) expose **two**
48
53
  entries when the user types "YT Builder MCP" into the picker:
49
54
 
50
55
  - **`YT Builder MCP for YOOtheme Pro (unofficial)`**: the MCP **server**.
51
- Provides the 23 first-class tools (20 essential, 2 direct, 1 gateway).
52
- The `yootheme_builder_advanced` gateway routes 7 additional tools.
56
+ Provides the 28 first-class tools (24 essential, 2 direct, 2 gateways).
57
+ The `yootheme_builder_advanced` gateway routes all 5 advanced tools; the
58
+ read-only `yootheme_builder_advanced_read` gateway routes the read-only
59
+ subset without a write-approval prompt.
53
60
  - **`Von YT Builder MCP for YOOtheme Pro`**: the bundled **skill** (this
54
61
  document). Gives the agent the workflow knowledge needed to drive those
55
62
  tools correctly on first try.
@@ -74,25 +81,37 @@ The server exposes:
74
81
  - **2 direct top-level tools**, always callable, always in `tools/list`:
75
82
  `yootheme_builder_health` and `yootheme_builder_diagnose`. These are
76
83
  the "the gateway itself might be broken" escape hatch.
77
- - **20 essential forwarded tools**: common reads + the most-used writes
78
- (pages_list, pages_create, pages_delete, get_etag, element_list / add /
79
- update_settings / get / move / clone / delete, page_get_layout,
80
- sources_list, element_types_list, element_type_get_schema,
84
+ - **25 essential forwarded tools**: common reads + the most-used writes
85
+ (pages_list, pages_create, pages_delete, page_dynamize, scaffold_section,
86
+ get_etag, element_list / add / update_settings / get / move / clone / delete,
87
+ page_get_layout, sources_list, element_types_list, element_type_get_schema,
81
88
  template_summary, inspect_multi_items_binding, sites_list, sites_test,
82
- use_site). Always advertised in `tools/list` so AI clients see them
83
- first-class.
84
- - **7 advanced captured tools**: everything else (page_save, page_publish,
85
- page_get_schema, element_get_binding, element_bind_source,
86
- element_unbind_source, clean_implode_directives). Reachable through one
87
- gateway tool: `yootheme_builder_advanced({ tool: "<name>", input: { ... } })`.
88
- - **1 gateway tool**: `yootheme_builder_advanced`.
89
-
90
- `tools/list` therefore advertises 23 names (20 + 2 + 1). That's 20 L1
91
- essentials + 2 L3 direct + 1 gateway. The total callable surface is 30
92
- (23 advertised + 7 advanced reachable through the gateway). If the AI
89
+ use_site, and the bind→save→publish chain element_bind_source /
90
+ page_save / page_publish). Always advertised in `tools/list` so AI
91
+ clients see them first-class. `scaffold_section` creates a valid
92
+ section row → column hull in one call — the easiest correct way to
93
+ start a layout block (content placed anywhere else is rejected by the
94
+ structural-hierarchy guard).
95
+ - **5 advanced captured tools**: everything else (page_get_schema,
96
+ element_get_binding, element_unbind_source, clean_implode_directives,
97
+ and `inspect_sublayout`). Reachable through one gateway tool:
98
+ `yootheme_builder_advanced({ tool: "<name>", arguments: { ... } })`. For
99
+ example, to inspect a panel/grid_item `< SUBLAYOUT`:
100
+ `yootheme_builder_advanced({ tool: "yootheme_builder_inspect_sublayout", arguments: { template_id, element_path } })`.
101
+ - **2 gateway tools**: `yootheme_builder_advanced` (write-capable; can route
102
+ into delete/unbind, so hosts gate it) and `yootheme_builder_advanced_read`
103
+ (read-only; routes ONLY the read-only advanced subset — page_get_schema,
104
+ element_get_binding, inspect_sublayout — and is read-only-annotated so hosts
105
+ auto-allow it). Prefer the read gateway for pure inspection:
106
+ `yootheme_builder_advanced_read({ tool: "yootheme_builder_page_get_schema", arguments: { template_id } })`.
107
+
108
+ `tools/list` therefore advertises 29 names (25 + 2 + 2). That's 25 L1
109
+ essentials + 2 L3 direct + 2 gateways. The total callable surface is 34
110
+ (29 advertised + 5 advanced reachable through the gateways). If the AI
93
111
  client reports "tool not found", you are almost certainly calling an
94
112
  advanced tool by its raw name. Wrap it in
95
- `yootheme_builder_advanced({ tool, input })` instead.
113
+ `yootheme_builder_advanced({ tool, arguments })` (or the read gateway for
114
+ read-only tools) instead.
96
115
 
97
116
  ## Site and frontend URLs (for deep-linking and verification)
98
117
 
@@ -282,8 +301,8 @@ one conversation.
282
301
  - `yootheme_builder_pages_list({ site_id: "wp-acme", fields: ["id", "label"] })`
283
302
  - `yootheme_builder_get_etag({ site_id: "wp-acme" })`
284
303
  - `yootheme_builder_element_update_settings({ site_id: "wp-acme", template_id: "home", element_path: "/0/children/0/children/0/children/0", props: { content: "New headline" }, merge: true, etag: "<etag>" })`
285
- - `yootheme_builder_advanced({ tool: "yootheme_builder_page_save", input: { site_id: "wp-acme", template_id: "home", etag: "<fresh>" } })`
286
- - `yootheme_builder_advanced({ tool: "yootheme_builder_page_publish", input: { site_id: "wp-acme", template_id: "home", etag: "<fresh>" } })`
304
+ - `yootheme_builder_page_save({ site_id: "wp-acme", template_id: "home", etag: "<fresh>" })`
305
+ - `yootheme_builder_page_publish({ site_id: "wp-acme", template_id: "home", etag: "<fresh>" })`
287
306
  3. The customer sees a stream of replies, each prefixed with the matching
288
307
  `[label @ host]`, so it is obvious which site is at which step.
289
308
 
@@ -321,11 +340,11 @@ to an existing page.
321
340
  add a text element.
322
341
  8. `yootheme_builder_element_add({ template_id, parent_path: "<row-path>", element_type: "button", props: { content: "<cta>", link: "<url>" }, etag })`:
323
342
  add the CTA button.
324
- 9. `yootheme_builder_advanced({ tool: "yootheme_builder_page_save", input: { template_id, etag } })`:
343
+ 9. `yootheme_builder_page_save({ template_id, etag })`:
325
344
  persist the working copy (visible in YOOtheme Customizer preview).
326
- `page_save` is an advanced tool; call it through the gateway.
327
- 10. `yootheme_builder_advanced({ tool: "yootheme_builder_page_publish", input: { template_id, etag } })`:
328
- make the changes live on the front-end. Also an advanced tool.
345
+ `page_save` is a first-class L1 tool; call it directly.
346
+ 10. `yootheme_builder_page_publish({ template_id, etag })`:
347
+ make the changes live on the front-end. Also a first-class L1 tool.
329
348
 
330
349
  **Common pitfalls:**
331
350
 
@@ -346,9 +365,11 @@ to an existing page.
346
365
  - **Reusing a stale etag across many writes.** Every write returns a
347
366
  fresh etag in the response. Pass THAT etag into the next write.
348
367
  Don't hold the one from the original `get_etag` call.
349
- - **Calling page_save / page_publish by name.** Both are advanced
350
- (L2) tools. Call them through `yootheme_builder_advanced({ tool, input })`,
351
- not directly. The first sign you forgot is "tool not found".
368
+ - **Forgetting to publish.** `page_save` and `page_publish` are both
369
+ first-class L1 tools (call them directly by name they are advertised
370
+ in `tools/list`). Saving stages the change; only `page_publish` makes
371
+ it live. A saved-but-unpublished edit looks "done" in the Customizer
372
+ but visitors still see the old page.
352
373
 
353
374
  **Worked example (tool-call snippet):**
354
375
 
@@ -364,11 +385,8 @@ yootheme_builder_element_add({
364
385
  // Response: { path: "/0/children/3", etag: "def456" }
365
386
  // → next call uses etag "def456"
366
387
 
367
- // Step 9. page_save is L2; call via the gateway.
368
- yootheme_builder_advanced({
369
- tool: "yootheme_builder_page_save",
370
- input: { template_id: "home", etag: "<latest>" }
371
- })
388
+ // Step 9. page_save is a first-class L1 tool; call it directly.
389
+ yootheme_builder_page_save({ template_id: "home", etag: "<latest>" })
372
390
  ```
373
391
 
374
392
  **Edge case:** YOOtheme allows nested sections (rare). If the user
@@ -403,21 +421,21 @@ renders dynamic items.
403
421
  4. `yootheme_builder_sources_list()`: enumerate available Sources.
404
422
  Each returns `{ name, label, origin, kind }`. Pick the one the
405
423
  user asked for.
406
- 5. `yootheme_builder_advanced({ tool: "yootheme_builder_element_get_binding", input: { template_id, element_path } })`
424
+ 5. `yootheme_builder_advanced({ tool: "yootheme_builder_element_get_binding", arguments: { template_id, element_path } })`
407
425
  check whether the Grid is already bound (idempotency: skip step
408
426
  7 if `source_name` already matches the user's intent).
409
427
  `element_get_binding` is an advanced (L2) tool. Call via the gateway.
410
428
  6. `yootheme_builder_get_etag()`: fetch the optimistic-lock etag for
411
429
  the upcoming mutation.
412
- 7. `yootheme_builder_advanced({ tool: "yootheme_builder_element_bind_source", input: { template_id, element_path, source_name: "<name>", etag: "<etag>" } })`
430
+ 7. `yootheme_builder_element_bind_source({ template_id, element_path, source_name: "<name>", etag: "<etag>" })`
413
431
  applies the binding. Returns `{ path, etag, has_binding: true }`.
414
432
  Pass `source_id: "<origin>:<name>"` as well **only** when two
415
433
  plugins register a source with the same `source_name` (the server
416
434
  surfaces the ambiguity as an elicitation prompt; if the host
417
435
  doesn't support elicitation you'll see a structured error listing
418
- the candidates). Also an advanced tool.
419
- 8. `yootheme_builder_advanced({ tool: "yootheme_builder_page_save", input: { template_id, etag: "<fresh>" } })`
420
- then `yootheme_builder_advanced({ tool: "yootheme_builder_page_publish", input: { template_id, etag: "<fresh>" } })`.
436
+ the candidates). This is a first-class L1 tool — call it directly.
437
+ 8. `yootheme_builder_page_save({ template_id, etag: "<fresh>" })`
438
+ then `yootheme_builder_page_publish({ template_id, etag: "<fresh>" })`.
421
439
 
422
440
  **Common pitfalls:**
423
441
 
@@ -440,29 +458,29 @@ renders dynamic items.
440
458
  - **Forgetting `etag`.** Every write requires the optimistic-lock
441
459
  etag. On `412 Precondition Failed` re-fetch via
442
460
  `yootheme_builder_get_etag` and retry.
443
- - **Calling bind/unbind directly.** Both `element_bind_source` and
444
- `element_get_binding` are L2 advanced. Wrap in
445
- `yootheme_builder_advanced({ tool, input })`.
461
+ - **Mis-routing bind vs the read helpers.** `element_bind_source` is
462
+ now a first-class L1 tool — call it directly by name. The binding
463
+ *read* helpers `element_get_binding` and `element_unbind_source` stay
464
+ L2 advanced; reach those through
465
+ `yootheme_builder_advanced({ tool, arguments })`.
446
466
 
447
467
  **Worked example (tool-call snippet):**
448
468
 
449
469
  ```jsonc
450
- // Step 7. Bind a Posts source onto a Grid element via the gateway.
451
- yootheme_builder_advanced({
452
- tool: "yootheme_builder_element_bind_source",
453
- input: {
454
- template_id: "home",
455
- element_path: "/0/children/2/children/0",
456
- source_name: "wp_posts",
457
- etag: "abc123"
458
- // source_id: "wordpress:wp_posts" // pass ONLY when name collides
459
- }
470
+ // Step 7. Bind a Posts source onto a Grid element. element_bind_source
471
+ // is a first-class L1 tool — call it directly.
472
+ yootheme_builder_element_bind_source({
473
+ template_id: "home",
474
+ element_path: "/0/children/2/children/0",
475
+ source_name: "wp_posts",
476
+ etag: "abc123"
477
+ // source_id: "wordpress:wp_posts" // pass ONLY when name collides
460
478
  })
461
479
  // Response: { path: "/0/children/2/children/0", etag: "def456", has_binding: true }
462
480
  // Verify (via gateway):
463
481
  yootheme_builder_advanced({
464
482
  tool: "yootheme_builder_element_get_binding",
465
- input: { template_id: "home", element_path: "/0/children/2/children/0" }
483
+ arguments: { template_id: "home", element_path: "/0/children/2/children/0" }
466
484
  })
467
485
  // → { source_name: "wp_posts", source_config: { ... }, ... }
468
486
  ```
@@ -478,6 +496,50 @@ items from the Source (verify by item count and at least one
478
496
  field-value spot-check). `yootheme_builder_element_get_binding`
479
497
  (via gateway) returns the new `source_name`.
480
498
 
499
+ ### Multi-Items renderer truth table (read before binding rich cards)
500
+
501
+ The YT5 renderer (`SourceTransform`) follows ONE rule:
502
+
503
+ > A `…List` source renders nested children **only** when the element
504
+ > carrying it is a **CONTAINER** whose template renders its children
505
+ > (`column`, `fragment`, `row`, `section`, `grid`). `grid_item` and every
506
+ > `*_item` atom are **LEAF renderers**: the list iterates them per row, but
507
+ > their template paints **only their own slots** and **never** renders nested
508
+ > children — so any elements nested inside an iterating `grid_item` are
509
+ > dropped and you see placeholders.
510
+
511
+ What the renderer consumes from `item.source.props`: it maps each row field
512
+ onto the element's **own** display slots (`grid_item`:
513
+ title/meta/content/image/video/hover_image/hover_video/link/icon; `panel`:
514
+ title/meta/content/image). It is **last-write-wins** — two fields mapped to
515
+ the same slot silently lose one.
516
+
517
+ Two canonical forms (both live-verified):
518
+
519
+ - **(a) Simple card, N ≤ slots — iterate ON the `grid_item`:**
520
+ `grid_item{ source:{ query:{name:"…List"}, props:{ title:{name:F1}, meta:{name:F2}, image:{name:F3} } } }`.
521
+ No nested children. Renders because the data lands on the item's own slots.
522
+
523
+ - **(b) Rich / arbitrary card, any N — iterate ON a CONTAINER:**
524
+ `column{ source:{query:{name:"…List"}} > fragment{#parent} > leaves{ source:{query:{name:"#parent"}, props:{<slot>:{name:Fk}}} }`.
525
+ One leaf per field, **no leaf limit**. `<slot>` is `content` for
526
+ headline/text, or title/meta/image for panel. The `fragment` wrapper is
527
+ **optional** (it may carry `source.query.name="#parent"` or no source —
528
+ both work because a fragment renders its children either way).
529
+
530
+ **Guards (the tool enforces these):**
531
+
532
+ - Binding a leaf that is a **DIRECT child of an iterating `grid_item`** (no
533
+ `fragment` between) auto-**consolidates** the field onto the item's own
534
+ slots (form (a)) and leaves the leaf source-free (`consolidated_to_parent`).
535
+ - A consolidation that targets an **occupied slot** OR a key that is **not a
536
+ slot** of the item type is **rejected** with `slot_collision` (HTTP 409) —
537
+ give each field its own leaf / a distinct slot.
538
+ - Binding a `…List` source ONTO a `grid_item` that already has nested
539
+ children surfaces a blocking `iterator_is_leaf_renderer` warning (the
540
+ children are render-dead): map the fields onto the item's slots, or move
541
+ the List onto a container.
542
+
481
543
  ---
482
544
 
483
545
  ## Workflow 3: Clone & modify a section within a template
@@ -502,7 +564,7 @@ CMS-level template duplication (in wp-admin or Joomla administrator).
502
564
  1. `yootheme_builder_health`: confirm host plugin reachable.
503
565
  2. `yootheme_builder_pages_list({ fields: ["id", "label"] })`:
504
566
  locate the template by `label`. Note its `id`.
505
- 3. `yootheme_builder_advanced({ tool: "yootheme_builder_page_get_schema", input: { template_id } })`
567
+ 3. `yootheme_builder_advanced({ tool: "yootheme_builder_page_get_schema", arguments: { template_id } })`
506
568
  returns a flat schema view (lighter than `page_get_layout`) showing every
507
569
  element path + type. Pick the JSON-Pointer path of the section
508
570
  to clone. `page_get_schema` is L2; call via the gateway.
@@ -518,8 +580,8 @@ CMS-level template duplication (in wp-admin or Joomla administrator).
518
580
  pass `merge: true` to apply a server-side deep-merge instead).
519
581
  Read the current props first via `yootheme_builder_element_get`
520
582
  if you only want to tweak a subset.
521
- 8. `yootheme_builder_advanced({ tool: "yootheme_builder_page_save", input: { template_id, etag } })`
522
- then `yootheme_builder_advanced({ tool: "yootheme_builder_page_publish", input: { template_id, etag } })`.
583
+ 8. `yootheme_builder_page_save({ template_id, etag })`
584
+ then `yootheme_builder_page_publish({ template_id, etag })`.
523
585
 
524
586
  **Common pitfalls:**
525
587
 
@@ -537,7 +599,7 @@ CMS-level template duplication (in wp-admin or Joomla administrator).
537
599
  - **Cloning a bound element keeps the binding.** `element_clone`
538
600
  copies the entire element including `props.source`. If the user
539
601
  wanted a "data-free" copy, call
540
- `yootheme_builder_advanced({ tool: "yootheme_builder_element_unbind_source", input: { ... } })`
602
+ `yootheme_builder_advanced({ tool: "yootheme_builder_element_unbind_source", arguments: { ... } })`
541
603
  on the new path afterwards.
542
604
  - **Wrong parameter names.** Use `template_id`, `element_path`,
543
605
  `etag` (NOT `pageId`, `srcPath`, `ifMatch`).
@@ -569,11 +631,11 @@ yootheme_builder_element_update_settings({
569
631
  **Edge case:** When cloning a Grid with a source binding, the binding
570
632
  is preserved (same `source_name`). If the user wants a "data-free"
571
633
  copy, follow up with
572
- `yootheme_builder_advanced({ tool: "yootheme_builder_element_unbind_source", input: { ... } })`
634
+ `yootheme_builder_advanced({ tool: "yootheme_builder_element_unbind_source", arguments: { ... } })`
573
635
  on the new path. Verify with the gateway `element_get_binding` call.
574
636
 
575
637
  **Success criterion:** After publish,
576
- `yootheme_builder_advanced({ tool: "yootheme_builder_page_get_schema", input: { template_id } })`
638
+ `yootheme_builder_advanced({ tool: "yootheme_builder_page_get_schema", arguments: { template_id } })`
577
639
  shows the new section at the cloned path with the user's tweaks reflected in
578
640
  `element_get` on that path.
579
641
 
@@ -708,8 +770,8 @@ an instance with a sensible default props payload.
708
770
  iterates on the props. **Note: this REPLACES `props` entirely by
709
771
  default; pass `merge: true` for a server-side deep-merge.** When
710
772
  replacing, include every key you want to keep.
711
- 8. `yootheme_builder_advanced({ tool: "yootheme_builder_page_save", input: { template_id, etag } })`
712
- then `yootheme_builder_advanced({ tool: "yootheme_builder_page_publish", input: { template_id, etag } })`.
773
+ 8. `yootheme_builder_page_save({ template_id, etag })`
774
+ then `yootheme_builder_page_publish({ template_id, etag })`.
713
775
 
714
776
  **Common pitfalls:**
715
777
 
@@ -789,11 +851,11 @@ and the props payload you passed.
789
851
  elicitation, it returns a preview-with-confirm-required response;
790
852
  call again with `confirm: true`.
791
853
  - **Unbind a source**: call through the gateway:
792
- `yootheme_builder_advanced({ tool: "yootheme_builder_element_unbind_source", input: { template_id, element_path, etag, confirm: true } })`.
854
+ `yootheme_builder_advanced({ tool: "yootheme_builder_element_unbind_source", arguments: { template_id, element_path, etag, confirm: true } })`.
793
855
  Same elicitation flow as delete.
794
856
  - **Flat schema inspection** (e.g. enumerate every element path +
795
857
  type without fetching the whole nested tree): call through the
796
- gateway: `yootheme_builder_advanced({ tool: "yootheme_builder_page_get_schema", input: { template_id } })`.
858
+ gateway: `yootheme_builder_advanced({ tool: "yootheme_builder_page_get_schema", arguments: { template_id } })`.
797
859
  - **Etag-only fetch** (e.g. polling for concurrent edits): use
798
860
  `yootheme_builder_get_etag()` (takes no arguments) is cheaper than
799
861
  fetching the full layout.
@@ -808,7 +870,7 @@ and the props payload you passed.
808
870
  - **Strip legacy `implode` directives** from an element binding (audit-clean
809
871
  source props that pre-date the wrapper-source refactor): call through the
810
872
  gateway:
811
- `yootheme_builder_advanced({ tool: "yootheme_builder_clean_implode_directives", input: { template_id, element_path, etag } })`.
873
+ `yootheme_builder_advanced({ tool: "yootheme_builder_clean_implode_directives", arguments: { template_id, element_path, etag } })`.
812
874
  Returns the audit log + a fresh ETag; idempotent (`cleaned_count: 0` when
813
875
  there is nothing to remove).
814
876
 
@@ -822,14 +884,14 @@ Joomla administrator access." Don't fabricate tool calls.
822
884
 
823
885
  <!-- TOOL-CATALOG:BEGIN -->
824
886
 
825
- **29 catalogued tools** plus the `yootheme_builder_advanced` gateway = **30 reachable via `tools/list`** (20 L1 + 2 L3 + 1 gateway = 23 advertised; the gateway routes to 7 additional advanced tools, bringing the total to 30 callable). Generated by `scripts/extract-tools.mjs` from the compiled `buildAllTools()` registry. Do not hand-edit this section; re-run `npm run build && node scripts/extract-tools.mjs` after changing tool definitions.
887
+ **32 catalogued tools** plus the `yootheme_builder_advanced` (write) + `yootheme_builder_advanced_read` (read-only) gateways = **34 reachable via `tools/list`** (25 L1 + 2 L3 + 2 gateways = 29 advertised; the gateways route to 5 additional advanced tools, bringing the total to 34 callable). Generated by `scripts/extract-tools.mjs` from the compiled `buildAllTools()` registry. Do not hand-edit this section; re-run `npm run build && node scripts/extract-tools.mjs` after changing tool definitions.
826
888
 
827
889
  | Tool | Kind | Input keys | Description |
828
890
  | --- | --- | --- | --- |
829
891
  | `yootheme_builder_clean_implode_directives` | destructive | `confirm`, `element_path`, `etag`, `site_id`, `template_id` | Strips `props.source.props.*.implode` directives from an element binding. Returns audit log + new ETag. Idempotent at the server (cleaned_count: 0 when nothing to remove) but classed as destructive because the affected binding cannot be restored without re-mapping. Always ask the user to confirm first, then call again with `confirm: true`. Requires ETag. Operates on the default site unless site_id is provided. |
830
892
  | `yootheme_builder_diagnose` | read+idempotent | `site_id` | Full diagnostic: /health + authenticated /etag probe. Returns site_url, home_url, plugin reachability, Bearer validity in one call. First call when you need to know where the site lives. For per-template URLs see pages_list. Operates on the default site unless site_id is provided. |
831
- | `yootheme_builder_element_add` | mutating | `children`, `element_type`, `etag`, `parent_path`, `props`, `site_id`, `template_id` | Add a new element to a template. Provide `parent_path` (or "" for root), `element_type` (e.g. "headline", "text", "grid"), and optional `props` / `children`. Returns the new element's JSON-Pointer path. Requires ETag. Operates on the default site unless site_id is provided. |
832
- | `yootheme_builder_element_bind_source` | idempotent | `bindingLevel`, `element_path`, `etag`, `field_mappings`, `site_id`, `source_id`, `source_name`, `template_id` | Binds a Builder source to an element (sets `props.source`). Use bindingLevel "item" on Multi-Items containers (grid/slideshow/switcher/…) to bind on the first *_item child instead of the container itself. Requires ETag. Operates on the default site unless site_id is provided. |
893
+ | `yootheme_builder_element_add` | mutating | `children`, `element_type`, `etag`, `index`, `parent_path`, `position`, `props`, `site_id`, `template_id`, `type_name` | Add a new element to a template. Provide `parent_path` (or "" for root), `element_type` (e.g. "headline", "text", "grid"), and optional `props` / `children`. Appends by default; pass `index` (0 = first) to insert before siblings. Returns the new element's JSON-Pointer path. Requires ETag. Operates on the default site unless site_id is provided. |
894
+ | `yootheme_builder_element_bind_source` | idempotent | `bindingLevel`, `element_path`, `etag`, `field_mappings`, `site_id`, `source_id`, `source_name`, `template_id` | Binds a Builder source to an element (canonical shape: `source` top-level). Pass `field_mappings` in the SAME call; bindingLevel "item" binds a container's first *_item child. Leaf under an iterating *_item → CONSOLIDATE onto item slots (409 slot_collision if taken/not a slot); leaf under a #parent fragment → INHERIT (`__node_item__`); standalone renders empty. List on a grid_item with children iterator_is_leaf_renderer. Map: bind `map_item`, map `location` to a "lat,lng" field or no markers. Requires ETag. Call directly. Operates on the default site unless site_id is provided. |
833
895
  | `yootheme_builder_element_clone` | mutating | `element_path`, `etag`, `site_id`, `template_id` | Clone an element as a sibling (same parent, immediately after the source). Returns the new element's path. Requires ETag. Operates on the default site unless site_id is provided. |
834
896
  | `yootheme_builder_element_delete` | destructive | `confirm`, `element_path`, `etag`, `site_id`, `template_id` | PERMANENTLY delete an element + children. Cannot be undone. Pass `confirm: true` (boolean) AND a fresh ETag. If `preview:true` returns despite confirm, check `details.received_confirm` — strings/numbers accepted, but boolean is canonical. Operates on the default site unless site_id is provided. |
835
897
  | `yootheme_builder_element_get` | read+idempotent | `element_path`, `site_id`, `template_id` | Get the full element object at a specific JSON-Pointer path, including props and children. Use yootheme_builder_element_list to discover paths. Operates on the default site unless site_id is provided. |
@@ -837,23 +899,26 @@ Joomla administrator access." Don't fabricate tool calls.
837
899
  | `yootheme_builder_element_list` | read+idempotent | `cursor`, `depth`, `fields`, `limit`, `root_path`, `site_id`, `template_id` | List elements in a template as a flat array with JSON-Pointer paths + types. Scope with `root_path`/`depth` for a subtree, paginate with `limit`/`cursor` for large templates. `fields[]` narrows each row. Operates on the default site unless site_id is provided. |
838
900
  | `yootheme_builder_element_move` | idempotent | `element_path`, `etag`, `site_id`, `template_id`, `to_index`, `to_parent_path` | Move an element to a new parent + index in the tree. Useful for reordering or reparenting (e.g. moving a card from one grid column to another). Requires ETag. Operates on the default site unless site_id is provided. |
839
901
  | `yootheme_builder_element_type_get_schema` | read+idempotent | `element_type`, `site_id`, `type_name` | **Call before every `element_add` / `_update_settings`** — unknown prop keys are silently dropped server-side, so guessing fails quietly. Returns `{name,type,label?}` field descriptors. Use `element_type`; `type_name` is DEPRECATED. Operates on the default site unless site_id is provided. |
840
- | `yootheme_builder_element_types_list` | read+idempotent | `fields`, `site_id` | List element types registered on this site (built-ins + YOOessentials/uEssentials extras). Names feed `element_type` of element_add. Pass `fields[]` to narrow each row. Operates on the default site unless site_id is provided. |
902
+ | `yootheme_builder_element_types_list` | read+idempotent | `fields`, `site_id` | List element types registered on this site (built-ins + YOOessentials/uEssentials extras). Names feed `element_type` of element_add. Pass `fields[]` to narrow each row. Keywords: "slider"/"carousel" → `slideshow`/`panel-slider`/`overlay-slider`. Prop keys differ per element (grid_item `title` vs headline `content`) — use element_type_get_schema before element_add/bind. Operates on the default site unless site_id is provided. |
841
903
  | `yootheme_builder_element_unbind_source` | destructive | `confirm`, `element_path`, `etag`, `site_id`, `template_id` | Remove the source binding from an element. Clears `props.source`. Destructive in the sense that it may break dynamic-content rendering — always ask the user to confirm. Requires ETag. Operates on the default site unless site_id is provided. |
842
904
  | `yootheme_builder_element_update_settings` | idempotent | `element_path`, `etag`, `merge`, `props`, `site_id`, `template_id` | Update `props` on an element. Default replaces all props; pass `merge:true` for server-side deep-merge (only request keys overwritten, others survive — avoids read-modify-write races). Requires ETag. Operates on the default site unless site_id is provided. |
843
905
  | `yootheme_builder_get_etag` | read+idempotent | `site_id` | Get the current ETag (state revision) for the YOOtheme builder. Returns sha256+revision string used for optimistic locking on writes. Pass the returned value back as `etag` on any write tool (page_save, page_publish, element_add, element_update_settings, element_clone, element_move, element_delete). The server returns HTTP 412 if the ETag has changed since you read it. Keywords: get etag, current etag, state revision, optimistic lock, version stamp. Operates on the default site unless site_id is provided. |
844
906
  | `yootheme_builder_health` | read+idempotent | `site_id` | Check plugin installed/reachable. Returns plugin version, YT Pro version, REST endpoints. Authenticated payload adds site_url + home_url for deep-linking. See yootheme_builder_diagnose for Bearer-validity + connectivity summary. Operates on the default site unless site_id is provided. |
845
- | `yootheme_builder_inspect_multi_items_binding` | read+idempotent | `element_path`, `site_id`, `template_id` | Reports Multi-Items binding state: container/item pair (grid↔grid_item, slideshow↔slideshow_item, …), current binding level (none\|container\|item), and a recommended_fix when the binding sits on the container instead of the child. Operates on the default site unless site_id is provided. |
846
- | `yootheme_builder_page_get_layout` | read+idempotent | `fields`, `flat`, `site_id`, `template_id` | Get full layout tree for one template. Default nested `{layout, etag}`. Set `flat:true` for depth-first array `{elements:[...], etag}`; combine with `fields[]` to project per-element. Operates on the default site unless site_id is provided. |
907
+ | `yootheme_builder_inspect_multi_items_binding` | read+idempotent | `element_path`, `site_id`, `template_id` | Reports Multi-Items binding state: container/item pair (grid↔grid_item, slideshow↔slideshow_item, map↔map_item, …), current binding level (none\|container\|item), and a recommended_fix when the binding sits on the container instead of the child. For map/map_item, a bound item without a `location` ("lat,lng") field is flagged as a blocking map_location_warning (renders 0 markers). A List on a grid_item with nested children → blocking iterator_is_leaf_renderer (children never render). Operates on the default site unless site_id is provided. |
908
+ | `yootheme_builder_inspect_sublayout` | read+idempotent | `element_path`, `site_id`, `template_id` | Inspects a panel/grid_item `< SUBLAYOUT`: lists the `fragment` subtree bindable leaves (with JSON-Pointer paths to bind on — NOT the container) and the render-time inner grid. Flags `ungated_grid_prop` (blocking): grid props set but the gate (title_align=left / image_align=left\|right) unsatisfied → silent no-op. For container↔item binding see inspect_multi_items_binding. Operates on the default site unless site_id is provided. |
909
+ | `yootheme_builder_page_dynamize` | mutating | `conditions`, `element_path`, `etag`, `leaf_map`, `list_source_name`, `page`, `remove_leaves`, `section_name`, `site_id`, `source_map`, `template_id` | One-call way to dynamize a designed section: copies the layout byte-identically and swaps only what you map. Use INSTEAD of hand-editing JSON. Give a REFERENCE (section_name from template_summary, or element_path) + list_source_name + a leaf_map (original leaf field-name → flat flow field; #parent + tuned props kept). A section with several source blocks (Played/Next/Later) dynamizes in ONE call via source_map ({match, source_name, leaf_map?}[]). Sub-query panels: key by "<subquery>.<leaf>". Returns page + `summary`. Requires page.title. Operates on the default site unless site_id is provided. |
910
+ | `yootheme_builder_page_get_layout` | read+idempotent | `fields`, `flat`, `force`, `mode`, `site_id`, `template_id` | Get the layout tree for one template. For dynamize/bind work prefer `mode:"bindings_only"` — just the binding skeleton (path, element_type, name, has_binding, source{query_name,props,has_condition}, children), no style props, typically <=15% of full size. Default `mode:"full"` returns nested `{layout, etag}`. `flat:true` gives a depth-first `{elements:[...], etag}` array (combine with `fields[]`). A repeated full read of an unchanged template auto-skips with `[unchanged]` — `force:true` re-fetches. Operates on the default site unless site_id is provided. |
847
911
  | `yootheme_builder_page_get_schema` | read+idempotent | `site_id`, `template_id` | Get the flat schema for a template — a list of nodes with their JSON-Pointer paths and element types. Best entry-point for navigation: lighter than page_get_layout, sufficient to locate elements before editing. Operates on the default site unless site_id is provided. |
848
912
  | `yootheme_builder_page_publish` | idempotent | `etag`, `site_id`, `template_id` | Publish a template — persist state, flush YT + WP caches, snapshot the published-state ETag. ETag optional — when provided, 412 on conflict; when omitted, last-write-wins. Recommended for collaborative edits. Operates on the default site unless site_id is provided. |
849
- | `yootheme_builder_page_save` | idempotent | `etag`, `site_id`, `template_id` | Re-run save-transforms + flush caches. Does NOT accept a layout — land edits via element_add/update/bind/delete first. No-op if byte-identical. New pages: pages_create. Publish: page_publish. ETag optional. Operates on the default site unless site_id is provided. |
850
- | `yootheme_builder_pages_create` | idempotent | `dry_run`, `layout`, `site_id`, `slug`, `status`, `title` | Create a new WordPress page with a YOOtheme per-page layout. Required: title. Optional: slug (defaults to sanitize_title(title)), status (default: draft), layout (JSON, default: {type:"layout",children:[]}). Supports dry-run mode (dry_run:true) to preflight all hardening layers without persisting. Returns page_id, slug (post-collision-resolved), template_id, etag, warnings. Operates on the default site unless site_id is provided. |
851
- | `yootheme_builder_pages_delete` | idempotent | `confirm`, `force`, `post_id`, `site_id` | Delete a WordPress page (with associated YOOtheme per-page layout). Requires confirm:true (gate against accidental deletion). Default behavior: wp_trash_post (recoverable via wp-admin). With force:true: permanent wp_delete_post(force=true). Refuses non-page post types with 403 (Layer 9 defense). Returns deleted:true, page_id, force_deleted, bumped etag. Operates on the default site unless site_id is provided. |
852
- | `yootheme_builder_pages_list` | read+idempotent | `fields`, `site_id` | List all pages, templates, and layouts in the YOOtheme Pro builder. Returns template_id, label, type, element count, and frontend_url per row. CALL THIS FIRST to discover available template IDs before any tool that needs a template_id (page_get_layout, element_list, page_get_schema, etc.). Keywords: list pages, list templates, list layouts, discover template_id, index, available templates, what pages exist. Pass `fields:["id","label"]` to slim. Returns ALL pages in one call (no pagination, typically <50 templates per site). Operates on the default site unless site_id is provided. |
913
+ | `yootheme_builder_page_save` | idempotent | `etag`, `layout`, `site_id`, `template_id` | Re-run save-transforms + flush caches. Optionally pass a whole `layout` to REPLACE the template tree ATOMICALLY (F85) ideal for wholesale dynamization (read layout → swap query → remap fields → write back). A supplied layout is validated + ETag-locked; on rejection nothing is persisted. Omit `layout` to just re-run transforms (no-op if byte-identical) — for incremental edits use element_add/update/bind/delete first. New pages: pages_create. Publish: page_publish. ETag optional (412 on conflict; else last-write-wins). Operates on the default site unless site_id is provided. |
914
+ | `yootheme_builder_pages_create` | idempotent | `dry_run`, `layout`, `menu_item`, `published`, `site_id`, `slug`, `status`, `title` | Create a page (WordPress) or article (Joomla 5/6) with a YOOtheme per-page layout. Required: title. Optional: slug, status (default draft), published (default false → live on true: WP publish / Joomla state 1), layout (JSON), menu_item (Joomla SEF route), dry_run (preflight, no persist). Returns page_id (WP) / article_id (Joomla), slug, template_id (page:{id} or article:{id}), etag, warnings. Joomla: a published article has NO SEF route until a menu item points at it — pass menu_item, else frontend_url may 404. Operates on the default site unless site_id is provided. |
915
+ | `yootheme_builder_pages_delete` | idempotent | `confirm`, `force`, `post_id`, `site_id` | Delete a page (WordPress) or article (Joomla 5/6) with its YOOtheme per-page layout. Requires confirm:true (gate against accidental deletion). Default: trash (recoverable). force:true: permanent delete. Refuses non-page/article types with 403 (Layer 9 defense). Returns deleted:true, page_id (WP) / article_id (Joomla), force_deleted, bumped etag. Operates on the default site unless site_id is provided. |
916
+ | `yootheme_builder_pages_list` | read+idempotent | `fields`, `site_id` | List all pages, templates, and layouts in the YOOtheme Pro builder. Returns template_id, label, type, element count, frontend_url, and builder_url (deep-link to open it in the builder) per row. CALL THIS FIRST to discover available template IDs before any tool that needs a template_id (page_get_layout, element_list, page_get_schema, etc.). Keywords: list pages, list templates, discover template_id. Pass `fields:["id","label"]` to slim. Returns ALL pages in one call (no pagination, typically <50 templates per site). Operates on the default site unless site_id is provided. |
917
+ | `yootheme_builder_scaffold_section` | mutating | `columns`, `etag`, `site_id`, `template_id` | Create a VALID section → row → column hull in ONE atomic call and return the column JSON-Pointer path(s) to drop content into. This is the EASIEST correct way to start a new layout block: YOOtheme content must live in section → row → column, and adding content anywhere else (root, bare section, bare row) is rejected. Pass `columns` (1-12, default 1) for a multi-column row. Requires ETag. Operates on the default site unless site_id is provided. |
853
918
  | `yootheme_builder_sites_list` | read+idempotent | `site_id` | List all sites configured in this multi-site MCP installation. Returns site_id + URL + platform (wordpress\|joomla) + default flag per row. CALL THIS FIRST when working with a fresh MCP connection to discover available site_ids before targeting one with any other tool. Read-only, no REST calls. Keywords: list sites, list connections, list installations, discover site_id, available sites, configured sites, what sites exist, multi-site index. (site_id is accepted for schema-uniformity but ignored by this tool.) |
854
919
  | `yootheme_builder_sites_test` | read+idempotent | `site_id` | Verify connectivity to ONE site: probes /health (no auth) + /etag (auth) in parallel; returns plugin_reachable + bearer_valid. `site_id` is REQUIRED. Use sites_list to find IDs. |
855
- | `yootheme_builder_sources_list` | read+idempotent | `fields`, `site_id` | List all data sources, feeds, and dynamic content sources available in the YOOtheme Pro builder. Returns name + label + origin (apimapper / wordpress / joomla / essentials) per source. CALL THIS BEFORE binding any element to a data source. Pick a source name from the list and pass it to `element_bind_source`. Keywords: list sources, list data sources, list feeds, list bindings, dynamic content, available data, what sources exist. Pass `fields[]` to narrow each row. Operates on the default site unless site_id is provided. |
856
- | `yootheme_builder_template_summary` | read+idempotent | `site_id`, `template_id` | Token-efficient template overview: element counts by type, binding count, max nesting depth, and named landmark sections — computed server-side in one call. Use this to grasp a large template before pulling element_list or page_get_layout. Operates on the default site unless site_id is provided. |
857
- | `yootheme_builder_use_site` | idempotent | `probe`, `site_id` | Switch the ACTIVE site for this multi-site session. After this call, every tool that omits `site_id` targets the site you picked here (until you switch again or restart). Runs a /health + /etag probe by default; pass `probe: false` to switch offline. A degraded site is a soft warning (the switch still happens). `site_id` is REQUIRED. Keywords: switch site, change site, set active site, select installation, use profile, activate site, target site. Use yootheme_builder_sites_list first to find IDs. |
920
+ | `yootheme_builder_sources_list` | read+idempotent | `fields`, `site_id` | List all data sources, feeds, and dynamic content sources available in the YOOtheme Pro builder. Returns name + label + origin (apimapper / wordpress / joomla / essentials) per source. CALL THIS BEFORE binding any element to a data source. Then bind directly with yootheme_builder_element_bind_source (a first-class tool in tools/list). Keywords: list sources, list data sources, list feeds, list bindings, dynamic content, available data, what sources exist. Pass `fields[]` to narrow each row. Operates on the default site unless site_id is provided. |
921
+ | `yootheme_builder_template_summary` | read+idempotent | `site_id`, `template_id` | Token-efficient template overview: element counts by type, binding count, max nesting depth, and named landmark sections — computed server-side in one call. Use this to grasp a large template before pulling element_list or page_get_layout. Example: yootheme_builder_template_summary({ template_id: "default" }). Operates on the default site unless site_id is provided. |
922
+ | `yootheme_builder_use_site` | idempotent | `probe`, `site_id` | Switch the ACTIVE site for this multi-site session. After this call, every tool that omits `site_id` targets the site you picked here. NOTE: this default is PROCESS-WIDE — concurrent clients sharing this MCP server inherit it; pass `site_id` per call for isolation between parallel agents. Runs a /health + /etag probe by default; pass `probe: false` to switch offline. A degraded site is a soft warning (the switch still happens). `site_id` is REQUIRED. Keywords: switch/change/set active/target site, select installation, use profile. Use yootheme_builder_sites_list first to find IDs. |
858
923
 
859
924
  <!-- TOOL-CATALOG:END -->