@caelo-cms/mcp-server 0.11.2 → 0.11.4
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.
- package/package.json +1 -1
- package/power-catalogue.json +78 -11
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@caelo-cms/mcp-server",
|
|
3
3
|
"mcpName": "io.github.caelo-cms/caelo",
|
|
4
|
-
"version": "0.11.
|
|
4
|
+
"version": "0.11.4",
|
|
5
5
|
"private": false,
|
|
6
6
|
"license": "MPL-2.0",
|
|
7
7
|
"description": "MCP servers for Caelo CMS: `caelo_chat` (talk to Caelo's own AI) and the admin-scoped Power-MCP (the full chat-runner tool catalogue, driven by your own agent). Lets Claude Code (or any MCP-aware client) drive a Caelo install from outside the browser.",
|
package/power-catalogue.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.11.
|
|
2
|
+
"version": "0.11.4",
|
|
3
3
|
"tools": [
|
|
4
4
|
{
|
|
5
5
|
"name": "read_content",
|
|
@@ -229,7 +229,7 @@
|
|
|
229
229
|
},
|
|
230
230
|
{
|
|
231
231
|
"name": "build_page",
|
|
232
|
-
"description": "Build a WHOLE page in ONE transaction: create (`page:{slug, title}`) or target existing (`page:{pageId}`) + the full ordered module list (each entry places one module into a template block, top to bottom; on an existing page entries append). Any invalid entry aborts everything (error names `modules[i]` + failing field); nothing is written.\nUSE FOR: every page creation (THE page-creation tool); any page needing >1 module — never `add_module` / `create_content_instances` chains. `modules: []` = intentionally empty page shell.\nDO NOT USE FOR: one incremental module on an existing page -> `add_module` (target `page`); site chrome header/footer -> `add_module` (target `layout`; chrome never rides in a page body).\nCORE RULES:\n- Creating: typed page -> `page.pageType` (+ `properties`/`terms`; an ordinary page omits pageType); always `page.metaDescription`, and `status:\"published\"` for a page that belongs on the site — a Stage refuses published pages without a description and builds only published ones; the result says what still blocks a Stage.\n- Per module, two modes: `moduleId` places an EXISTING module (`list_modules`; reuse first — shared modules keep pages consistent), or mint with `displayName` + `html` + `description` + `kind` + explicit `fields[]` (all required).\n- Pair `{{field_name}}` placeholders in `html` with `fields[]` in semantic snake_case (`hero_title`, `primary_cta_href`); never heuristic names (`cta2label2`) or numbered scalars (`label1`..`label10` -> ONE `list` field or a `module-list`).\n- Nested modules in the SAME call: inner entry gets `ref` and NO `blockName` (detached: minted + content-bound, not placed); the outer module's `module`/`module-list` field value references it as `{\"$ref\":\"<ref>\"}`, any array order. Never an `add_module` -> `remove_module_from` -> `create_content_instances` chain. E.g. `modules:[{ref:'btn', displayName:'Button', html:'<button>{{label}}</button>', fields:[…], content:{source:'inline', values:{label:'Go'}}}, {blockName:'content', displayName:'CTA', html:'<section>{{>cta}}</section>', fields:[{name:'cta', kind:'module', label:'CTA', allowedModuleTypes:['button']}], content:{source:'inline', values:{cta:{'$ref':'btn'}}}}]`\n- Zero templates on the site -> bootstrap first (`create_layout` -> `create_template`).\n- INTERNAL LINKS (`html` hrefs, `url`/`link` fields, list-entry links): write the page path (e.g. `/about`). Target MUST be an existing page (`list_pages`) or it is refused — create an empty shell first (`build_page({page:{slug, title}, modules:[]})`) or link after. `/` and `/#section` are always valid. Exception: links to pages of this chat's site-import run are kept and resolved by `resolve_import_links` at the end. Media/files: media URL (`find_media`). External: full `https://` URL.\nTypical call: `{page:{slug:'pricing', title:'Pricing', status:'published', metaDescription:'…'}, modules:[{blockName:'content', displayName:'Pricing Hero', kind:'hero', description:'…', html:'<section><h1>{{hero_title}}</h1></section>', fields:[{name:'hero_title', kind:'text', label:'Hero title'}], content:{source:'inline', values:{hero_title:'Fair pricing'}}}, …]}`",
|
|
232
|
+
"description": "Build a WHOLE page in ONE transaction: create (`page:{slug, title}`) or target existing (`page:{pageId}`) + the full ordered module list (each entry places one module into a template block, top to bottom; on an existing page entries append). Any invalid entry aborts everything (error names `modules[i]` + failing field); nothing is written.\nUSE FOR: every page creation (THE page-creation tool); any page needing >1 module — never `add_module` / `create_content_instances` chains. `modules: []` = intentionally empty page shell.\nDO NOT USE FOR: one incremental module on an existing page -> `add_module` (target `page`); site chrome header/footer -> `add_module` (target `layout`; chrome never rides in a page body).\nCORE RULES:\n- Creating: typed page -> `page.pageType` (+ `properties`/`terms`; an ordinary page omits pageType); always `page.metaDescription`, and `status:\"published\"` for a page that belongs on the site — a Stage refuses published pages without a description and builds only published ones; the result says what still blocks a Stage.\n- Per module, two modes: `moduleId` places an EXISTING module (`list_modules`; reuse first — shared modules keep pages consistent), or mint with `displayName` + `html` + `description` + `kind` + explicit `fields[]` (all required).\n- Pair `{{field_name}}` placeholders in `html` with `fields[]` in semantic snake_case (`hero_title`, `primary_cta_href`); never heuristic names (`cta2label2`) or numbered scalars (`label1`..`label10` -> ONE `list` field or a `module-list`).\n- An overview of pages (guides hub, category page) is ONE `list` field bound to a page query (`bind:\"source\"`, `source:{kind:\"query\", defaults:{page_type:…}}`; `term_pages` / `children`), never a hand-kept card per page.\n- Nested modules in the SAME call: inner entry gets `ref` and NO `blockName` (detached: minted + content-bound, not placed); the outer module's `module`/`module-list` field value references it as `{\"$ref\":\"<ref>\"}`, any array order. Never an `add_module` -> `remove_module_from` -> `create_content_instances` chain. E.g. `modules:[{ref:'btn', displayName:'Button', html:'<button>{{label}}</button>', fields:[…], content:{source:'inline', values:{label:'Go'}}}, {blockName:'content', displayName:'CTA', html:'<section>{{>cta}}</section>', fields:[{name:'cta', kind:'module', label:'CTA', allowedModuleTypes:['button']}], content:{source:'inline', values:{cta:{'$ref':'btn'}}}}]`\n- Zero templates on the site -> bootstrap first (`create_layout` -> `create_template`).\n- INTERNAL LINKS (`html` hrefs, `url`/`link` fields, list-entry links): write the page path (e.g. `/about`). Target MUST be an existing page (`list_pages`) or it is refused — create an empty shell first (`build_page({page:{slug, title}, modules:[]})`) or link after. `/` and `/#section` are always valid. Exception: links to pages of this chat's site-import run are kept and resolved by `resolve_import_links` at the end. Media/files: media URL (`find_media`). External: full `https://` URL.\nTypical call: `{page:{slug:'pricing', title:'Pricing', status:'published', metaDescription:'…'}, modules:[{blockName:'content', displayName:'Pricing Hero', kind:'hero', description:'…', html:'<section><h1>{{hero_title}}</h1></section>', fields:[{name:'hero_title', kind:'text', label:'Hero title'}], content:{source:'inline', values:{hero_title:'Fair pricing'}}}, …]}`",
|
|
233
233
|
"inputSchema": {
|
|
234
234
|
"type": "object",
|
|
235
235
|
"additionalProperties": false,
|
|
@@ -528,7 +528,28 @@
|
|
|
528
528
|
},
|
|
529
529
|
"source": {
|
|
530
530
|
"type": "object",
|
|
531
|
-
"description": "bind \"source\": {kind:\"query\", editable, defaults} | {kind:\"system\", name: breadcrumbs|children|siblings|page_terms|term_pages} | {kind:\"plugin\", name} (a plugin list iterated by name needs no field)."
|
|
531
|
+
"description": "bind \"source\": {kind:\"query\", editable, defaults} | {kind:\"system\", name: breadcrumbs|children|siblings|page_terms|term_pages|pagination} | {kind:\"plugin\", name} (a plugin list iterated by name needs no field)."
|
|
532
|
+
},
|
|
533
|
+
"paginate": {
|
|
534
|
+
"type": "object",
|
|
535
|
+
"additionalProperties": false,
|
|
536
|
+
"description": "Overview of ALL matching pages (query without `limit`, or term_pages): page 1 here, then <path>/page/2/…; one per module. Needs a pager field (source system \"pagination\": {{number}}, {{link}}, is_current/is_prev/is_next). A placement may override with value `paginate`.",
|
|
537
|
+
"properties": {
|
|
538
|
+
"per_page": {
|
|
539
|
+
"type": "integer",
|
|
540
|
+
"minimum": 1,
|
|
541
|
+
"maximum": 50,
|
|
542
|
+
"description": "Default 50."
|
|
543
|
+
},
|
|
544
|
+
"follow_ups": {
|
|
545
|
+
"type": "string",
|
|
546
|
+
"enum": [
|
|
547
|
+
"index",
|
|
548
|
+
"noindex"
|
|
549
|
+
],
|
|
550
|
+
"description": "Default \"index\" (self-canonical, in sitemap)."
|
|
551
|
+
}
|
|
552
|
+
}
|
|
532
553
|
},
|
|
533
554
|
"allowedModuleTypes": {
|
|
534
555
|
"type": "array",
|
|
@@ -715,7 +736,7 @@
|
|
|
715
736
|
},
|
|
716
737
|
{
|
|
717
738
|
"name": "list_content_instances",
|
|
718
|
-
"description": "List content_instances — values filling module placeholders (TOON rows: id, module, kind, slug, displayName, purpose, placements, parents),
|
|
739
|
+
"description": "List content_instances — values filling module placeholders (TOON rows: id, module, kind, slug, displayName, purpose, placements, parents, pages), widest reach first; counts as this chat's draft sees them.\n- `purpose` = why a shared row exists: read it BEFORE minting (`create_content_instances`); reuse a row whose purpose + module fit.\n- `placements` = its own placements; `parents` = instances, module defaults (layout chrome) and shared lists that show it inside them.\n- `pages` = blast radius: every page it renders on, its own placements plus everything its parents render on (`+site` = also layout chrome or a shared list) -> check BEFORE `set_content_instance_values_many`; `get_content_instance` names them.\n- ORPHAN (safe to delete) = placements 0 AND parents 0.\nNarrow by `moduleId` / `slug` / `pageId` (instances used on that page).",
|
|
719
740
|
"inputSchema": {
|
|
720
741
|
"type": "object",
|
|
721
742
|
"properties": {
|
|
@@ -757,7 +778,7 @@
|
|
|
757
778
|
},
|
|
758
779
|
{
|
|
759
780
|
"name": "get_content_instance",
|
|
760
|
-
"description": "Fetch one content_instance, as this chat's draft sees it: values, placements (page path, block, position, sync_mode)
|
|
781
|
+
"description": "Fetch one content_instance, as this chat's draft sees it: values, placements (page path, block, position, sync_mode), parents showing it (instances' `module`/`module-list` fields, module defaults, shared lists) and every page it renders on. Check that blast radius before `set_content_instance_values_many` and before deleting (orphan = no placements AND no parents).",
|
|
761
782
|
"inputSchema": {
|
|
762
783
|
"type": "object",
|
|
763
784
|
"properties": {
|
|
@@ -774,7 +795,7 @@
|
|
|
774
795
|
},
|
|
775
796
|
{
|
|
776
797
|
"name": "set_content_instance_values_many",
|
|
777
|
-
"description": "Edit values of 1..N shared content_instances in one transaction. Each item propagates to EVERY
|
|
798
|
+
"description": "Edit values of 1..N shared content_instances in one transaction. Each item propagates to EVERY page it renders on: its `synced` placements and every page of the parents that show it (blast radius = `pages` in `list_content_instances`).\nUSE FOR: deliberate shared-content changes — check `purpose`, pages and parents first (`list_content_instances` / `get_content_instance`).\nDO NOT USE FOR: an edit meant for ONE page -> `set_page_module_content_many` (unsynced placement) or `fork_placement_content` first (synced); module structure -> `update_modules_many`.\nCORE RULES:\n- All-or-nothing: an invalid item aborts the batch (error names `items[i]`); nothing is written.\n- Optional metadata in the same write: `slug`, `displayName` (`null` clears), `purpose`.\n- The result names per item where the edit now shows — relay it when the reach is wider than the operator asked for.\n- INTERNAL LINKS (`html` hrefs, `url`/`link` fields, list-entry links): write the page path (e.g. `/about`). Target MUST be an existing page (`list_pages`) or it is refused — create an empty shell first (`build_page({page:{slug, title}, modules:[]})`) or link after. `/` and `/#section` are always valid. Exception: links to pages of this chat's site-import run are kept and resolved by `resolve_import_links` at the end. Media/files: media URL (`find_media`). External: full `https://` URL.",
|
|
778
799
|
"inputSchema": {
|
|
779
800
|
"type": "object",
|
|
780
801
|
"additionalProperties": false,
|
|
@@ -836,7 +857,7 @@
|
|
|
836
857
|
},
|
|
837
858
|
{
|
|
838
859
|
"name": "delete_content_instances",
|
|
839
|
-
"description": "Soft-delete 1..N ORPHAN content_instances in one transaction. Orphan = no placements AND no parent
|
|
860
|
+
"description": "Soft-delete 1..N ORPHAN content_instances in one transaction. Orphan = no placements AND no parent shows it — no instance's `module`/`module-list` field, module default or shared list (`list_content_instances`: placements=0, parents=0).\nCORE RULES:\n- ANY refused item rolls back the WHOLE batch; the refusal names the blockers:\n - placements (page path, pageId, blockName, position) -> detach each via `fork_placement_content` with those values (page keeps a private copy), then retry.\n - parents -> detach first: an instance parent via `set_content_instance_values_many` (or delete the parent EARLIER in the same call), a module default via `update_modules_many`, a shared list entry via `patch_list_items_many`.\n- In a chat this lands on the draft; live changes when staged.",
|
|
840
861
|
"inputSchema": {
|
|
841
862
|
"type": "object",
|
|
842
863
|
"additionalProperties": false,
|
|
@@ -1116,7 +1137,7 @@
|
|
|
1116
1137
|
},
|
|
1117
1138
|
{
|
|
1118
1139
|
"name": "list_modules",
|
|
1119
|
-
"description": "List the module catalog (metadata, no HTML/CSS/JS): id, slug, type, kind, description, fields, placement usage.\nUSE FOR: a reuse candidate before placing/creating (prefer `add_module` with `moduleId` over a near-duplicate); the accepted child types before filling a `module`/`module-list` field.\nFields column: `blocks:module-list allowed=faq/cta` -> child `type` must be one of them (`allowed=any` = unrestricted). `nav:list(menu) shared=main-nav` = shared list (edit entries via `patch_list_items_many`) | `items:list(texts) local` = entries per placement | `latest:list(links) source=query(…)
|
|
1140
|
+
"description": "List the module catalog (metadata, no HTML/CSS/JS): id, slug, type, kind, description, fields, placement usage.\nUSE FOR: a reuse candidate before placing/creating (prefer `add_module` with `moduleId` over a near-duplicate); the accepted child types before filling a `module`/`module-list` field.\nFields column: `blocks:module-list allowed=faq/cta` -> child `type` must be one of them (`allowed=any` = unrestricted). `nav:list(menu) shared=main-nav` = shared list (edit entries via `patch_list_items_many`) | `items:list(texts) local` = entries per placement | `latest:list(links) source=query(…)` | `… paginate(per_page=50 follow_ups=index)` = overview of every match over follow-up pages.",
|
|
1120
1141
|
"inputSchema": {
|
|
1121
1142
|
"type": "object",
|
|
1122
1143
|
"properties": {
|
|
@@ -2387,7 +2408,28 @@
|
|
|
2387
2408
|
},
|
|
2388
2409
|
"source": {
|
|
2389
2410
|
"type": "object",
|
|
2390
|
-
"description": "bind \"source\": {kind:\"query\", editable, defaults} | {kind:\"system\", name: breadcrumbs|children|siblings|page_terms|term_pages} | {kind:\"plugin\", name} (a plugin list iterated by name needs no field)."
|
|
2411
|
+
"description": "bind \"source\": {kind:\"query\", editable, defaults} | {kind:\"system\", name: breadcrumbs|children|siblings|page_terms|term_pages|pagination} | {kind:\"plugin\", name} (a plugin list iterated by name needs no field)."
|
|
2412
|
+
},
|
|
2413
|
+
"paginate": {
|
|
2414
|
+
"type": "object",
|
|
2415
|
+
"additionalProperties": false,
|
|
2416
|
+
"description": "Overview of ALL matching pages (query without `limit`, or term_pages): page 1 here, then <path>/page/2/…; one per module. Needs a pager field (source system \"pagination\": {{number}}, {{link}}, is_current/is_prev/is_next). A placement may override with value `paginate`.",
|
|
2417
|
+
"properties": {
|
|
2418
|
+
"per_page": {
|
|
2419
|
+
"type": "integer",
|
|
2420
|
+
"minimum": 1,
|
|
2421
|
+
"maximum": 50,
|
|
2422
|
+
"description": "Default 50."
|
|
2423
|
+
},
|
|
2424
|
+
"follow_ups": {
|
|
2425
|
+
"type": "string",
|
|
2426
|
+
"enum": [
|
|
2427
|
+
"index",
|
|
2428
|
+
"noindex"
|
|
2429
|
+
],
|
|
2430
|
+
"description": "Default \"index\" (self-canonical, in sitemap)."
|
|
2431
|
+
}
|
|
2432
|
+
}
|
|
2391
2433
|
},
|
|
2392
2434
|
"allowedModuleTypes": {
|
|
2393
2435
|
"type": "array",
|
|
@@ -4061,6 +4103,10 @@
|
|
|
4061
4103
|
"minLength": 1,
|
|
4062
4104
|
"maxLength": 300,
|
|
4063
4105
|
"description": "CSS selector: capture only the first match (e.g. '[data-caelo-module-id=\"<uuid>\"]', 'footer.caelo-layout-footer') — cheaper when checking one module. Error if nothing matches."
|
|
4106
|
+
},
|
|
4107
|
+
"fullPage": {
|
|
4108
|
+
"type": "boolean",
|
|
4109
|
+
"description": "Server render only: true = the whole page; default = the visible viewport. Prefer `selector` for one section below the fold."
|
|
4064
4110
|
}
|
|
4065
4111
|
}
|
|
4066
4112
|
}
|
|
@@ -4577,7 +4623,28 @@
|
|
|
4577
4623
|
},
|
|
4578
4624
|
"source": {
|
|
4579
4625
|
"type": "object",
|
|
4580
|
-
"description": "bind \"source\": {kind:\"query\", editable, defaults} | {kind:\"system\", name: breadcrumbs|children|siblings|page_terms|term_pages} | {kind:\"plugin\", name} (a plugin list iterated by name needs no field)."
|
|
4626
|
+
"description": "bind \"source\": {kind:\"query\", editable, defaults} | {kind:\"system\", name: breadcrumbs|children|siblings|page_terms|term_pages|pagination} | {kind:\"plugin\", name} (a plugin list iterated by name needs no field)."
|
|
4627
|
+
},
|
|
4628
|
+
"paginate": {
|
|
4629
|
+
"type": "object",
|
|
4630
|
+
"additionalProperties": false,
|
|
4631
|
+
"description": "Overview of ALL matching pages (query without `limit`, or term_pages): page 1 here, then <path>/page/2/…; one per module. Needs a pager field (source system \"pagination\": {{number}}, {{link}}, is_current/is_prev/is_next). A placement may override with value `paginate`.",
|
|
4632
|
+
"properties": {
|
|
4633
|
+
"per_page": {
|
|
4634
|
+
"type": "integer",
|
|
4635
|
+
"minimum": 1,
|
|
4636
|
+
"maximum": 50,
|
|
4637
|
+
"description": "Default 50."
|
|
4638
|
+
},
|
|
4639
|
+
"follow_ups": {
|
|
4640
|
+
"type": "string",
|
|
4641
|
+
"enum": [
|
|
4642
|
+
"index",
|
|
4643
|
+
"noindex"
|
|
4644
|
+
],
|
|
4645
|
+
"description": "Default \"index\" (self-canonical, in sitemap)."
|
|
4646
|
+
}
|
|
4647
|
+
}
|
|
4581
4648
|
},
|
|
4582
4649
|
"allowedModuleTypes": {
|
|
4583
4650
|
"type": "array",
|
|
@@ -7554,7 +7621,7 @@
|
|
|
7554
7621
|
},
|
|
7555
7622
|
{
|
|
7556
7623
|
"name": "upsert_list_types_many",
|
|
7557
|
-
"description": "Create or replace list types (the SHAPE of a list)
|
|
7624
|
+
"description": "Create or replace list types (the SHAPE of a list).\nDO NOT USE FOR: a near-duplicate of a shipped type (reuse `links`/`menu`); changing a plugin-shipped type (create your own slug).\nCORE RULES:\n- `root.allow` = top-level node kinds. `purpose` = why the type exists (later reads decide by it). `max_depth` required when a node allows itself. `current_from` names the node's link field that marks the current page.\n- Field types: text, richtext, link (value {href}), media, select (`options`), boolean, number, date, icon, module (embedded; `accepts` = module types, absent = any), term (entries of vocabulary list `list: <slug>`).\n- Vocabulary types: one node kind with text fields `name` + `slug`.\n- `source` -> generated entries instead of stored children: {kind:'query', editable:[knobs an entry may change], defaults:{page_type, order, limit, …}} | {kind:'system', name: breadcrumbs|children|siblings|page_terms|term_pages} | {kind:'plugin', name}.\n- Mega menu: root.allow [\"column\"]; `column` {fields:[heading text], children:{name:\"links\", allow:[\"link\",\"news\"]}}; `link` {fields:[label text*, link link*], current_from:\"link\"}; `news` {fields:[heading text], source:{kind:\"query\", editable:[\"limit\"], defaults:{page_type:\"news\", order:\"published_desc\", limit:3}}} (`*` = required:true).\n- Reserved names: id, node, index, depth, first, last, items, page, site_text, recurse, is_*, has_*, count_*.\n- Changes are checked against every list of the type: a new required field needs a `default`; removing a kind/field with values is refused -> `dropValues:true` only if the operator agreed.\n- `expectedVersion` (from `list_list_types`) guards concurrent changes.",
|
|
7558
7625
|
"inputSchema": {
|
|
7559
7626
|
"type": "object",
|
|
7560
7627
|
"additionalProperties": false,
|