@kywi-software/mcp 0.11.0 → 0.12.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.
package/AGENT-PATTERNS.md CHANGED
@@ -76,7 +76,7 @@ the full proposal — ten minutes of sign-off beats re-entering fifty nodes.
76
76
  | Hardcode a list (testimonials, logos, posts, products, team) | Folder of nodes + a Feed + the Feed Display module (§1) |
77
77
  | Create one-off pages with identical field shapes | A custom content type + one node per item (§2) |
78
78
  | Filter/group content by topic, industry, audience | Categories & tags, queried by feeds (§3) |
79
- | Copy-paste a CTA/banner/snippet across pages | Save it as a reusable component (§4) |
79
+ | Copy-paste a CTA/banner/snippet across pages | Save it as a reusable component — linked, so one edit updates them all (§4) |
80
80
  | Write page sections as JSX | Build them as layout sections/modules the owner can edit (§5) |
81
81
  | Build a page as one column of full-width headings and paragraphs | Compose: section bands, columns, object modules (§5) |
82
82
  | Put a custom module's editable copy in a `json` prop | One `text`/`textarea`/`richText` prop per field the owner edits (§5) |
@@ -179,14 +179,99 @@ Anything designed once and used on multiple pages — CTA bands, promo banners,
179
179
  newsletter signup blocks, campaign snippets, "as seen in" strips — should be a
180
180
  **reusable component**, not copy-pasted sections.
181
181
 
