@webiny/mcp 0.0.0-unstable.f6dc066313

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 (47) hide show
  1. package/Extension.d.ts +2 -0
  2. package/Extension.js +11 -0
  3. package/Extension.js.map +1 -0
  4. package/LICENSE +21 -0
  5. package/README.md +11 -0
  6. package/agents/claude.d.ts +15 -0
  7. package/agents/claude.js +33 -0
  8. package/agents/claude.js.map +1 -0
  9. package/agents/cline.d.ts +17 -0
  10. package/agents/cline.js +29 -0
  11. package/agents/cline.js.map +1 -0
  12. package/agents/copilot.d.ts +17 -0
  13. package/agents/copilot.js +64 -0
  14. package/agents/copilot.js.map +1 -0
  15. package/agents/cursor.d.ts +15 -0
  16. package/agents/cursor.js +33 -0
  17. package/agents/cursor.js.map +1 -0
  18. package/agents/instructions.d.ts +7 -0
  19. package/agents/instructions.js +13 -0
  20. package/agents/instructions.js.map +1 -0
  21. package/agents/shared.d.ts +41 -0
  22. package/agents/shared.js +124 -0
  23. package/agents/shared.js.map +1 -0
  24. package/agents/windsurf.d.ts +15 -0
  25. package/agents/windsurf.js +33 -0
  26. package/agents/windsurf.js.map +1 -0
  27. package/cli/ConfigureMcp.d.ts +15 -0
  28. package/cli/ConfigureMcp.js +57 -0
  29. package/cli/ConfigureMcp.js.map +1 -0
  30. package/cli/McpServer.d.ts +12 -0
  31. package/cli/McpServer.js +239 -0
  32. package/cli/McpServer.js.map +1 -0
  33. package/index.d.ts +1 -0
  34. package/index.js +3 -0
  35. package/index.js.map +1 -0
  36. package/package.json +49 -0
  37. package/skills/admin-ui-extensions/SKILL.md +267 -0
  38. package/skills/cli-extensions/SKILL.md +133 -0
  39. package/skills/content-models/SKILL.md +306 -0
  40. package/skills/custom-graphql-api/SKILL.md +199 -0
  41. package/skills/dependency-injection/SKILL.md +252 -0
  42. package/skills/infrastructure-extensions/SKILL.md +192 -0
  43. package/skills/lifecycle-events/SKILL.md +203 -0
  44. package/skills/local-development/SKILL.md +245 -0
  45. package/skills/project-structure/SKILL.md +156 -0
  46. package/skills/webiny-sdk/SKILL.md +271 -0
  47. package/skills/website-builder/SKILL.md +384 -0
