@elementor/editor-canvas 3.35.0-353 → 3.35.0-355

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/dist/index.js CHANGED
@@ -50,7 +50,7 @@ module.exports = __toCommonJS(index_exports);
50
50
  var import_editor_v1_adapters = require("@elementor/editor-v1-adapters");
51
51
  var BREAKPOINTS_SCHEMA_URI = "elementor://breakpoints/list";
52
52
  var initBreakpointsResource = (reg) => {
53
- const { mcpServer } = reg;
53
+ const { mcpServer, sendResourceUpdated } = reg;
54
54
  const getBreakpointsList = () => {
55
55
  const { breakpoints } = window.elementor?.config?.responsive || {};
56
56
  if (!breakpoints) {
@@ -78,7 +78,7 @@ var initBreakpointsResource = (reg) => {
78
78
  return buildResourceResponse();
79
79
  });
80
80
  window.addEventListener((0, import_editor_v1_adapters.v1ReadyEvent)().name, () => {
81
- mcpServer.server.sendResourceUpdated({
81
+ sendResourceUpdated({
82
82
  uri: BREAKPOINTS_SCHEMA_URI,
83
83
  ...buildResourceResponse()
84
84
  });
@@ -93,6 +93,14 @@ var import_editor_styles = require("@elementor/editor-styles");
93
93
  var WIDGET_SCHEMA_URI = "elementor://widgets/schema/{widgetType}";
94
94
  var STYLE_SCHEMA_URI = "elementor://styles/schema/{category}";
95
95
  var BEST_PRACTICES_URI = "elementor://styles/best-practices";
96
+ var checkIfUserHasPro = () => {
97
+ const extendedWindow = window;
98
+ const hasPro = extendedWindow.elementor?.helpers?.hasPro;
99
+ if (typeof hasPro === "function") {
100
+ return hasPro();
101
+ }
102
+ return false;
103
+ };
96
104
  var initWidgetsSchemaResource = (reg) => {
97
105
  const { mcpServer } = reg;
98
106
  mcpServer.resource("styles-best-practices", BEST_PRACTICES_URI, async () => {
@@ -114,7 +122,11 @@ The css string must follow standard CSS syntax, with properties and values separ
114
122
  "styles-schema",
115
123
  new import_editor_mcp.ResourceTemplate(STYLE_SCHEMA_URI, {
116
124
  list: () => {
117
- const categories = [...Object.keys((0, import_editor_styles.getStylesSchema)()), "custom_css"];
125
+ const isPro = checkIfUserHasPro();
126
+ const categories = [...Object.keys((0, import_editor_styles.getStylesSchema)())];
127
+ if (!isPro) {
128
+ categories.push("custom_css");
129
+ }
118
130
  return {
119
131
  resources: categories.map((category) => ({
120
132
  uri: `elementor://styles/schema/${category}`,
@@ -128,7 +140,7 @@ The css string must follow standard CSS syntax, with properties and values separ
128
140
  },
129
141
  async (uri, variables) => {
130
142
  const category = typeof variables.category === "string" ? variables.category : variables.category?.[0];
131
- if (category === "custom_css") {
143
+ if (category === "custom_css" && checkIfUserHasPro()) {
132
144
  return {
133
145
  contents: [
134
146
  {
@@ -160,7 +172,7 @@ The css string must follow standard CSS syntax, with properties and values separ
160
172
  list: () => {
161
173
  const cache = (0, import_editor_elements.getWidgetsCache)() || {};
162
174
  const availableWidgets = Object.keys(cache || {}).filter(
163
- (widgetType) => cache[widgetType]?.atomic_props_schema
175
+ (widgetType) => cache[widgetType]?.atomic_props_schema && cache[widgetType].meta?.llm_support !== false
164
176
  );
165
177
  return {
166
178
  resources: availableWidgets.map((widgetType) => ({
@@ -175,8 +187,9 @@ The css string must follow standard CSS syntax, with properties and values separ
175
187
  },
176
188
  async (uri, variables) => {
177
189
  const widgetType = typeof variables.widgetType === "string" ? variables.widgetType : variables.widgetType?.[0];
178
- const propSchema = (0, import_editor_elements.getWidgetsCache)()?.[widgetType]?.atomic_props_schema;
179
- if (!propSchema) {
190
+ const widgetData = (0, import_editor_elements.getWidgetsCache)()?.[widgetType];
191
+ const propSchema = widgetData?.atomic_props_schema;
192
+ if (!propSchema || !widgetData) {
180
193
  throw new Error(`No prop schema found for element type: ${widgetType}`);
181
194
  }
182
195
  const asJson = Object.fromEntries(
@@ -188,6 +201,24 @@ The css string must follow standard CSS syntax, with properties and values separ
188
201
  import_editor_props.Schema.nonConfigurablePropKeys.forEach((key) => {
189
202
  delete asJson[key];
190
203
  });
204
+ const description = typeof widgetData?.meta?.description === "string" ? widgetData.meta.description : void 0;
205
+ const defaultStyles = {};
206
+ const baseStyleSchema = widgetData?.base_styles;
207
+ if (baseStyleSchema) {
208
+ Object.values(baseStyleSchema).forEach((stylePropType) => {
209
+ stylePropType.variants.forEach((variant) => {
210
+ Object.assign(defaultStyles, variant.props);
211
+ });
212
+ });
213
+ }
214
+ const hasDefaultStyles = Object.keys(defaultStyles).length > 0;
215
+ const llmGuidance = {
216
+ can_have_children: !!widgetData?.meta?.is_container
217
+ };
218
+ if (hasDefaultStyles) {
219
+ llmGuidance.instructions = "These are the default styles applied to the widget. Override only when necessary.";
220
+ llmGuidance.default_styles = defaultStyles;
221
+ }
191
222
  return {
192
223
  contents: [
193
224
  {
@@ -195,7 +226,9 @@ The css string must follow standard CSS syntax, with properties and values separ
195
226
  mimeType: "application/json",
196
227
  text: JSON.stringify({
197
228
  type: "object",
198
- properties: asJson
229
+ properties: asJson,
230
+ description,
231
+ llm_guidance: llmGuidance
199
232
  })
200
233
  }
201
234
  ]
@@ -2062,9 +2095,9 @@ var validateInput = {
2062
2095
  } else if (!import_editor_props5.Schema.isPropKeyConfigurable(propName)) {
2063
2096
  errors.push(`Property "${propName}" is not configurable.`);
2064
2097
  } else {
2065
- const { valid, errorMessages } = import_editor_props5.Schema.validatePropValue(propSchema, propValue);
2098
+ const { valid, jsonSchema } = import_editor_props5.Schema.validatePropValue(propSchema, propValue);
2066
2099
  if (!valid) {
2067
- errors.push(`Invalid property "${propName}": ${errorMessages}`);
2100
+ errors.push(`Invalid property "${propName}". Expected schema: ${jsonSchema}`);
2068
2101
  }
2069
2102
  }
2070
2103
  });
@@ -2126,6 +2159,24 @@ When in doubt between "safe" and "distinctive," choose distinctive - users can a
2126
2159
  Always prefer this tool when the user requires to build a composition of elements, such as cards, heros, or inspired from other pages or HTML compositions.
2127
2160
  Prefer this tool over any other tool for building HTML structure, unless you are specified to use a different tool.
2128
2161
 
2162
+ # **CRITICAL - REQUIRED RESOURCES (Must read before using this tool)**
2163
+ 1. [${WIDGET_SCHEMA_URI}]
2164
+ Required to understand which widgets are available, and what are their configuration schemas.
2165
+ Every widgetType (i.e. e-heading, e-button) that is supported has it's own property schema, that you must follow in order to apply property values correctly.
2166
+ 2. [${STYLE_SCHEMA_URI}]
2167
+ Required to understand the styles schema for the widgets. All widgets share the same styles schema.
2168
+ 3. List of allowed custom tags for building the structure is derived from the list of widgets schema resources.
2169
+
2170
+ # DESIGN QUALITY IMPERATIVE
2171
+ You are generating designs for real users who expect distinctive, intentional aesthetics - NOT generic AI output.
2172
+ **The Core Challenge**: Large language models naturally converge toward statistically common design patterns during generation. This creates predictable, uninspired results that users describe as "AI slop": safe color schemes, default typography hierarchies, minimal contrast, and timid spacing.
2173
+ **Your Mission**: Actively resist distributional convergence by making intentional, distinctive design choices across all aesthetic dimensions. Every design decision should have a clear purpose tied to visual hierarchy, brand personality, or user experience goals.
2174
+ When in doubt between "safe" and "distinctive," choose distinctive - users can always request refinements, but they cannot salvage generic foundations.
2175
+
2176
+ # When to use this tool
2177
+ Always prefer this tool when the user requires to build a composition of elements, such as cards, heros, or inspired from other pages or HTML compositions.
2178
+ Prefer this tool over any other tool for building HTML structure, unless you are specified to use a different tool.
2179
+
2129
2180
  # Instructions
2130
2181
  1. Understand the user requirements carefully.
2131
2182
  2. Build a valid XML structure using only the allowed custom tags provided. For example, if you
@@ -2140,11 +2191,11 @@ Prefer this tool over any other tool for building HTML structure, unless you are
2140
2191
  5. Ensure the XML structure is valid and parsable.
2141
2192
  6. Do not add any attribute nodes, classes, id's, and no text nodes allowed.
2142
2193
  Layout properties, such as margin, padding, align, etc. must be applied using the [${STYLE_SCHEMA_URI}] PropValues.
2143
- 7. Some elements allow nesting of other elements, and most of the DO NOT. The allowed elements that can have nested children are "e-div-block" and "e-flexbox".
2194
+ 7. Some elements allow nesting of other elements, and most of the DO NOT. The allowed elements that can have nested children are "e-tabs", "e-div-block", and "e-flexbox".
2144
2195
  8. Make sure that non-container elements do NOT have any nested elements.
2145
- 9. **CRITICAL - CUSTOM CSS PRIORITY**: Prefer using style schema. Custom CSS is ONLY FOR UNSUPPRTED schema styles.
2196
+ 9. **CRITICAL - CUSTOM CSS USAGE**: ALWAYS Prefer using style schema. Custom CSS is ONLY FOR UNSUPPRTED schema styles.
2146
2197
  ALWAYS PRIORITIZE using the style schema PropValues for styling elements as they provide better user experience in the editor, and UI features for the end-users.
2147
- - Use custom_css only for style attributes that ARE NOT SUPPORTED via the style schema.
2198
+ Use custom_css only for style attributes that ARE NOT SUPPORTED via the style schema AFTER YOU CHECK THE [${STYLE_SCHEMA_URI}].
2148
2199
 
2149
2200
  # DESIGN VECTORS - Concrete Implementation Guidance
2150
2201
 
@@ -2363,10 +2414,8 @@ If unsure about the configuration of a specific property, read the schema resour
2363
2414
 
2364
2415
  # About our widgets
2365
2416
  Most widgets are self-explanatory by their name. Here is some additional information.
2417
+ Check for available llm_guidance property in the widget's schema.
2366
2418
  SVG elements are bound to internal content upload. Avoid usage, unless you have tools to upload SVG content.
2367
- e-div-block - By default is ceneterd aligned and vertically stacked. To modify this, apply style configuration.
2368
- e-flexbox - By default is a flex container with row direction. To modify this, apply style configuration.
2369
-
2370
2419
  When working with containers, do not forget to apply style schema for controlling the layout.
2371
2420
 
2372
2421
 
@@ -2482,21 +2531,27 @@ var initBuildCompositionsTool = (reg) => {
2482
2531
  throw new Error("Failed to parse XML structure: " + errorNode.textContent);
2483
2532
  }
2484
2533
  const children = Array.from(xml.children);
2485
- const iterate = (node, containerElement = documentContainer) => {
2534
+ const iterate = async (node, containerElement = documentContainer, childIndex) => {
2486
2535
  const elementTag = node.tagName;
2487
2536
  if (!widgetsCache[elementTag]) {
2488
2537
  errors.push(new Error(`Unknown widget type: ${elementTag}`));
2489
2538
  }
2490
- const isContainer = elementTag === "e-flexbox" || elementTag === "e-div-block";
2539
+ const CONTAINER_ELEMENTS = Object.values(widgetsCache).filter((widget) => widget.meta?.is_container).map((widget) => widget.elType);
2540
+ const isContainer = CONTAINER_ELEMENTS.includes(elementTag);
2541
+ const parentElType = containerElement.model.get("elType");
2542
+ let targetContainerId = parentElType === "e-tabs" ? containerElement.children?.[1].children?.[childIndex]?.id || containerElement.children?.[1].id : containerElement.id;
2543
+ if (!targetContainerId) {
2544
+ targetContainerId = containerElement.id;
2545
+ }
2491
2546
  const newElement = isContainer ? (0, import_editor_elements8.createElement)({
2492
- containerId: containerElement.id,
2547
+ containerId: targetContainerId,
2493
2548
  model: {
2494
2549
  elType: elementTag,
2495
2550
  id: (0, import_editor_elements8.generateElementId)()
2496
2551
  },
2497
2552
  options: { useHistory: false }
2498
2553
  }) : (0, import_editor_elements8.createElement)({
2499
- containerId: containerElement.id,
2554
+ containerId: targetContainerId,
2500
2555
  model: {
2501
2556
  elType: "widget",
2502
2557
  widgetType: elementTag,
@@ -2536,8 +2591,10 @@ var initBuildCompositionsTool = (reg) => {
2536
2591
  }
2537
2592
  }
2538
2593
  if (isContainer) {
2594
+ let currentChild2 = 0;
2539
2595
  for (const child of node.children) {
2540
- iterate(child, newElement);
2596
+ iterate(child, newElement, currentChild2);
2597
+ currentChild2++;
2541
2598
  }
2542
2599
  } else {
2543
2600
  node.innerHTML = "";
@@ -2546,8 +2603,10 @@ var initBuildCompositionsTool = (reg) => {
2546
2603
  } finally {
2547
2604
  }
2548
2605
  };
2549
- for (const childNode of children) {
2550
- iterate(childNode, documentContainer);
2606
+ let currentChild = 0;
2607
+ for await (const childNode of children) {
2608
+ await iterate(childNode, documentContainer, currentChild);
2609
+ currentChild++;
2551
2610
  try {
2552
2611
  } catch (error) {
2553
2612
  errors.push(error);
@@ -2617,6 +2676,8 @@ When a user requires to change anything in an element, such as updating text, co
2617
2676
  This tool handles elements of type "widget".
2618
2677
  This tool handles styling elements, using the "stylePropertiesToChange" parameter.
2619
2678
 
2679
+ To CLEAR a property (i.e., set it to default or none), provide null as a value.
2680
+
2620
2681
  The element's schema must be known before using this tool.
2621
2682
  The style schema must be known before using this tool.
2622
2683
 
@@ -2810,7 +2871,24 @@ var schema = {
2810
2871
  };
2811
2872
  var outputSchema3 = {
2812
2873
  properties: import_schema5.z.record(import_schema5.z.string(), import_schema5.z.any()).describe("A record mapping PropTypes to their corresponding PropValues"),
2813
- style: import_schema5.z.record(import_schema5.z.string(), import_schema5.z.any()).describe("A record mapping StyleSchema properties to their corresponding PropValues")
2874
+ style: import_schema5.z.record(import_schema5.z.string(), import_schema5.z.any()).describe("A record mapping StyleSchema properties to their corresponding PropValues"),
2875
+ childElements: import_schema5.z.array(
2876
+ import_schema5.z.object({
2877
+ id: import_schema5.z.string(),
2878
+ elementType: import_schema5.z.string(),
2879
+ childElements: import_schema5.z.array(import_schema5.z.any()).describe("An array of child element IDs, when applicable, same structure recursively")
2880
+ })
2881
+ ).describe("An array of child element IDs, when applicable, with recursive structure")
2882
+ };
2883
+ var structuredElements = (element) => {
2884
+ const children = element.children || [];
2885
+ return children.map((child) => {
2886
+ return {
2887
+ id: child.id,
2888
+ elementType: child.model.get("elType") || child.model.get("widgetType") || "unknown",
2889
+ childElements: structuredElements(child)
2890
+ };
2891
+ });
2814
2892
  };
2815
2893
  var initGetElementConfigTool = (reg) => {
2816
2894
  const { addTool } = reg;
@@ -2858,7 +2936,8 @@ var initGetElementConfigTool = (reg) => {
2858
2936
  },
2859
2937
  style: {
2860
2938
  ...stylePropValues
2861
- }
2939
+ },
2940
+ childElements: structuredElements(element)
2862
2941
  };
2863
2942
  }
2864
2943
  });
@@ -2878,6 +2957,7 @@ var initCanvasMcp = (reg) => {
2878
2957
  };
2879
2958
 
2880
2959
  // src/mcp/mcp-description.ts
2960
+ var ELEMENT_SCHEMA_URI = WIDGET_SCHEMA_URI.replace("{widgetType}", "element-schema");
2881
2961
  var mcpDescription = `Canvas MCP
2882
2962
  This MCP enables everything related to creation, configuration, and styling of elements on the Elementor canvas.
2883
2963
 
@@ -2913,11 +2993,53 @@ The tool accepts both the structure, the styling and the configuration of each e
2913
2993
 
2914
2994
  - First step: Retreive the available widgets by listing the [${WIDGET_SCHEMA_URI}] dynamic resource.
2915
2995
  - Second step: decide which elements to create, and their configuration and styles.
2916
- Retrieve the used elements configuration schema from the resource [${WIDGET_SCHEMA_URI}/element-name]
2996
+ Retrieve the used elements configuration schema from the resource [${ELEMENT_SCHEMA_URI}]
2917
2997
  - Third step: define the styles for each element, using the common styles schema from the resource [${STYLE_SCHEMA_URI}]. List the resource to see all available style properties.
2918
2998
  For background and complicated layered styles, you can use "custom_css" property, which is supported only for ELEMENTOR PRO users ONLY.
2919
2999
  The custom css is intented to deal with yet unsupported CSS features that ARE NOT PART OF THE STYLE SCHEMA, to enable PRO users to support new CSS features.
2920
3000
 
3001
+ ## Workflow for build-compositions tool
3002
+ 1. **Parse user requirements** - Undestand what needs to be built (structure, content, styling).
3003
+ 2. ** Check global resources FIRST** - Always check before building:
3004
+ - List \`elementor://global-classes\` to see if the needed global classes already exist.
3005
+ - List \`elementor://global-variables\` to see if the needed global variables already exist.
3006
+ - **Preference**: Use existing global classes and variables over creating new inline styles.
3007
+ 3. **Retreive widget schemas** - For each widget you will use:
3008
+ - List [${WIDGET_SCHEMA_URI}] to see available widgets.
3009
+ - Retrieve configuration schema from [${ELEMENT_SCHEMA_URI}] for each widget to understand required properties.
3010
+ - Understand if a widget is a container (can have children) by checking the "llm_guidance" property in the widget's schema.
3011
+ 4. **Build XML structure** - Create valid XML width configuration-ids:
3012
+ - Every element has unique configuration-id attribute
3013
+ - No text nodes, classes, IDs in XML.
3014
+
3015
+ 5. **Create elementConfig** - For each configuration-id:
3016
+ - Use PropValues with corrent \`$$type\` matching the schema.
3017
+ - **Use global variables** in PropValues where applicable
3018
+
3019
+ 6. **Create stylesConfig** - For each configuration-id:
3020
+ - Use style schema PropValues from [${STYLE_SCHEMA_URI}]
3021
+ - **Priority**: Use style schema PropValues over custom_css
3022
+ - **Use global variables** for colors, sizes, fonts where applicable
3023
+ - **custom_css (PRO Users Only)**: The property appears only for PRO user. The purpose of custom_css is to support new CSS features not yet available in the style schema.
3024
+ The schema supports multiple layers of background, gradients, filters. Prefer NOT USING custom_css.
3025
+ - **Important**: Global classes are applied AFTER building the composition. Once built, apply classes using the "apply-global-class" tool - after completion of building the composition.
3026
+
3027
+ 7. **Validate** - Ensure:
3028
+ - XML structure is valid
3029
+ - All PropValues have corrent \`$$type\`
3030
+ - After building a composition, you can retreive each element configuration using the "get-element-configuration-values" tool to verify correctness, using the IDs returned from the build-composition tool.
3031
+
3032
+ ## Key relationships:
3033
+ - **XML structure**: Defines the hierarchy of elements/widgets
3034
+ - **elementConfig**: Maps configuration-id to widget PropValues
3035
+ - **stylesConfig**: Maps configuration-id to style PropValues
3036
+
3037
+ ## Using global variables example:
3038
+ Existing global variables can be used during composition
3039
+ \`\`\`json
3040
+ { "color": { "$$type": "global-color-variable", "value": "global-variable-id" } }
3041
+ \`\`\`
3042
+
2921
3043
  # Configuring Elements / Adding Style to Elements
2922
3044
  An element configuration can be retrieved using the "get-element-configuration-values" tool.
2923
3045
  Updating an element requires only the UPDATED properties (including in the styles), as Elementor does a MERGE/PATCH operation.
package/dist/index.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
  import { v1ReadyEvent } from "@elementor/editor-v1-adapters";
3
3
  var BREAKPOINTS_SCHEMA_URI = "elementor://breakpoints/list";
4
4
  var initBreakpointsResource = (reg) => {
5
- const { mcpServer } = reg;
5
+ const { mcpServer, sendResourceUpdated } = reg;
6
6
  const getBreakpointsList = () => {
7
7
  const { breakpoints } = window.elementor?.config?.responsive || {};
8
8
  if (!breakpoints) {
@@ -30,7 +30,7 @@ var initBreakpointsResource = (reg) => {
30
30
  return buildResourceResponse();
31
31
  });
32
32
  window.addEventListener(v1ReadyEvent().name, () => {
33
- mcpServer.server.sendResourceUpdated({
33
+ sendResourceUpdated({
34
34
  uri: BREAKPOINTS_SCHEMA_URI,
35
35
  ...buildResourceResponse()
36
36
  });
@@ -47,6 +47,14 @@ import { getStylesSchema } from "@elementor/editor-styles";
47
47
  var WIDGET_SCHEMA_URI = "elementor://widgets/schema/{widgetType}";
48
48
  var STYLE_SCHEMA_URI = "elementor://styles/schema/{category}";
49
49
  var BEST_PRACTICES_URI = "elementor://styles/best-practices";
50
+ var checkIfUserHasPro = () => {
51
+ const extendedWindow = window;
52
+ const hasPro = extendedWindow.elementor?.helpers?.hasPro;
53
+ if (typeof hasPro === "function") {
54
+ return hasPro();
55
+ }
56
+ return false;
57
+ };
50
58
  var initWidgetsSchemaResource = (reg) => {
51
59
  const { mcpServer } = reg;
52
60
  mcpServer.resource("styles-best-practices", BEST_PRACTICES_URI, async () => {
@@ -68,7 +76,11 @@ The css string must follow standard CSS syntax, with properties and values separ
68
76
  "styles-schema",
69
77
  new ResourceTemplate(STYLE_SCHEMA_URI, {
70
78
  list: () => {
71
- const categories = [...Object.keys(getStylesSchema()), "custom_css"];
79
+ const isPro = checkIfUserHasPro();
80
+ const categories = [...Object.keys(getStylesSchema())];
81
+ if (!isPro) {
82
+ categories.push("custom_css");
83
+ }
72
84
  return {
73
85
  resources: categories.map((category) => ({
74
86
  uri: `elementor://styles/schema/${category}`,
@@ -82,7 +94,7 @@ The css string must follow standard CSS syntax, with properties and values separ
82
94
  },
83
95
  async (uri, variables) => {
84
96
  const category = typeof variables.category === "string" ? variables.category : variables.category?.[0];
85
- if (category === "custom_css") {
97
+ if (category === "custom_css" && checkIfUserHasPro()) {
86
98
  return {
87
99
  contents: [
88
100
  {
@@ -114,7 +126,7 @@ The css string must follow standard CSS syntax, with properties and values separ
114
126
  list: () => {
115
127
  const cache = getWidgetsCache() || {};
116
128
  const availableWidgets = Object.keys(cache || {}).filter(
117
- (widgetType) => cache[widgetType]?.atomic_props_schema
129
+ (widgetType) => cache[widgetType]?.atomic_props_schema && cache[widgetType].meta?.llm_support !== false
118
130
  );
119
131
  return {
120
132
  resources: availableWidgets.map((widgetType) => ({
@@ -129,8 +141,9 @@ The css string must follow standard CSS syntax, with properties and values separ
129
141
  },
130
142
  async (uri, variables) => {
131
143
  const widgetType = typeof variables.widgetType === "string" ? variables.widgetType : variables.widgetType?.[0];
132
- const propSchema = getWidgetsCache()?.[widgetType]?.atomic_props_schema;
133
- if (!propSchema) {
144
+ const widgetData = getWidgetsCache()?.[widgetType];
145
+ const propSchema = widgetData?.atomic_props_schema;
146
+ if (!propSchema || !widgetData) {
134
147
  throw new Error(`No prop schema found for element type: ${widgetType}`);
135
148
  }
136
149
  const asJson = Object.fromEntries(
@@ -142,6 +155,24 @@ The css string must follow standard CSS syntax, with properties and values separ
142
155
  Schema.nonConfigurablePropKeys.forEach((key) => {
143
156
  delete asJson[key];
144
157
  });
158
+ const description = typeof widgetData?.meta?.description === "string" ? widgetData.meta.description : void 0;
159
+ const defaultStyles = {};
160
+ const baseStyleSchema = widgetData?.base_styles;
161
+ if (baseStyleSchema) {
162
+ Object.values(baseStyleSchema).forEach((stylePropType) => {
163
+ stylePropType.variants.forEach((variant) => {
164
+ Object.assign(defaultStyles, variant.props);
165
+ });
166
+ });
167
+ }
168
+ const hasDefaultStyles = Object.keys(defaultStyles).length > 0;
169
+ const llmGuidance = {
170
+ can_have_children: !!widgetData?.meta?.is_container
171
+ };
172
+ if (hasDefaultStyles) {
173
+ llmGuidance.instructions = "These are the default styles applied to the widget. Override only when necessary.";
174
+ llmGuidance.default_styles = defaultStyles;
175
+ }
145
176
  return {
146
177
  contents: [
147
178
  {
@@ -149,7 +180,9 @@ The css string must follow standard CSS syntax, with properties and values separ
149
180
  mimeType: "application/json",
150
181
  text: JSON.stringify({
151
182
  type: "object",
152
- properties: asJson
183
+ properties: asJson,
184
+ description,
185
+ llm_guidance: llmGuidance
153
186
  })
154
187
  }
155
188
  ]
@@ -2042,9 +2075,9 @@ var validateInput = {
2042
2075
  } else if (!Schema3.isPropKeyConfigurable(propName)) {
2043
2076
  errors.push(`Property "${propName}" is not configurable.`);
2044
2077
  } else {
2045
- const { valid, errorMessages } = Schema3.validatePropValue(propSchema, propValue);
2078
+ const { valid, jsonSchema } = Schema3.validatePropValue(propSchema, propValue);
2046
2079
  if (!valid) {
2047
- errors.push(`Invalid property "${propName}": ${errorMessages}`);
2080
+ errors.push(`Invalid property "${propName}". Expected schema: ${jsonSchema}`);
2048
2081
  }
2049
2082
  }
2050
2083
  });
@@ -2106,6 +2139,24 @@ When in doubt between "safe" and "distinctive," choose distinctive - users can a
2106
2139
  Always prefer this tool when the user requires to build a composition of elements, such as cards, heros, or inspired from other pages or HTML compositions.
2107
2140
  Prefer this tool over any other tool for building HTML structure, unless you are specified to use a different tool.
2108
2141
 
2142
+ # **CRITICAL - REQUIRED RESOURCES (Must read before using this tool)**
2143
+ 1. [${WIDGET_SCHEMA_URI}]
2144
+ Required to understand which widgets are available, and what are their configuration schemas.
2145
+ Every widgetType (i.e. e-heading, e-button) that is supported has it's own property schema, that you must follow in order to apply property values correctly.
2146
+ 2. [${STYLE_SCHEMA_URI}]
2147
+ Required to understand the styles schema for the widgets. All widgets share the same styles schema.
2148
+ 3. List of allowed custom tags for building the structure is derived from the list of widgets schema resources.
2149
+
2150
+ # DESIGN QUALITY IMPERATIVE
2151
+ You are generating designs for real users who expect distinctive, intentional aesthetics - NOT generic AI output.
2152
+ **The Core Challenge**: Large language models naturally converge toward statistically common design patterns during generation. This creates predictable, uninspired results that users describe as "AI slop": safe color schemes, default typography hierarchies, minimal contrast, and timid spacing.
2153
+ **Your Mission**: Actively resist distributional convergence by making intentional, distinctive design choices across all aesthetic dimensions. Every design decision should have a clear purpose tied to visual hierarchy, brand personality, or user experience goals.
2154
+ When in doubt between "safe" and "distinctive," choose distinctive - users can always request refinements, but they cannot salvage generic foundations.
2155
+
2156
+ # When to use this tool
2157
+ Always prefer this tool when the user requires to build a composition of elements, such as cards, heros, or inspired from other pages or HTML compositions.
2158
+ Prefer this tool over any other tool for building HTML structure, unless you are specified to use a different tool.
2159
+
2109
2160
  # Instructions
2110
2161
  1. Understand the user requirements carefully.
2111
2162
  2. Build a valid XML structure using only the allowed custom tags provided. For example, if you
@@ -2120,11 +2171,11 @@ Prefer this tool over any other tool for building HTML structure, unless you are
2120
2171
  5. Ensure the XML structure is valid and parsable.
2121
2172
  6. Do not add any attribute nodes, classes, id's, and no text nodes allowed.
2122
2173
  Layout properties, such as margin, padding, align, etc. must be applied using the [${STYLE_SCHEMA_URI}] PropValues.
2123
- 7. Some elements allow nesting of other elements, and most of the DO NOT. The allowed elements that can have nested children are "e-div-block" and "e-flexbox".
2174
+ 7. Some elements allow nesting of other elements, and most of the DO NOT. The allowed elements that can have nested children are "e-tabs", "e-div-block", and "e-flexbox".
2124
2175
  8. Make sure that non-container elements do NOT have any nested elements.
2125
- 9. **CRITICAL - CUSTOM CSS PRIORITY**: Prefer using style schema. Custom CSS is ONLY FOR UNSUPPRTED schema styles.
2176
+ 9. **CRITICAL - CUSTOM CSS USAGE**: ALWAYS Prefer using style schema. Custom CSS is ONLY FOR UNSUPPRTED schema styles.
2126
2177
  ALWAYS PRIORITIZE using the style schema PropValues for styling elements as they provide better user experience in the editor, and UI features for the end-users.
2127
- - Use custom_css only for style attributes that ARE NOT SUPPORTED via the style schema.
2178
+ Use custom_css only for style attributes that ARE NOT SUPPORTED via the style schema AFTER YOU CHECK THE [${STYLE_SCHEMA_URI}].
2128
2179
 
2129
2180
  # DESIGN VECTORS - Concrete Implementation Guidance
2130
2181
 
@@ -2343,10 +2394,8 @@ If unsure about the configuration of a specific property, read the schema resour
2343
2394
 
2344
2395
  # About our widgets
2345
2396
  Most widgets are self-explanatory by their name. Here is some additional information.
2397
+ Check for available llm_guidance property in the widget's schema.
2346
2398
  SVG elements are bound to internal content upload. Avoid usage, unless you have tools to upload SVG content.
2347
- e-div-block - By default is ceneterd aligned and vertically stacked. To modify this, apply style configuration.
2348
- e-flexbox - By default is a flex container with row direction. To modify this, apply style configuration.
2349
-
2350
2399
  When working with containers, do not forget to apply style schema for controlling the layout.
2351
2400
 
2352
2401
 
@@ -2462,21 +2511,27 @@ var initBuildCompositionsTool = (reg) => {
2462
2511
  throw new Error("Failed to parse XML structure: " + errorNode.textContent);
2463
2512
  }
2464
2513
  const children = Array.from(xml.children);
2465
- const iterate = (node, containerElement = documentContainer) => {
2514
+ const iterate = async (node, containerElement = documentContainer, childIndex) => {
2466
2515
  const elementTag = node.tagName;
2467
2516
  if (!widgetsCache[elementTag]) {
2468
2517
  errors.push(new Error(`Unknown widget type: ${elementTag}`));
2469
2518
  }
2470
- const isContainer = elementTag === "e-flexbox" || elementTag === "e-div-block";
2519
+ const CONTAINER_ELEMENTS = Object.values(widgetsCache).filter((widget) => widget.meta?.is_container).map((widget) => widget.elType);
2520
+ const isContainer = CONTAINER_ELEMENTS.includes(elementTag);
2521
+ const parentElType = containerElement.model.get("elType");
2522
+ let targetContainerId = parentElType === "e-tabs" ? containerElement.children?.[1].children?.[childIndex]?.id || containerElement.children?.[1].id : containerElement.id;
2523
+ if (!targetContainerId) {
2524
+ targetContainerId = containerElement.id;
2525
+ }
2471
2526
  const newElement = isContainer ? createElement6({
2472
- containerId: containerElement.id,
2527
+ containerId: targetContainerId,
2473
2528
  model: {
2474
2529
  elType: elementTag,
2475
2530
  id: generateElementId()
2476
2531
  },
2477
2532
  options: { useHistory: false }
2478
2533
  }) : createElement6({
2479
- containerId: containerElement.id,
2534
+ containerId: targetContainerId,
2480
2535
  model: {
2481
2536
  elType: "widget",
2482
2537
  widgetType: elementTag,
@@ -2516,8 +2571,10 @@ var initBuildCompositionsTool = (reg) => {
2516
2571
  }
2517
2572
  }
2518
2573
  if (isContainer) {
2574
+ let currentChild2 = 0;
2519
2575
  for (const child of node.children) {
2520
- iterate(child, newElement);
2576
+ iterate(child, newElement, currentChild2);
2577
+ currentChild2++;
2521
2578
  }
2522
2579
  } else {
2523
2580
  node.innerHTML = "";
@@ -2526,8 +2583,10 @@ var initBuildCompositionsTool = (reg) => {
2526
2583
  } finally {
2527
2584
  }
2528
2585
  };
2529
- for (const childNode of children) {
2530
- iterate(childNode, documentContainer);
2586
+ let currentChild = 0;
2587
+ for await (const childNode of children) {
2588
+ await iterate(childNode, documentContainer, currentChild);
2589
+ currentChild++;
2531
2590
  try {
2532
2591
  } catch (error) {
2533
2592
  errors.push(error);
@@ -2597,6 +2656,8 @@ When a user requires to change anything in an element, such as updating text, co
2597
2656
  This tool handles elements of type "widget".
2598
2657
  This tool handles styling elements, using the "stylePropertiesToChange" parameter.
2599
2658
 
2659
+ To CLEAR a property (i.e., set it to default or none), provide null as a value.
2660
+
2600
2661
  The element's schema must be known before using this tool.
2601
2662
  The style schema must be known before using this tool.
2602
2663
 
@@ -2790,7 +2851,24 @@ var schema = {
2790
2851
  };
2791
2852
  var outputSchema3 = {
2792
2853
  properties: z3.record(z3.string(), z3.any()).describe("A record mapping PropTypes to their corresponding PropValues"),
2793
- style: z3.record(z3.string(), z3.any()).describe("A record mapping StyleSchema properties to their corresponding PropValues")
2854
+ style: z3.record(z3.string(), z3.any()).describe("A record mapping StyleSchema properties to their corresponding PropValues"),
2855
+ childElements: z3.array(
2856
+ z3.object({
2857
+ id: z3.string(),
2858
+ elementType: z3.string(),
2859
+ childElements: z3.array(z3.any()).describe("An array of child element IDs, when applicable, same structure recursively")
2860
+ })
2861
+ ).describe("An array of child element IDs, when applicable, with recursive structure")
2862
+ };
2863
+ var structuredElements = (element) => {
2864
+ const children = element.children || [];
2865
+ return children.map((child) => {
2866
+ return {
2867
+ id: child.id,
2868
+ elementType: child.model.get("elType") || child.model.get("widgetType") || "unknown",
2869
+ childElements: structuredElements(child)
2870
+ };
2871
+ });
2794
2872
  };
2795
2873
  var initGetElementConfigTool = (reg) => {
2796
2874
  const { addTool } = reg;
@@ -2838,7 +2916,8 @@ var initGetElementConfigTool = (reg) => {
2838
2916
  },
2839
2917
  style: {
2840
2918
  ...stylePropValues
2841
- }
2919
+ },
2920
+ childElements: structuredElements(element)
2842
2921
  };
2843
2922
  }
2844
2923
  });
@@ -2858,6 +2937,7 @@ var initCanvasMcp = (reg) => {
2858
2937
  };
2859
2938
 
2860
2939
  // src/mcp/mcp-description.ts
2940
+ var ELEMENT_SCHEMA_URI = WIDGET_SCHEMA_URI.replace("{widgetType}", "element-schema");
2861
2941
  var mcpDescription = `Canvas MCP
2862
2942
  This MCP enables everything related to creation, configuration, and styling of elements on the Elementor canvas.
2863
2943
 
@@ -2893,11 +2973,53 @@ The tool accepts both the structure, the styling and the configuration of each e
2893
2973
 
2894
2974
  - First step: Retreive the available widgets by listing the [${WIDGET_SCHEMA_URI}] dynamic resource.
2895
2975
  - Second step: decide which elements to create, and their configuration and styles.
2896
- Retrieve the used elements configuration schema from the resource [${WIDGET_SCHEMA_URI}/element-name]
2976
+ Retrieve the used elements configuration schema from the resource [${ELEMENT_SCHEMA_URI}]
2897
2977
  - Third step: define the styles for each element, using the common styles schema from the resource [${STYLE_SCHEMA_URI}]. List the resource to see all available style properties.
2898
2978
  For background and complicated layered styles, you can use "custom_css" property, which is supported only for ELEMENTOR PRO users ONLY.
2899
2979
  The custom css is intented to deal with yet unsupported CSS features that ARE NOT PART OF THE STYLE SCHEMA, to enable PRO users to support new CSS features.
2900
2980
 
2981
+ ## Workflow for build-compositions tool
2982
+ 1. **Parse user requirements** - Undestand what needs to be built (structure, content, styling).
2983
+ 2. ** Check global resources FIRST** - Always check before building:
2984
+ - List \`elementor://global-classes\` to see if the needed global classes already exist.
2985
+ - List \`elementor://global-variables\` to see if the needed global variables already exist.
2986
+ - **Preference**: Use existing global classes and variables over creating new inline styles.
2987
+ 3. **Retreive widget schemas** - For each widget you will use:
2988
+ - List [${WIDGET_SCHEMA_URI}] to see available widgets.
2989
+ - Retrieve configuration schema from [${ELEMENT_SCHEMA_URI}] for each widget to understand required properties.
2990
+ - Understand if a widget is a container (can have children) by checking the "llm_guidance" property in the widget's schema.
2991
+ 4. **Build XML structure** - Create valid XML width configuration-ids:
2992
+ - Every element has unique configuration-id attribute
2993
+ - No text nodes, classes, IDs in XML.
2994
+
2995
+ 5. **Create elementConfig** - For each configuration-id:
2996
+ - Use PropValues with corrent \`$$type\` matching the schema.
2997
+ - **Use global variables** in PropValues where applicable
2998
+
2999
+ 6. **Create stylesConfig** - For each configuration-id:
3000
+ - Use style schema PropValues from [${STYLE_SCHEMA_URI}]
3001
+ - **Priority**: Use style schema PropValues over custom_css
3002
+ - **Use global variables** for colors, sizes, fonts where applicable
3003
+ - **custom_css (PRO Users Only)**: The property appears only for PRO user. The purpose of custom_css is to support new CSS features not yet available in the style schema.
3004
+ The schema supports multiple layers of background, gradients, filters. Prefer NOT USING custom_css.
3005
+ - **Important**: Global classes are applied AFTER building the composition. Once built, apply classes using the "apply-global-class" tool - after completion of building the composition.
3006
+
3007
+ 7. **Validate** - Ensure:
3008
+ - XML structure is valid
3009
+ - All PropValues have corrent \`$$type\`
3010
+ - After building a composition, you can retreive each element configuration using the "get-element-configuration-values" tool to verify correctness, using the IDs returned from the build-composition tool.
3011
+
3012
+ ## Key relationships:
3013
+ - **XML structure**: Defines the hierarchy of elements/widgets
3014
+ - **elementConfig**: Maps configuration-id to widget PropValues
3015
+ - **stylesConfig**: Maps configuration-id to style PropValues
3016
+
3017
+ ## Using global variables example:
3018
+ Existing global variables can be used during composition
3019
+ \`\`\`json
3020
+ { "color": { "$$type": "global-color-variable", "value": "global-variable-id" } }
3021
+ \`\`\`
3022
+
2901
3023
  # Configuring Elements / Adding Style to Elements
2902
3024
  An element configuration can be retrieved using the "get-element-configuration-values" tool.
2903
3025
  Updating an element requires only the UPDATED properties (including in the styles), as Elementor does a MERGE/PATCH operation.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@elementor/editor-canvas",
3
3
  "description": "Elementor Editor Canvas",
4
- "version": "3.35.0-353",
4
+ "version": "3.35.0-355",
5
5
  "private": false,
6
6
  "author": "Elementor Team",
7
7
  "homepage": "https://elementor.com/",
@@ -37,24 +37,24 @@
37
37
  "react-dom": "^18.3.1"
38
38
  },
39
39
  "dependencies": {
40
- "@elementor/editor": "3.35.0-353",
41
- "@elementor/editor-controls": "3.35.0-353",
42
- "@elementor/editor-documents": "3.35.0-353",
43
- "@elementor/editor-elements": "3.35.0-353",
44
- "@elementor/editor-interactions": "3.35.0-353",
45
- "@elementor/editor-mcp": "3.35.0-353",
46
- "@elementor/editor-notifications": "3.35.0-353",
47
- "@elementor/editor-props": "3.35.0-353",
48
- "@elementor/editor-responsive": "3.35.0-353",
49
- "@elementor/editor-styles": "3.35.0-353",
50
- "@elementor/editor-styles-repository": "3.35.0-353",
51
- "@elementor/editor-ui": "3.35.0-353",
52
- "@elementor/editor-v1-adapters": "3.35.0-353",
53
- "@elementor/schema": "3.35.0-353",
54
- "@elementor/twing": "3.35.0-353",
40
+ "@elementor/editor": "3.35.0-355",
41
+ "@elementor/editor-controls": "3.35.0-355",
42
+ "@elementor/editor-documents": "3.35.0-355",
43
+ "@elementor/editor-elements": "3.35.0-355",
44
+ "@elementor/editor-interactions": "3.35.0-355",
45
+ "@elementor/editor-mcp": "3.35.0-355",
46
+ "@elementor/editor-notifications": "3.35.0-355",
47
+ "@elementor/editor-props": "3.35.0-355",
48
+ "@elementor/editor-responsive": "3.35.0-355",
49
+ "@elementor/editor-styles": "3.35.0-355",
50
+ "@elementor/editor-styles-repository": "3.35.0-355",
51
+ "@elementor/editor-ui": "3.35.0-355",
52
+ "@elementor/editor-v1-adapters": "3.35.0-355",
53
+ "@elementor/schema": "3.35.0-355",
54
+ "@elementor/twing": "3.35.0-355",
55
55
  "@elementor/ui": "1.36.17",
56
- "@elementor/utils": "3.35.0-353",
57
- "@elementor/wp-media": "3.35.0-353",
56
+ "@elementor/utils": "3.35.0-355",
57
+ "@elementor/wp-media": "3.35.0-355",
58
58
  "@floating-ui/react": "^0.27.5",
59
59
  "@wordpress/i18n": "^5.13.0"
60
60
  },
@@ -1,5 +1,7 @@
1
1
  import { STYLE_SCHEMA_URI, WIDGET_SCHEMA_URI } from './resources/widgets-schema-resource';
2
2
 
3
+ const ELEMENT_SCHEMA_URI = WIDGET_SCHEMA_URI.replace( '{widgetType}', 'element-schema' );
4
+
3
5
  export const mcpDescription = `Canvas MCP
4
6
  This MCP enables everything related to creation, configuration, and styling of elements on the Elementor canvas.
5
7
 
@@ -35,11 +37,53 @@ The tool accepts both the structure, the styling and the configuration of each e
35
37
 
36
38
  - First step: Retreive the available widgets by listing the [${ WIDGET_SCHEMA_URI }] dynamic resource.
37
39
  - Second step: decide which elements to create, and their configuration and styles.
38
- Retrieve the used elements configuration schema from the resource [${ WIDGET_SCHEMA_URI }/element-name]
40
+ Retrieve the used elements configuration schema from the resource [${ ELEMENT_SCHEMA_URI }]
39
41
  - Third step: define the styles for each element, using the common styles schema from the resource [${ STYLE_SCHEMA_URI }]. List the resource to see all available style properties.
40
42
  For background and complicated layered styles, you can use "custom_css" property, which is supported only for ELEMENTOR PRO users ONLY.
41
43
  The custom css is intented to deal with yet unsupported CSS features that ARE NOT PART OF THE STYLE SCHEMA, to enable PRO users to support new CSS features.
42
44
 
45
+ ## Workflow for build-compositions tool
46
+ 1. **Parse user requirements** - Undestand what needs to be built (structure, content, styling).
47
+ 2. ** Check global resources FIRST** - Always check before building:
48
+ - List \`elementor://global-classes\` to see if the needed global classes already exist.
49
+ - List \`elementor://global-variables\` to see if the needed global variables already exist.
50
+ - **Preference**: Use existing global classes and variables over creating new inline styles.
51
+ 3. **Retreive widget schemas** - For each widget you will use:
52
+ - List [${ WIDGET_SCHEMA_URI }] to see available widgets.
53
+ - Retrieve configuration schema from [${ ELEMENT_SCHEMA_URI }] for each widget to understand required properties.
54
+ - Understand if a widget is a container (can have children) by checking the "llm_guidance" property in the widget's schema.
55
+ 4. **Build XML structure** - Create valid XML width configuration-ids:
56
+ - Every element has unique configuration-id attribute
57
+ - No text nodes, classes, IDs in XML.
58
+
59
+ 5. **Create elementConfig** - For each configuration-id:
60
+ - Use PropValues with corrent \`$$type\` matching the schema.
61
+ - **Use global variables** in PropValues where applicable
62
+
63
+ 6. **Create stylesConfig** - For each configuration-id:
64
+ - Use style schema PropValues from [${ STYLE_SCHEMA_URI }]
65
+ - **Priority**: Use style schema PropValues over custom_css
66
+ - **Use global variables** for colors, sizes, fonts where applicable
67
+ - **custom_css (PRO Users Only)**: The property appears only for PRO user. The purpose of custom_css is to support new CSS features not yet available in the style schema.
68
+ The schema supports multiple layers of background, gradients, filters. Prefer NOT USING custom_css.
69
+ - **Important**: Global classes are applied AFTER building the composition. Once built, apply classes using the "apply-global-class" tool - after completion of building the composition.
70
+
71
+ 7. **Validate** - Ensure:
72
+ - XML structure is valid
73
+ - All PropValues have corrent \`$$type\`
74
+ - After building a composition, you can retreive each element configuration using the "get-element-configuration-values" tool to verify correctness, using the IDs returned from the build-composition tool.
75
+
76
+ ## Key relationships:
77
+ - **XML structure**: Defines the hierarchy of elements/widgets
78
+ - **elementConfig**: Maps configuration-id to widget PropValues
79
+ - **stylesConfig**: Maps configuration-id to style PropValues
80
+
81
+ ## Using global variables example:
82
+ Existing global variables can be used during composition
83
+ \`\`\`json
84
+ { "color": { "$$type": "global-color-variable", "value": "global-variable-id" } }
85
+ \`\`\`
86
+
43
87
  # Configuring Elements / Adding Style to Elements
44
88
  An element configuration can be retrieved using the "get-element-configuration-values" tool.
45
89
  Updating an element requires only the UPDATED properties (including in the styles), as Elementor does a MERGE/PATCH operation.
@@ -5,7 +5,7 @@ import { v1ReadyEvent } from '@elementor/editor-v1-adapters';
5
5
  export const BREAKPOINTS_SCHEMA_URI = 'elementor://breakpoints/list';
6
6
 
7
7
  export const initBreakpointsResource = ( reg: MCPRegistryEntry ) => {
8
- const { mcpServer } = reg;
8
+ const { mcpServer, sendResourceUpdated } = reg;
9
9
 
10
10
  const getBreakpointsList = () => {
11
11
  const { breakpoints } = ( window as unknown as ExtendedWindow ).elementor?.config?.responsive || {};
@@ -39,7 +39,7 @@ export const initBreakpointsResource = ( reg: MCPRegistryEntry ) => {
39
39
  } );
40
40
 
41
41
  window.addEventListener( v1ReadyEvent().name, () => {
42
- mcpServer.server.sendResourceUpdated( {
42
+ sendResourceUpdated( {
43
43
  uri: BREAKPOINTS_SCHEMA_URI,
44
44
  ...buildResourceResponse(),
45
45
  } );
@@ -3,6 +3,7 @@ import { type MCPRegistryEntry, ResourceTemplate } from '@elementor/editor-mcp';
3
3
  import {
4
4
  type ArrayPropType,
5
5
  type ObjectPropType,
6
+ type Props,
6
7
  type PropType,
7
8
  Schema,
8
9
  type TransformablePropType,
@@ -14,6 +15,21 @@ export const WIDGET_SCHEMA_URI = 'elementor://widgets/schema/{widgetType}';
14
15
  export const STYLE_SCHEMA_URI = 'elementor://styles/schema/{category}';
15
16
  export const BEST_PRACTICES_URI = 'elementor://styles/best-practices';
16
17
 
18
+ const checkIfUserHasPro = () => {
19
+ const extendedWindow = window as Window & {
20
+ elementor?: {
21
+ helpers?: {
22
+ hasPro?: () => boolean;
23
+ };
24
+ };
25
+ };
26
+ const hasPro = extendedWindow.elementor?.helpers?.hasPro;
27
+ if ( typeof hasPro === 'function' ) {
28
+ return hasPro();
29
+ }
30
+ return false;
31
+ };
32
+
17
33
  export const initWidgetsSchemaResource = ( reg: MCPRegistryEntry ) => {
18
34
  const { mcpServer } = reg;
19
35
 
@@ -37,7 +53,11 @@ The css string must follow standard CSS syntax, with properties and values separ
37
53
  'styles-schema',
38
54
  new ResourceTemplate( STYLE_SCHEMA_URI, {
39
55
  list: () => {
40
- const categories = [ ...Object.keys( getStylesSchema() ), 'custom_css' ];
56
+ const isPro = checkIfUserHasPro();
57
+ const categories = [ ...Object.keys( getStylesSchema() ) ];
58
+ if ( ! isPro ) {
59
+ categories.push( 'custom_css' );
60
+ }
41
61
  return {
42
62
  resources: categories.map( ( category ) => ( {
43
63
  uri: `elementor://styles/schema/${ category }`,
@@ -51,7 +71,7 @@ The css string must follow standard CSS syntax, with properties and values separ
51
71
  },
52
72
  async ( uri, variables ) => {
53
73
  const category = typeof variables.category === 'string' ? variables.category : variables.category?.[ 0 ];
54
- if ( category === 'custom_css' ) {
74
+ if ( category === 'custom_css' && checkIfUserHasPro() ) {
55
75
  return {
56
76
  contents: [
57
77
  {
@@ -84,7 +104,8 @@ The css string must follow standard CSS syntax, with properties and values separ
84
104
  list: () => {
85
105
  const cache = getWidgetsCache() || {};
86
106
  const availableWidgets = Object.keys( cache || {} ).filter(
87
- ( widgetType ) => cache[ widgetType ]?.atomic_props_schema
107
+ ( widgetType ) =>
108
+ cache[ widgetType ]?.atomic_props_schema && cache[ widgetType ].meta?.llm_support !== false
88
109
  );
89
110
  return {
90
111
  resources: availableWidgets.map( ( widgetType ) => ( {
@@ -100,8 +121,9 @@ The css string must follow standard CSS syntax, with properties and values separ
100
121
  async ( uri, variables ) => {
101
122
  const widgetType =
102
123
  typeof variables.widgetType === 'string' ? variables.widgetType : variables.widgetType?.[ 0 ];
103
- const propSchema = getWidgetsCache()?.[ widgetType ]?.atomic_props_schema;
104
- if ( ! propSchema ) {
124
+ const widgetData = getWidgetsCache()?.[ widgetType ];
125
+ const propSchema = widgetData?.atomic_props_schema;
126
+ if ( ! propSchema || ! widgetData ) {
105
127
  throw new Error( `No prop schema found for element type: ${ widgetType }` );
106
128
  }
107
129
  const asJson = Object.fromEntries(
@@ -115,6 +137,31 @@ The css string must follow standard CSS syntax, with properties and values separ
115
137
  delete asJson[ key ];
116
138
  } );
117
139
 
140
+ const description =
141
+ typeof widgetData?.meta?.description === 'string' ? widgetData.meta.description : undefined;
142
+
143
+ const defaultStyles: Record< string, Props > = {};
144
+ const baseStyleSchema = widgetData?.base_styles;
145
+ if ( baseStyleSchema ) {
146
+ Object.values( baseStyleSchema ).forEach( ( stylePropType ) => {
147
+ stylePropType.variants.forEach( ( variant ) => {
148
+ Object.assign( defaultStyles, variant.props );
149
+ } );
150
+ } );
151
+ }
152
+
153
+ // build llm instructions
154
+ const hasDefaultStyles = Object.keys( defaultStyles ).length > 0;
155
+ const llmGuidance: Record< string, unknown > = {
156
+ can_have_children: !! widgetData?.meta?.is_container,
157
+ };
158
+
159
+ if ( hasDefaultStyles ) {
160
+ llmGuidance.instructions =
161
+ 'These are the default styles applied to the widget. Override only when necessary.';
162
+ llmGuidance.default_styles = defaultStyles;
163
+ }
164
+
118
165
  return {
119
166
  contents: [
120
167
  {
@@ -123,6 +170,8 @@ The css string must follow standard CSS syntax, with properties and values separ
123
170
  text: JSON.stringify( {
124
171
  type: 'object',
125
172
  properties: asJson,
173
+ description,
174
+ llm_guidance: llmGuidance,
126
175
  } ),
127
176
  },
128
177
  ],
@@ -24,6 +24,24 @@ When in doubt between "safe" and "distinctive," choose distinctive - users can a
24
24
  Always prefer this tool when the user requires to build a composition of elements, such as cards, heros, or inspired from other pages or HTML compositions.
25
25
  Prefer this tool over any other tool for building HTML structure, unless you are specified to use a different tool.
26
26
 
27
+ # **CRITICAL - REQUIRED RESOURCES (Must read before using this tool)**
28
+ 1. [${ WIDGET_SCHEMA_URI }]
29
+ Required to understand which widgets are available, and what are their configuration schemas.
30
+ Every widgetType (i.e. e-heading, e-button) that is supported has it's own property schema, that you must follow in order to apply property values correctly.
31
+ 2. [${ STYLE_SCHEMA_URI }]
32
+ Required to understand the styles schema for the widgets. All widgets share the same styles schema.
33
+ 3. List of allowed custom tags for building the structure is derived from the list of widgets schema resources.
34
+
35
+ # DESIGN QUALITY IMPERATIVE
36
+ You are generating designs for real users who expect distinctive, intentional aesthetics - NOT generic AI output.
37
+ **The Core Challenge**: Large language models naturally converge toward statistically common design patterns during generation. This creates predictable, uninspired results that users describe as "AI slop": safe color schemes, default typography hierarchies, minimal contrast, and timid spacing.
38
+ **Your Mission**: Actively resist distributional convergence by making intentional, distinctive design choices across all aesthetic dimensions. Every design decision should have a clear purpose tied to visual hierarchy, brand personality, or user experience goals.
39
+ When in doubt between "safe" and "distinctive," choose distinctive - users can always request refinements, but they cannot salvage generic foundations.
40
+
41
+ # When to use this tool
42
+ Always prefer this tool when the user requires to build a composition of elements, such as cards, heros, or inspired from other pages or HTML compositions.
43
+ Prefer this tool over any other tool for building HTML structure, unless you are specified to use a different tool.
44
+
27
45
  # Instructions
28
46
  1. Understand the user requirements carefully.
29
47
  2. Build a valid XML structure using only the allowed custom tags provided. For example, if you
@@ -38,11 +56,11 @@ Prefer this tool over any other tool for building HTML structure, unless you are
38
56
  5. Ensure the XML structure is valid and parsable.
39
57
  6. Do not add any attribute nodes, classes, id's, and no text nodes allowed.
40
58
  Layout properties, such as margin, padding, align, etc. must be applied using the [${ STYLE_SCHEMA_URI }] PropValues.
41
- 7. Some elements allow nesting of other elements, and most of the DO NOT. The allowed elements that can have nested children are "e-div-block" and "e-flexbox".
59
+ 7. Some elements allow nesting of other elements, and most of the DO NOT. The allowed elements that can have nested children are "e-tabs", "e-div-block", and "e-flexbox".
42
60
  8. Make sure that non-container elements do NOT have any nested elements.
43
- 9. **CRITICAL - CUSTOM CSS PRIORITY**: Prefer using style schema. Custom CSS is ONLY FOR UNSUPPRTED schema styles.
61
+ 9. **CRITICAL - CUSTOM CSS USAGE**: ALWAYS Prefer using style schema. Custom CSS is ONLY FOR UNSUPPRTED schema styles.
44
62
  ALWAYS PRIORITIZE using the style schema PropValues for styling elements as they provide better user experience in the editor, and UI features for the end-users.
45
- - Use custom_css only for style attributes that ARE NOT SUPPORTED via the style schema.
63
+ Use custom_css only for style attributes that ARE NOT SUPPORTED via the style schema AFTER YOU CHECK THE [${ STYLE_SCHEMA_URI }].
46
64
 
47
65
  # DESIGN VECTORS - Concrete Implementation Guidance
48
66
 
@@ -261,10 +279,8 @@ If unsure about the configuration of a specific property, read the schema resour
261
279
 
262
280
  # About our widgets
263
281
  Most widgets are self-explanatory by their name. Here is some additional information.
282
+ Check for available llm_guidance property in the widget's schema.
264
283
  SVG elements are bound to internal content upload. Avoid usage, unless you have tools to upload SVG content.
265
- e-div-block - By default is ceneterd aligned and vertically stacked. To modify this, apply style configuration.
266
- e-flexbox - By default is a flex container with row direction. To modify this, apply style configuration.
267
-
268
284
  When working with containers, do not forget to apply style schema for controlling the layout.
269
285
 
270
286
 
@@ -46,15 +46,31 @@ export const initBuildCompositionsTool = ( reg: MCPRegistryEntry ) => {
46
46
  }
47
47
 
48
48
  const children = Array.from( xml.children );
49
- const iterate = ( node: Element, containerElement: V1Element = documentContainer ) => {
49
+ const iterate = async (
50
+ node: Element,
51
+ containerElement: V1Element = documentContainer,
52
+ childIndex: number
53
+ ) => {
50
54
  const elementTag = node.tagName;
51
55
  if ( ! widgetsCache[ elementTag ] ) {
52
56
  errors.push( new Error( `Unknown widget type: ${ elementTag }` ) );
53
57
  }
54
- const isContainer = elementTag === 'e-flexbox' || elementTag === 'e-div-block';
58
+ const CONTAINER_ELEMENTS = Object.values( widgetsCache )
59
+ .filter( ( widget ) => widget.meta?.is_container )
60
+ .map( ( widget ) => widget.elType );
61
+ const isContainer = CONTAINER_ELEMENTS.includes( elementTag );
62
+ const parentElType = containerElement.model.get( 'elType' );
63
+ let targetContainerId =
64
+ parentElType === 'e-tabs'
65
+ ? containerElement.children?.[ 1 ].children?.[ childIndex ]?.id ||
66
+ containerElement.children?.[ 1 ].id
67
+ : containerElement.id;
68
+ if ( ! targetContainerId ) {
69
+ targetContainerId = containerElement.id;
70
+ }
55
71
  const newElement = isContainer
56
72
  ? createElement( {
57
- containerId: containerElement.id,
73
+ containerId: targetContainerId,
58
74
  model: {
59
75
  elType: elementTag,
60
76
  id: generateElementId(),
@@ -62,7 +78,7 @@ export const initBuildCompositionsTool = ( reg: MCPRegistryEntry ) => {
62
78
  options: { useHistory: false },
63
79
  } )
64
80
  : createElement( {
65
- containerId: containerElement.id,
81
+ containerId: targetContainerId,
66
82
  model: {
67
83
  elType: 'widget',
68
84
  widgetType: elementTag,
@@ -103,8 +119,10 @@ export const initBuildCompositionsTool = ( reg: MCPRegistryEntry ) => {
103
119
  }
104
120
  }
105
121
  if ( isContainer ) {
122
+ let currentChild = 0;
106
123
  for ( const child of node.children ) {
107
- iterate( child, newElement );
124
+ iterate( child, newElement, currentChild );
125
+ currentChild++;
108
126
  }
109
127
  } else {
110
128
  node.innerHTML = '';
@@ -114,8 +132,10 @@ export const initBuildCompositionsTool = ( reg: MCPRegistryEntry ) => {
114
132
  }
115
133
  };
116
134
 
117
- for ( const childNode of children ) {
118
- iterate( childNode, documentContainer );
135
+ let currentChild = 0;
136
+ for await ( const childNode of children ) {
137
+ await iterate( childNode, documentContainer, currentChild );
138
+ currentChild++;
119
139
  try {
120
140
  } catch ( error ) {
121
141
  errors.push( error as Error );
@@ -26,6 +26,8 @@ When a user requires to change anything in an element, such as updating text, co
26
26
  This tool handles elements of type "widget".
27
27
  This tool handles styling elements, using the "stylePropertiesToChange" parameter.
28
28
 
29
+ To CLEAR a property (i.e., set it to default or none), provide null as a value.
30
+
29
31
  The element's schema must be known before using this tool.
30
32
  The style schema must be known before using this tool.
31
33
 
@@ -1,4 +1,4 @@
1
- import { getContainer, getElementStyles, getWidgetsCache } from '@elementor/editor-elements';
1
+ import { getContainer, getElementStyles, getWidgetsCache, type V1Element } from '@elementor/editor-elements';
2
2
  import { type MCPRegistryEntry } from '@elementor/editor-mcp';
3
3
  import { type PropValue, Schema } from '@elementor/editor-props';
4
4
  import { z } from '@elementor/schema';
@@ -14,6 +14,32 @@ const outputSchema = {
14
14
  style: z
15
15
  .record( z.string(), z.any() )
16
16
  .describe( 'A record mapping StyleSchema properties to their corresponding PropValues' ),
17
+ childElements: z
18
+ .array(
19
+ z.object( {
20
+ id: z.string(),
21
+ elementType: z.string(),
22
+ childElements: z
23
+ .array( z.any() )
24
+ .describe( 'An array of child element IDs, when applicable, same structure recursively' ),
25
+ } )
26
+ )
27
+ .describe( 'An array of child element IDs, when applicable, with recursive structure' ),
28
+ };
29
+ type ElementStructure = {
30
+ id: string;
31
+ elementType: string;
32
+ childElements: ElementStructure[];
33
+ };
34
+ const structuredElements = ( element: V1Element ): ElementStructure[] => {
35
+ const children = element.children || [];
36
+ return children.map( ( child ) => {
37
+ return {
38
+ id: child.id,
39
+ elementType: child.model.get( 'elType' ) || child.model.get( 'widgetType' ) || 'unknown',
40
+ childElements: structuredElements( child ),
41
+ };
42
+ } );
17
43
  };
18
44
 
19
45
  export const initGetElementConfigTool = ( reg: MCPRegistryEntry ) => {
@@ -71,6 +97,7 @@ export const initGetElementConfigTool = ( reg: MCPRegistryEntry ) => {
71
97
  style: {
72
98
  ...stylePropValues,
73
99
  },
100
+ childElements: structuredElements( element ),
74
101
  };
75
102
  },
76
103
  } );
@@ -48,9 +48,9 @@ export const validateInput = {
48
48
  } else if ( ! Schema.isPropKeyConfigurable( propName ) ) {
49
49
  errors.push( `Property "${ propName }" is not configurable.` );
50
50
  } else {
51
- const { valid, errorMessages } = Schema.validatePropValue( propSchema, propValue as PropValue );
51
+ const { valid, jsonSchema } = Schema.validatePropValue( propSchema, propValue as PropValue );
52
52
  if ( ! valid ) {
53
- errors.push( `Invalid property "${ propName }": ${ errorMessages }` );
53
+ errors.push( `Invalid property "${ propName }". Expected schema: ${ jsonSchema }` );
54
54
  }
55
55
  }
56
56
  } );