182
- - In the layout editor, select the module and **Save as Component**; insert it
183
- elsewhere from the component picker. Placed instances are **live
184
- references**: editing the source component updates every page that uses it.
185
- - **Detach** an instance when a page genuinely needs a one-off variant it
186
- becomes an independent copy from that point on.
187
- - Rule of thumb: the second time you paste the same section, stop and make it
188
- a component. The owner should be able to update the sitewide CTA in one
189
- place, ten minutes before their webinar.
182
+ A component is a **live source**, not a snapshot. Every page that places one
183
+ holds a *link* to it (a `componentId` on the node), and the link is resolved on
184
+ every request so writing a new definition changes every page that uses it
185
+ immediately, published pages included, with nothing to re-publish. That is the
186
+ whole point, and it is also the thing to be careful with.
187
+
188
+ **What can be one.** A single module, a whole section (band), or a personalized /
189
+ A-B tested band with its variants intact — the three `type` values are `module`,
190
+ `section` and `variantContainer`. A band's variants travel with it; which arm a
191
+ visitor sees is still decided per request, per placement, so the same personalized
192
+ component can sit on five pages and target correctly on each.
193
+
194
+ **In the editors** (front-of-site overlay or the admin Layout tab): select the
195
+ module, section or band → **Save as component** → name it. The selection is
196
+ replaced in place by a linked instance, marked with an outline and a pill naming
197
+ the component. Place it again from the section picker's *Components* rows.
198
+
199
+ **Editing a linked instance ends in a question.** There are no per-prop overrides
200
+ in v1: an instance renders its component exactly. So when you edit one and save,
201
+ Kywi asks, naming the blast radius ("updates 3 instances across 2 pages, including
202
+ published"):
203
+
204
+ - **Save and update all instances** — the edit becomes the component. Every
205
+ instance everywhere follows it, live.
206
+ - **Save to this page only** — this instance *detaches*: it keeps the edit as its
207
+ own independent content and stops following the component. Everything else is
208
+ untouched.
209
+
210
+ **Rule of thumb:** the second time you paste the same section, stop and make it a
211
+ component. The owner should be able to update the sitewide CTA in one place, ten
212
+ minutes before their webinar.
213
+
214
+ **Managing them:** *Components* in the admin nav is the library — every component
215
+ with the number of pages using it, rename, an editing canvas for the definition,
216
+ and delete. Deleting **detaches every instance first**: each page keeps rendering
217
+ exactly what it rendered, as its own copy, and stops following.
218
+
219
+ ### Components over the API
220
+
221
+ The admin UI is one client; the endpoints are the contract. `siteId` is optional
222
+ and defaults to the resolved site — components are **per-site** in v1, and
223
+ per-site authorization applies.
224
+
225
+ 1. `POST /api/v1/components` — `{ name, type, definition, moduleType?, description? }`.
226
+ The `definition` is the node itself: a `section` component stores the whole
227
+ `LayoutSection`, a `variantContainer` the whole container, a `module` component
228
+ stores `{ props, style }` and names its `moduleType`.
229
+ 2. **Place it** by writing a layout that carries the link. There is no separate
230
+ "insert" endpoint: `PUT /api/v1/content/:type/:id/layout` with the definition's
231
+ own shape plus `componentId` on the node, giving the placement a fresh `id` of
232
+ its own. The node's inline content is the *fallback copy* — what renders if the
233
+ component ever stops resolving — so write the definition's content there, not a
234
+ placeholder.
235
+
236
+ **An `ab_test` placement must mint its own `experimentId`.** A
237
+ `variantContainer` definition normally carries an `experimentId` — the one the
238
+ band had on the page it was saved from — because `mode: 'ab_test'` without one
239
+ is invalid, so it cannot simply be left out of the definition. A placement that
240
+ names no binding of its own **inherits the definition's**. Place that component
241
+ on three pages and all three arms report into a *single* experiment run; a
242
+ `winnerId` that travels the same way locks every placement to a finished test,
243
+ permanently serving one arm on pages nobody tested. So when you write an
244
+ `ab_test` placement: set a **fresh `experimentId`** on the placement node (any
245
+ uuid — one run per placement is the whole model) and **never copy `winnerId`**.
246
+ The editors do exactly this (`buildConnectedVariantContainerNode`), and a
247
+ definition saved from an editor carries no `winnerId` at all; a definition
248
+ POSTed straight over the API can, so read what you are placing. A
249
+ `personalization` container has no binding and needs none.
250
+ 3. `GET /api/v1/components/:id/usage` — where it is placed (`instances`, `pages`,
251
+ the page ids and node ids, and trashed pages counted separately). This is the
252
+ blast radius; read it *before* changing a definition.
253
+ 4. `PUT /api/v1/components/:id` — a body with `definition` **is the propagation
254
+ write**: every linked instance renders the new definition on its next request.
255
+ A body with only `name` / `description` is a rename and changes nothing any page
256
+ renders.
257
+ 5. `POST /api/v1/components/:id/detach-all` — materialize the definition into every
258
+ page that links it and drop the links; each page keeps rendering identically.
259
+ 6. `DELETE /api/v1/components/:id` — refuses (409) while instances exist; add
260
+ `?detachAll=1` to detach-then-delete. `GET /api/v1/components?withUsage=1` folds
261
+ the counts into a list, in one read.
262
+
263
+ **Two refusals to design around.** A component definition may not link to another
264
+ component (one level only, deliberately: a nested link is invisible to usage counts
265
+ and the delete gate, so the editors *materialize* an inner component when you save
266
+ a section that contains one — the inner instance stops following its own source, and
267
+ the dialog says so). And a stored layout that a live layout could not hold is
268
+ rejected at the door, because detaching would copy it into every page that links it.
269
+
270
+ **Component writes bypass approvals in v1.** They are not routed through
271
+ changesets or the review workflow — a `PUT` with a definition is live on publish
272
+ pages the moment it returns. On a site with an editorial workflow, treat a
273
+ definition write as a publish, not a draft: no draft, schedule or review step
274
+ holds it back. Changeset integration is a follow-up.
190
275
 
191
276
  ## 5. Page layouts & modules — not hardcoded JSX
192
277
 
@@ -588,7 +673,8 @@ early, so ask at scoping time.
588
673
  - Creating types and entering content before the owner signed off on a
589
674
  content model.
590
675
  - A hardcoded array of testimonials/logos/posts in a page component.
591
- - The same CTA JSX pasted on four pages.
676
+ - The same CTA JSX pasted on four pages — or the same section duplicated on four
677
+ pages in the editor, which the owner then has to update four times (§4).
592
678
  - A `<form>` that POSTs to a hand-rolled route (or nowhere).
593
679
  - Marketing imagery in `/public`.
594
680
  - A "blog" that is a folder of `.mdx` files the owner can't edit.
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/site/server.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAEnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAYjD;;;GAGG;AACH,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,SAAS,EACjB,GAAG,EAAE,YAAY,EACjB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC,CA8CjB;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,aAAa,GAAG,SAAS,CA8BpE"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/site/server.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAEnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAajD;;;GAGG;AACH,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,SAAS,EACjB,GAAG,EAAE,YAAY,EACjB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC,CA8CjB;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,aAAa,GAAG,SAAS,CAiCpE"}
@@ -7,6 +7,7 @@ import { registerModuleTypesTool } from '../module-types.js';
7
7
  import { registerContentTools } from './tools/content.js';