@@ -0,0 +1,384 @@
1
+ ---
2
+ name: webiny-website-builder
3
+ context: webiny-extensions
4
+ description: >
5
+ Building Website Builder editor components, theming, and CMS integration using
6
+ @webiny/website-builder-nextjs. Use this skill when the developer wants to create editor
7
+ components for the Website Builder, register components with createComponent, define
8
+ configurable inputs (text, number, boolean, color, select, file, slot, lexical),
9
+ set up component groups, customize the theme (CSS variables, createTheme, Tailwind bridge,
10
+ fonts), build Server Components that fetch CMS data, or understand the WB architecture
11
+ (Admin iframe + Next.js). Also use for anything related to the Website Builder starter kit.
12
+ ---
13
+
14
+ # Website Builder
15
+
16
+ ## TL;DR
17
+
18
+ The Webiny Website Builder uses a unique architecture: the Admin editor loads your Next.js app inside an iframe. All component code and styles live in your Next.js project -- Webiny only stores the page structure (which components and what input values). You build editor components with `@webiny/website-builder-nextjs`, register them via `createComponent()`, define configurable inputs, and manage theming through CSS custom properties and `createTheme()`.
19
+
20
+ ## Architecture
21
+
22
+ ```
23
+ +----------------------------------------------------------+
24
+ | Webiny Admin |
25
+ | +----------------------------------------------------+ |
26
+ | | Website Builder Editor | |
27
+ | | | |
28
+ | | sidebar +------------------------------+ | |
29
+ | | (inputs) | your Next.js app (iframe) | | |
30
+ | | | real components | | |
31
+ | | | real styles | | |
32
+ | | +------------------------------+ | |
33
+ | +----------------------------------------------------+ |
34
+ +----------------------------------------------------------+
35
+ postMessage (SDK)
36
+ +----------------------------------------------------------+
37
+ | Your Next.js App (running separately) |
38
+ | @webiny/website-builder-nextjs SDK installed |
39
+ +----------------------------------------------------------+
40
+ ```
41
+
42
+ Key implications:
43
+ - **No style clashes** -- your components, your styles, full ownership
44
+ - **Genuine WYSIWYG** -- editors see your real app, not a simulation
45
+ - **Framework-owned code** -- all React components live in your Next.js repo
46
+
47
+ ## Setup
48
+
49
+ ### Starter Kit
50
+
51
+ ```bash
52
+ git clone https://github.com/webiny/website-builder-nextjs.git my-website
53
+ cd my-website
54
+ npm install
55
+ ```
56
+
57
+ Ensure `@webiny/website-builder-nextjs` and `@webiny/sdk` versions in `package.json` match your Webiny version (`yarn webiny --version` in your Webiny project).
58
+
59
+ ### Environment Variables
60
+
61
+ ```dotenv
62
+ # .env
63
+ NEXT_PUBLIC_WEBSITE_BUILDER_API_KEY=your_wb_api_key
64
+ NEXT_PUBLIC_WEBSITE_BUILDER_API_HOST=https://your-cloudfront-url.cloudfront.net
65
+ NEXT_PUBLIC_WEBSITE_BUILDER_ADMIN_HOST=http://localhost:3001
66
+ NEXT_PUBLIC_WEBSITE_BUILDER_API_TENANT=root
67
+ ```
68
+
69
+ ## Editor Components
70
+
71
+ An editor component has two parts:
72
+ 1. **React component** -- renders the UI, receives configured values via `inputs` prop
73
+ 2. **Manifest** -- metadata (name, label, group, inputs) that tells the editor about the component
74
+
75
+ ### Creating a Component
76
+
77
+ ```tsx
78
+ // src/editorComponents/Banner.tsx
79
+ import React from "react";
80
+ import { ComponentProps } from "@webiny/website-builder-nextjs";
81
+
82
+ interface BannerInputs {
83
+ headline: string;
84
+ ctaLabel: string;
85
+ ctaUrl: string;
86
+ }
87
+
88
+ export function Banner({ inputs: { headline, ctaLabel, ctaUrl } }: ComponentProps<BannerInputs>) {
89
+ return (
90
+ <div className="bg-primary py-12 px-6 text-center text-white">
91
+ <h2 className="text-3xl font-bold mb-4">{headline}</h2>
92
+ {ctaLabel && ctaUrl && (
93
+ <a
94
+ href={ctaUrl}
95
+ className="inline-block bg-white text-primary font-semibold px-6 py-3 rounded-md"
96
+ >
97
+ {ctaLabel}
98
+ </a>
99
+ )}
100
+ </div>
101
+ );
102
+ }
103
+ ```
104
+
105
+ ### Registering Components
106
+
107
+ The `editorComponents` array must be in a `"use client"` file:
108
+
109
+ ```tsx
110
+ // src/editorComponents/index.tsx
111
+ "use client";
112
+ import { createComponent, createTextInput } from "@webiny/website-builder-nextjs";
113
+ import { Banner } from "./Banner";
114
+
115
+ export const editorComponents = [
116
+ createComponent(Banner, {
117
+ name: "Custom/Banner",
118
+ label: "Banner",
119
+ group: "custom",
120
+ inputs: [
121
+ createTextInput({
122
+ name: "headline",
123
+ label: "Headline",
124
+ description: "The main headline text.",
125
+ defaultValue: "Ready to get started?"
126
+ }),
127
+ createTextInput({
128
+ name: "ctaLabel",
129
+ label: "Button Label",
130
+ defaultValue: "Get started"
131
+ }),
132
+ createTextInput({
133
+ name: "ctaUrl",
134
+ label: "Button URL",
135
+ defaultValue: "/"
136
+ })
137
+ ]
138
+ })
139
+ ];
140
+ ```
141
+
142
+ **Important:** The `"use client"` directive is required because component registration communicates with the editor via the browser. However, components imported here can still be Server Components if they don't have their own `"use client"` directive.
143
+
144
+ ### Component Name Convention
145
+
146
+ Use a namespaced string: `"YourNamespace/ComponentName"`. Component names are stored in page documents -- treat them as **stable identifiers**; renaming breaks existing pages.
147
+
148
+ ## Input Types
149
+
150
+ | Factory Function | Use Case |
151
+ |---|---|
152
+ | `createTextInput` | Single-line text, URLs, labels |
153
+ | `createLongTextInput` | Multi-line text |
154
+ | `createNumberInput` | Numeric values |
155
+ | `createBooleanInput` | Toggle / checkbox |
156
+ | `createColorInput` | Color picker |
157
+ | `createDateInput` | Date / date-time picker |
158
+ | `createSelectInput` | Dropdown with predefined options |
159
+ | `createRadioInput` | Radio button group |
160
+ | `createTagsInput` | List of tags |
161
+ | `createObjectInput` | Nested object (group of sub-inputs) |
162
+ | `createLexicalInput` | Rich text (Lexical editor) |
163
+ | `createFileInput` | File / media picker |
164
+ | `createSlotInput` | Slot for nesting other components |
165
+
166
+ Each factory accepts: `name`, `label`, `description`, `defaultValue`, and type-specific options.
167
+
168
+ ## Component Groups
169
+
170
+ Groups organize the editor's component palette:
171
+
172
+ ```typescript
173
+ // src/contentSdk/groups.ts
174
+ import { registerComponentGroup, type ComponentManifest } from "@webiny/website-builder-nextjs";
175
+
176
+ export const registerComponentGroups = () => {
177
+ registerComponentGroup({
178
+ name: "basic",
179
+ label: "Basic",
180
+ description: "Components for simple content creation"
181
+ });
182
+ registerComponentGroup({
183
+ name: "custom",
184
+ label: "Custom",
185
+ description: "Assorted custom components",
186
+ filter: (component: ComponentManifest) => !component.group
187
+ });
188
+ };
189
+ ```
190
+
191
+ The `filter` option creates a catch-all group for components without an explicit `group`.
192
+
193
+ ## Theming
194
+
195
+ The theme system has three files that work together:
196
+
197
+ ### 1. `theme.css` -- CSS Custom Properties
198
+
199
+ ```css
200
+ /* src/theme/theme.css */
201
+ @import "@webiny/website-builder-nextjs/lexical.css";
202
+
203
+ :root {
204
+ --wb-theme-color-primary: #4632f5;
205
+ --wb-theme-color-secondary: #00ccb0;
206
+ --wb-theme-color-background: #ffffff;
207
+ --wb-theme-color-surface: #f9f9f9;
208
+ --wb-theme-color-text-base: #0a0a0a;
209
+ --wb-theme-color-text-muted: #6b7280;
210
+ --wb-theme-color-border: #e5e7eb;
211
+ --wb-theme-font-family: "Inter", sans-serif;
212
+ }
213
+
214
+ .wb-heading-1 {
215
+ font-weight: 700;
216
+ line-height: 1.2;
217
+ font-size: clamp(2rem, 1.5rem + 1.5vw, 3rem);
218
+ }
219
+
220
+ .wb-paragraph-1 {
221
+ font-weight: 400;
222
+ line-height: 1.6;
223
+ font-size: clamp(0.95rem, 0.9rem + 0.25vw, 1rem);
224
+ }
225
+ ```
226
+
227
+ ### 2. `theme.ts` -- Theme Registration
228
+
229
+ ```typescript
230
+ // src/theme/theme.ts
231
+ import { createTheme } from "@webiny/website-builder-nextjs";
232
+
233
+ declare const __THEME_CSS__: string;
234
+ export const css = __THEME_CSS__;
235
+
236
+ export const theme = createTheme({
237
+ css,
238
+ fonts: ["https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap"],
239
+ colors: [
240
+ { id: "color-primary", label: "Primary", value: "var(--wb-theme-color-primary)" },
241
+ { id: "color-secondary", label: "Secondary", value: "var(--wb-theme-color-secondary)" },
242
+ { id: "color-background", label: "Background", value: "var(--wb-theme-color-background)" },
243
+ { id: "color-text-base", label: "Text", value: "var(--wb-theme-color-text-base)" }
244
+ ],
245
+ typography: {
246
+ headings: [
247
+ { id: "heading1", label: "Heading 1", tag: "h1", className: "wb-heading-1" }
248
+ ],
249
+ paragraphs: [
250
+ { id: "paragraph1", label: "Paragraph 1", tag: "p", className: "wb-paragraph-1" }
251
+ ],
252
+ quotes: [
253
+ { id: "quote", label: "Quote", tag: "blockquote", className: "wb-blockquote-1" }
254
+ ],
255
+ lists: [
256
+ { id: "list1", label: "List 1", tag: "ul", className: "wb-unordered-list-1" }
257
+ ]
258
+ }
259
+ });
260
+ ```
261
+
262
+ - `colors` populates the editor's color picker
263
+ - `typography` populates the editor's typography toolbar
264
+ - `fonts` injects fonts into the editor iframe
265
+
266
+ ### 3. `tailwind.css` -- Tailwind Bridge
267
+
268
+ ```css
269
+ /* src/theme/tailwind.css */
270
+ @import "tailwindcss";
271
+
272
+ @theme inline {
273
+ --font-sans: InterVariable, sans-serif;
274
+ --color-primary: var(--wb-theme-color-primary);
275
+ --color-secondary: var(--wb-theme-color-secondary);
276
+ --color-text-base: var(--wb-theme-color-text-base);
277
+ }
278
+ ```
279
+
280
+ This bridges WB CSS variables to Tailwind tokens, enabling `bg-primary`, `text-primary`, etc. in your components.
281
+
282
+ ### Changing Fonts (4 Files)
283
+
284
+ When switching fonts, update all four places:
285
+
286
+ | File | What to Update |
287
+ |---|---|
288
+ | `src/app/layout.tsx` | Font import and config (e.g., `import { Geist } from "next/font/google"`) |
289
+ | `src/theme/tailwind.css` | `--font-sans` token |
290
+ | `src/theme/theme.css` | `--wb-theme-font-family` variable |
291
+ | `src/theme/theme.ts` | `fonts` array URL (must include same weight range as layout.tsx) |
292
+
293
+ ## Server Components Fetching CMS Data
294
+
295
+ Build editor components that fetch data from the Headless CMS at render time:
296
+
297
+ ```tsx
298
+ // src/editorComponents/ProductListing.tsx
299
+ import React from "react";
300
+ import { ComponentProps } from "@webiny/website-builder-nextjs";
301
+ import { sdk } from "@/lib/webiny";
302
+ import type { Product } from "@/lib/types";
303
+ import type { CmsEntryData } from "@webiny/sdk";
304
+
305
+ interface ProductListingInputs {
306
+ heading: string;
307
+ limit: string;
308
+ }
309
+
310
+ export async function ProductListing({
311
+ inputs: { heading, limit }
312
+ }: ComponentProps<ProductListingInputs>) {
313
+ const parsedLimit = parseInt(limit, 10) || 6;
314
+
315
+ const result = await sdk.cms.listEntries<Product>({
316
+ modelId: "product",
317
+ limit: parsedLimit,
318
+ sort: ["values.name_ASC"]
319
+ });
320
+
321
+ if (!result.isOk()) {
322
+ return <div className="text-red-600">Failed to load products: {result.error.message}</div>;
323
+ }
324
+
325
+ const products: CmsEntryData<Product>[] = result.value.data;
326
+
327
+ return (
328
+ <section className="py-12 px-6">
329
+ {heading && <h2 className="text-3xl font-bold text-center mb-8">{heading}</h2>}
330
+ <ul className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3 max-w-5xl mx-auto">
331
+ {products.map(product => (
332
+ <li key={product.id} className="border rounded-lg p-6">
333
+ <h3 className="text-xl font-semibold">{product.values.name}</h3>
334
+ <p className="text-lg font-bold mt-2">${product.values.price.toFixed(2)}</p>
335
+ </li>
336
+ ))}
337
+ </ul>
338
+ </section>
339
+ );
340
+ }
341
+ ```
342
+
343
+ Register it (async Server Components work even though `index.tsx` is `"use client"`):
344
+
345
+ ```tsx
346
+ createComponent(ProductListing, {
347
+ name: "Custom/ProductListing",
348
+ label: "Product Listing",
349
+ inputs: [
350
+ createTextInput({ name: "heading", label: "Section Heading", defaultValue: "Our Products" }),
351
+ createTextInput({ name: "limit", label: "Number of products", defaultValue: "6" })
352
+ ]
353
+ })
354
+ ```
355
+
356
+ To use the Headless CMS SDK, initialize it in `src/lib/webiny.ts` with a **Read API** key (see the `webiny-sdk` skill).
357
+
358
+ ## Data Flow
359
+
360
+ ```
361
+ Editor -> saves page document to Webiny API
362
+ (document: component name + input values)
363
+
364
+ Next.js request/build
365
+ -> contentSdk.getPage("/slug") -> returns page document
366
+ -> DocumentRenderer matches component name to React component
367
+ -> Component renders (Server Component may fetch CMS data)
368
+ ```
369
+
370
+ ## Quick Reference
371
+
372
+ ```
373
+ SDK package: @webiny/website-builder-nextjs
374
+ Component type: import { ComponentProps } from "@webiny/website-builder-nextjs";
375
+ Registration: createComponent(ReactComponent, { name, label, inputs })
376
+ Input factories: createTextInput, createNumberInput, createBooleanInput, etc.
377
+ Theme: createTheme({ css, fonts, colors, typography })
378
+ Groups: registerComponentGroup({ name, label, description })
379
+ ```
380
+
381
+ ## Related Skills
382
+
383
+ - `webiny-sdk` -- Using the Headless CMS SDK inside Website Builder components
384
+ - `project-structure` -- Webiny project setup and extension registration