8
8
  import { registerLayoutTools } from './tools/layout.js';
9
9
  import { registerFeedTools } from './tools/feeds.js';
10
+ import { registerComponentTools } from './tools/components.js';
10
11
  import { registerMenuTools } from './tools/menus.js';
11
12
  import { registerSearchTools } from './tools/search.js';
12
13
  import { registerMediaTools } from './tools/media.js';
@@ -69,6 +70,9 @@ export function createSiteMcpServer(config) {
69
70
  registerContentTools(server, sdk, config.baseUrl, config.apiKey);
70
71
  registerLayoutTools(server, sdk);
71
72
  registerFeedTools(server, sdk);
73
+ // Reusable components: discovery only — see tools/components.ts for why there is
74
+ // no write tool.
75
+ registerComponentTools(server, sdk);
72
76
  registerMenuTools(server, sdk);
73
77
  registerSearchTools(server, sdk);
74
78
  registerMediaTools(server, sdk);
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/site/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AACnE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAGlE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AACrD,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAA;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAEpD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,MAAiB,EACjB,GAAiB,EACjB,OAAe;IAEf,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,cAAc,CAAC,EAAE,OAAO,EAAE,CAAC,CAAA;QAC5C,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,GAAG,CAIpB,uBAAuB,CAAC,CAAA;QAE9B,IAAI,OAAO,IAAK,GAA+B;YAAE,OAAO,CAAC,CAAA;QAEzD,IAAI,KAAK,GAAG,CAAC,CAAA;QACb,KAAK,MAAM,EAAE,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;YAC1B,MAAM,YAAY,GAAiC,EAAE,CAAA;YACrD,KAAK,MAAM,KAAK,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC;gBAC9B,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,QAAQ;oBACvC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC;oBAClC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;YACjD,CAAC;YAED,MAAM,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE;gBACvC,WAAW,EAAE,gBAAgB,EAAE,CAAC,KAAK,EAAE;gBACvC,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC;aACpC,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;gBAChB,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,IAA+B,CAAC,CAAA;gBAC/E,OAAO,UAAU,CAAC,IAAI,CAAC,CAAA;YACzB,CAAC,CAAC,CAAA;YAEF,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE;gBACrC,WAAW,EAAE,QAAQ,EAAE,CAAC,KAAK,UAAU;gBACvC,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;oBACpB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;oBACjC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;oBAClC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;iBAC9B,CAAC;aACH,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;gBAChB,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,CAAA;gBAC/D,OAAO,UAAU,CAAC,MAAM,CAAC,CAAA;YAC3B,CAAC,CAAC,CAAA;YAEF,KAAK,IAAI,CAAC,CAAA;QACZ,CAAC;QACD,OAAO,KAAK,CAAA;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,CAAA;IACV,CAAC;AACH,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAqB;IACvD,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B,EAAE,IAAI,EAAE,yBAAyB,EAAE,OAAO,EAAE,OAAO,EAAE,EACrD,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,CAChC,CAAA;IAED,MAAM,GAAG,GAAG,aAAa,CAAC;QACxB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,MAAM,EAAE,MAAM,CAAC,MAAM;KACtB,CAAC,CAAA;IAEF,wEAAwE;IACxE,oBAAoB,CAAC,MAAM,CAAC,CAAA;IAC5B,yEAAyE;IACzE,iEAAiE;IACjE,uBAAuB,CAAC,MAAM,CAAC,CAAA;IAC/B,oBAAoB,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;IAChE,mBAAmB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAChC,iBAAiB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC9B,iBAAiB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC9B,mBAAmB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAChC,kBAAkB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC/B,iBAAiB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAE9B,uFAAuF;IACvF,mCAAmC;IACnC,+CAA+C;IAC/C,iEAAiE;IAEjE,OAAO,MAAM,CAAA;AACf,CAAC"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/site/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AACnE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAGlE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AACrD,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAA;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACpD,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAA;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAEpD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,MAAiB,EACjB,GAAiB,EACjB,OAAe;IAEf,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,cAAc,CAAC,EAAE,OAAO,EAAE,CAAC,CAAA;QAC5C,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,GAAG,CAIpB,uBAAuB,CAAC,CAAA;QAE9B,IAAI,OAAO,IAAK,GAA+B;YAAE,OAAO,CAAC,CAAA;QAEzD,IAAI,KAAK,GAAG,CAAC,CAAA;QACb,KAAK,MAAM,EAAE,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;YAC1B,MAAM,YAAY,GAAiC,EAAE,CAAA;YACrD,KAAK,MAAM,KAAK,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC;gBAC9B,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,QAAQ;oBACvC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC;oBAClC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;YACjD,CAAC;YAED,MAAM,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE;gBACvC,WAAW,EAAE,gBAAgB,EAAE,CAAC,KAAK,EAAE;gBACvC,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC;aACpC,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;gBAChB,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,IAA+B,CAAC,CAAA;gBAC/E,OAAO,UAAU,CAAC,IAAI,CAAC,CAAA;YACzB,CAAC,CAAC,CAAA;YAEF,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE;gBACrC,WAAW,EAAE,QAAQ,EAAE,CAAC,KAAK,UAAU;gBACvC,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;oBACpB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;oBACjC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;oBAClC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;iBAC9B,CAAC;aACH,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;gBAChB,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,CAAA;gBAC/D,OAAO,UAAU,CAAC,MAAM,CAAC,CAAA;YAC3B,CAAC,CAAC,CAAA;YAEF,KAAK,IAAI,CAAC,CAAA;QACZ,CAAC;QACD,OAAO,KAAK,CAAA;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,CAAA;IACV,CAAC;AACH,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAqB;IACvD,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B,EAAE,IAAI,EAAE,yBAAyB,EAAE,OAAO,EAAE,OAAO,EAAE,EACrD,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,CAChC,CAAA;IAED,MAAM,GAAG,GAAG,aAAa,CAAC;QACxB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,MAAM,EAAE,MAAM,CAAC,MAAM;KACtB,CAAC,CAAA;IAEF,wEAAwE;IACxE,oBAAoB,CAAC,MAAM,CAAC,CAAA;IAC5B,yEAAyE;IACzE,iEAAiE;IACjE,uBAAuB,CAAC,MAAM,CAAC,CAAA;IAC/B,oBAAoB,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;IAChE,mBAAmB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAChC,iBAAiB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC9B,iFAAiF;IACjF,iBAAiB;IACjB,sBAAsB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACnC,iBAAiB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC9B,mBAAmB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAChC,kBAAkB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC/B,iBAAiB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAE9B,uFAAuF;IACvF,mCAAmC;IACnC,+CAA+C;IAC/C,iEAAiE;IAEjE,OAAO,MAAM,CAAA;AACf,CAAC"}
@@ -0,0 +1,35 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { KywiSdkScope } from '@kywi-software/sdk';
3
+ /**
4
+ * Reusable components, for an authoring agent (kywi-cms#147).
5
+ *
6
+ * WHY THIS TOOL EXISTS. A component is placed by writing a layout node that
7
+ * carries its `componentId` — `update_layout` / `add_module` already do the
8
+ * writing. What an agent could not do was find out that a component exists, what
9
+ * it contains, or what its id is, which made the whole feature unreachable over
10
+ * MCP. This is the discovery half, in the same spirit as `list_module_types`:
11
+ * read, cheap, and the thing you call before composing a page.
12
+ *
13
+ * WHY THERE IS NO create/update/delete TOOL HERE. A definition write propagates:
14
+ * every page linking the component renders the new definition on its next request,
15
+ * published pages included, with no draft or approval step in v1. The editors put a
16
+ * named blast radius ("updates 3 instances across 2 pages, including published") in
17
+ * front of a person before doing it. An MCP tool has no equivalent, and a tool that
18
+ * quietly rewrites live pages is not one to add for symmetry's sake — so writes stay
19
+ * on the REST API, where the caller reaches for `GET /components/:id/usage` first.
20
+ * The full recipe (create, place, usage, detach-all, delete) is in
21
+ * `docs/agents/AGENT-PATTERNS.md` §4, which `kywi_patterns` serves.
22
+ */
23
+ export declare function handleListComponents(sdk: KywiSdkScope, args: {
24
+ siteId?: string | undefined;
25
+ type?: string | undefined;
26
+ withUsage?: boolean | undefined;
27
+ }): Promise<{
28
+ content: [{
29
+ type: "text";
30
+ text: string;
31
+ }];
32
+ isError?: undefined;
33
+ }>;
34
+ export declare function registerComponentTools(server: McpServer, sdk: KywiSdkScope): void;
35
+ //# sourceMappingURL=components.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../../../src/site/tools/components.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AACxE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAGtD;;;;;;;;;;;;;;;;;;;GAmBG;AAIH,wBAAsB,oBAAoB,CACxC,GAAG,EAAE,YAAY,EACjB,IAAI,EAAE;IACJ,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACzB,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CAChC;;;;;;GAQF;AAID,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,YAAY,GAAG,IAAI,CAsBjF"}
@@ -0,0 +1,55 @@
1
+ import { z } from 'zod';
2
+ import { textResult } from '../../shared.js';
3
+ /**
4
+ * Reusable components, for an authoring agent (kywi-cms#147).
5
+ *
6
+ * WHY THIS TOOL EXISTS. A component is placed by writing a layout node that
7
+ * carries its `componentId` — `update_layout` / `add_module` already do the
8
+ * writing. What an agent could not do was find out that a component exists, what
9
+ * it contains, or what its id is, which made the whole feature unreachable over
10
+ * MCP. This is the discovery half, in the same spirit as `list_module_types`:
11
+ * read, cheap, and the thing you call before composing a page.
12
+ *
13
+ * WHY THERE IS NO create/update/delete TOOL HERE. A definition write propagates:
14
+ * every page linking the component renders the new definition on its next request,
15
+ * published pages included, with no draft or approval step in v1. The editors put a
16
+ * named blast radius ("updates 3 instances across 2 pages, including published") in
17
+ * front of a person before doing it. An MCP tool has no equivalent, and a tool that
18
+ * quietly rewrites live pages is not one to add for symmetry's sake — so writes stay
19
+ * on the REST API, where the caller reaches for `GET /components/:id/usage` first.
20
+ * The full recipe (create, place, usage, detach-all, delete) is in
21
+ * `docs/agents/AGENT-PATTERNS.md` §4, which `kywi_patterns` serves.
22
+ */
23
+ // ─── Exported handler function (testable without a server) ──────────────────
24
+ export async function handleListComponents(sdk, args) {
25
+ const components = await sdk.components.list({
26
+ siteId: args.siteId,
27
+ type: args.type,
28
+ withUsage: args.withUsage,
29
+ });
30
+ return textResult({ components, total: components.length });
31
+ }
32
+ // ─── Registration ───────────────────────────────────────────────────────────
33
+ export function registerComponentTools(server, sdk) {
34
+ server.registerTool('list_components', {
35
+ description: 'List the site\'s reusable components (saved modules, sections and personalized/A-B bands). ' +
36
+ 'Each row carries its `definition` — the stored node. To PLACE one, write a layout node ' +
37
+ 'shaped like that definition with a fresh `id` of its own plus `componentId: <the id>`; the ' +
38
+ 'inline content is the fallback copy, so keep the definition\'s content there. Every ' +
39
+ 'placement is a live link: whoever edits the component changes every page that uses it, ' +
40
+ 'published pages included. Creating or editing a component is REST-only in v1 (see ' +
41
+ 'kywi_patterns §4) because a definition write has no draft or approval step.',
42
+ inputSchema: {
43
+ siteId: z.string().optional().describe('Site ID (uses the default site if omitted)'),
44
+ type: z
45
+ .enum(['module', 'section', 'variantContainer'])
46
+ .optional()
47
+ .describe('Filter by granularity: a single module, a whole section, or a personalized/A-B band'),
48
+ withUsage: z
49
+ .boolean()
50
+ .optional()
51
+ .describe('Include placement counts per component (instances, pages, trashed instances)'),
52
+ },
53
+ }, async (args) => handleListComponents(sdk, args));
54
+ }
55
+ //# sourceMappingURL=components.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"components.js","sourceRoot":"","sources":["../../../src/site/tools/components.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAE5C;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,+EAA+E;AAE/E,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,GAAiB,EACjB,IAIC;IAED,MAAM,UAAU,GAAG,MAAM,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC;QAC3C,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,SAAS,EAAE,IAAI,CAAC,SAAS;KAC1B,CAAC,CAAA;IACF,OAAO,UAAU,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAA;AAC7D,CAAC;AAED,+EAA+E;AAE/E,MAAM,UAAU,sBAAsB,CAAC,MAAiB,EAAE,GAAiB;IACzE,MAAM,CAAC,YAAY,CAAC,iBAAiB,EAAE;QACrC,WAAW,EACT,6FAA6F;YAC7F,yFAAyF;YACzF,6FAA6F;YAC7F,sFAAsF;YACtF,yFAAyF;YACzF,oFAAoF;YACpF,6EAA6E;QAC/E,WAAW,EAAE;YACX,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,4CAA4C,CAAC;YACpF,IAAI,EAAE,CAAC;iBACJ,IAAI,CAAC,CAAC,QAAQ,EAAE,SAAS,EAAE,kBAAkB,CAAC,CAAC;iBAC/C,QAAQ,EAAE;iBACV,QAAQ,CAAC,qFAAqF,CAAC;YAClG,SAAS,EAAE,CAAC;iBACT,OAAO,EAAE;iBACT,QAAQ,EAAE;iBACV,QAAQ,CAAC,8EAA8E,CAAC;SAC5F;KACF,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,oBAAoB,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAA;AACrD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kywi-software/mcp",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "description": "Model Context Protocol servers for Kywi CMS — a site server (content/nav/media over the REST API) and a developer server (kywi.config.ts scaffolding and mutation).",
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0-only",
@@ -47,8 +47,8 @@
47
47
  "dependencies": {
48
48
  "@modelcontextprotocol/sdk": "^1.12.0",
49
49
  "zod": "^3.25.0",
50
- "@kywi-software/sdk": "0.11.0",
51
- "@kywi-software/core": "0.11.0"
50
+ "@kywi-software/core": "0.12.0",
51
+ "@kywi-software/sdk": "0.12.0"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@types/node": "^20.0.0",