@elementor/editor-mcp 4.1.0-788 → 4.1.0-790

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
@@ -35,19 +35,23 @@ __export(index_exports, {
35
35
  McpServer: () => import_mcp2.McpServer,
36
36
  ResourceTemplate: () => import_mcp2.ResourceTemplate,
37
37
  SamplingMessageSchema: () => import_types2.SamplingMessageSchema,
38
- activateMcpRegistration: () => activateMcpRegistration,
38
+ activateAdapters: () => activateAdapters,
39
39
  createSampler: () => createSampler,
40
+ getActiveChatInfo: () => getActiveChatInfo,
40
41
  getAngieIframe: () => import_angie_sdk2.getAngieIframe,
41
42
  getAngieSdk: () => getAngieSdk,
42
43
  getMCPByDomain: () => getMCPByDomain,
43
- init: () => init,
44
+ getRegisteredMcpServers: () => getRegisteredMcpServers,
44
45
  installAngiePlugin: () => installAngiePlugin,
45
46
  isAngieAvailable: () => isAngieAvailable,
46
47
  isAngieSidebarOpen: () => isAngieSidebarOpen,
47
48
  redirectToAppAdmin: () => redirectToAppAdmin,
48
49
  redirectToInstallation: () => redirectToInstallation,
49
50
  registerMcp: () => registerMcp,
51
+ registerMcpAdapter: () => registerMcpAdapter,
50
52
  sendPromptToAngie: () => sendPromptToAngie,
53
+ signalMcpReady: () => signalMcpReady,
54
+ startMCPServer: () => startMCPServer,
51
55
  toMCPTitle: () => toMCPTitle,
52
56
  toolPrompts: () => toolPrompts
53
57
  });
@@ -72,12 +76,22 @@ var getSDK = () => {
72
76
  var import_mcp2 = require("@modelcontextprotocol/sdk/server/mcp.js");
73
77
  var import_types2 = require("@modelcontextprotocol/sdk/types.js");
74
78
 
75
- // src/init.ts
76
- var import_editor_v1_adapters = require("@elementor/editor-v1-adapters");
79
+ // src/utils/is-angie-available.ts
80
+ var import_angie_sdk3 = require("@elementor-external/angie-sdk");
81
+ var isAngieAvailable = () => {
82
+ return !!(0, import_angie_sdk3.getAngieIframe)();
83
+ };
84
+
85
+ // src/utils/is-angie-sidebar-open.ts
86
+ var import_angie_sdk4 = require("@elementor-external/angie-sdk");
87
+ var isAngieSidebarOpen = () => {
88
+ return (0, import_angie_sdk4.getAngieSidebarSavedState)() === import_angie_sdk4.ANGIE_SIDEBAR_STATE_OPEN;
89
+ };
77
90
 
78
91
  // src/mcp-registry.ts
79
92
  var import_schema = require("@elementor/schema");
80
93
  var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
94
+ var import_uriTemplate = require("@modelcontextprotocol/sdk/shared/uriTemplate.js");
81
95
 
82
96
  // src/angie-annotations.ts
83
97
  var ANGIE_MODEL_PREFERENCES = "angie/modelPreferences";
@@ -113,9 +127,6 @@ var mockMcpRegistry = () => {
113
127
  },
114
128
  setMCPDescription: () => {
115
129
  },
116
- getActiveChatInfo() {
117
- return { sessionId: "mock-session-id", expiresAt: Date.now() + 36e5 };
118
- },
119
130
  mcpServer: mock
120
131
  };
121
132
  };
@@ -124,37 +135,45 @@ var mockMcpRegistry = () => {
124
135
  var mcpRegistry = {};
125
136
  var mcpDescriptions = {};
126
137
  var isMcpRegistrationActivated = typeof globalThis.jest !== "undefined";
127
- var registerMcp = (mcp, name) => {
128
- const mcpName = isAlphabet(name);
129
- mcpRegistry[mcpName] = mcp;
130
- };
131
- async function activateMcpRegistration(sdk2, entries = Object.entries(mcpRegistry), retry = 3) {
132
- if (retry === 0) {
133
- console.error("Failed to register MCP after 3 retries. failed entries: ", entries);
134
- return;
135
- }
136
- if (entries.length === 0) {
137
- return;
138
+ var registrationAdapters = [];
139
+ var bufferedTools = [];
140
+ var bufferedResources = [];
141
+ var resolveReady;
142
+ var readyPromise = new Promise((resolve) => {
143
+ resolveReady = resolve;
144
+ });
145
+ var registerMcpAdapter = (adapter) => {
146
+ registrationAdapters.push(adapter);
147
+ for (const tool of bufferedTools) {
148
+ try {
149
+ adapter.onToolRegistered(tool[0], tool[1]);
150
+ } catch {
151
+ }
138
152
  }
139
- const failed = [];
140
- for await (const entry of entries) {
141
- const [key, mcpServer] = entry;
153
+ for (const resource of bufferedResources) {
142
154
  try {
143
- await sdk2.registerLocalServer({
144
- title: toMCPTitle(key),
145
- name: `editor-${key}`,
146
- server: mcpServer,
147
- version: "1.0.0",
148
- description: mcpDescriptions[key] || key
149
- });
155
+ adapter.onResourceRegistered(...resource);
150
156
  } catch {
151
- failed.push(entry);
152
157
  }
153
158
  }
154
- if (failed.length > 0) {
155
- return activateMcpRegistration(sdk2, failed, retry - 1);
159
+ };
160
+ var signalMcpReady = () => resolveReady();
161
+ var activateAdapters = () => callAdapters((adapter) => adapter.activate());
162
+ function callAdapters(fn) {
163
+ for (const adapter of registrationAdapters) {
164
+ try {
165
+ fn(adapter);
166
+ } catch {
167
+ }
156
168
  }
157
169
  }
170
+ var registerMcp = (mcp, name) => {
171
+ const mcpName = isAlphabet(name);
172
+ mcpRegistry[mcpName] = mcp;
173
+ };
174
+ var getRegisteredMcpServers = () => {
175
+ return Object.entries(mcpRegistry).map(([key, server]) => [key, server, mcpDescriptions[key] || key]);
176
+ };
158
177
  var isAlphabet = (str) => {
159
178
  const passes = !!str && /^[a-z_]+$/.test(str);
160
179
  if (!passes) {
@@ -180,49 +199,56 @@ var getMCPByDomain = (namespace, options) => {
180
199
  version: "1.0.0"
181
200
  },
182
201
  {
183
- instructions: options?.instructions
202
+ instructions: options?.instructions,
203
+ capabilities: { resources: { subscribe: true } }
184
204
  }
185
205
  );
206
+ if (!!options?.instructions) {
207
+ callAdapters(
208
+ (adapter) => adapter.onResourceRegistered(
209
+ `${mcpName}`,
210
+ { uriTemplate: new import_uriTemplate.UriTemplate(mcpName) },
211
+ () => Promise.resolve({ contents: [{ text: options.instructions ?? "" }] })
212
+ )
213
+ );
214
+ }
186
215
  }
187
216
  const mcpServer = mcpRegistry[namespace];
188
- const { addTool } = createToolRegistry(mcpServer);
217
+ const { addTool } = createToolRegistry(mcpServer, mcpName);
189
218
  return {
190
- waitForReady: () => getSDK().waitForReady(),
219
+ waitForReady: () => readyPromise,
191
220
  // @ts-expect-error: TS is unable to infer the type here
192
221
  resource: async (...args) => {
193
- await getSDK().waitForReady();
222
+ const [name, uriOrTemplate, ...rest] = args;
223
+ const handler = rest[rest.length - 1];
224
+ const resourceArgs = [
225
+ name,
226
+ uriOrTemplate,
227
+ handler
228
+ ];
229
+ bufferedResources.push(resourceArgs);
230
+ callAdapters((adapter) => adapter.onResourceRegistered(...resourceArgs));
194
231
  return mcpServer.registerResource(...args);
195
232
  },
196
233
  sendResourceUpdated: (...args) => {
197
- return getSDK().waitForReady().then(() => mcpServer.server.sendResourceUpdated(...args)).catch((error) => {
234
+ callAdapters((adapter) => adapter.sendResourceUpdated({ uri: args[0].uri }));
235
+ return Promise.resolve(mcpServer.server.sendResourceUpdated(...args)).catch((error) => {
198
236
  if (error?.message?.includes("Not connected")) {
199
237
  return;
200
238
  }
239
+ if (error?.message?.includes("does not support notifying about resources")) {
240
+ return;
241
+ }
201
242
  throw error;
202
243
  });
203
244
  },
204
- mcpServer,
205
245
  addTool,
206
246
  setMCPDescription: (description) => {
207
247
  mcpDescriptions[namespace] = description;
208
- },
209
- getActiveChatInfo: () => {
210
- const info = localStorage.getItem("angie_active_chat_id");
211
- if (!info) {
212
- return {
213
- expiresAt: 0,
214
- sessionId: ""
215
- };
216
- }
217
- const rawData = JSON.parse(info);
218
- return {
219
- expiresAt: rawData.expiresAt,
220
- sessionId: rawData.sessionId
221
- };
222
248
  }
223
249
  };
224
250
  };
225
- function createToolRegistry(server) {
251
+ function createToolRegistry(server, serverName) {
226
252
  function addTool(opts) {
227
253
  const outputSchema = opts.outputSchema;
228
254
  if (outputSchema) {
@@ -283,6 +309,24 @@ function createToolRegistry(server) {
283
309
  },
284
310
  toolCallback
285
311
  );
312
+ const toolDescriptor = {
313
+ name: opts.name,
314
+ description: opts.description,
315
+ inputSchema,
316
+ execute: (params) => Promise.resolve(
317
+ toolCallback(
318
+ params,
319
+ /* WebMCP: no protocol session — handlers must not rely on `extra` here */
320
+ {}
321
+ )
322
+ )
323
+ };
324
+ const extraData = {
325
+ resources: [`Server resource name: ${serverName}, Required to fetch!`],
326
+ requiredResources: opts.requiredResources?.map((resource) => resource.uri) ?? []
327
+ };
328
+ bufferedTools.push([toolDescriptor, extraData]);
329
+ callAdapters((adapter) => adapter.onToolRegistered(toolDescriptor, extraData));
286
330
  if (isMcpRegistrationActivated) {
287
331
  server.sendToolListChanged();
288
332
  }
@@ -292,42 +336,6 @@ function createToolRegistry(server) {
292
336
  };
293
337
  }
294
338
 
295
- // src/utils/is-angie-available.ts
296
- var import_angie_sdk3 = require("@elementor-external/angie-sdk");
297
- var isAngieAvailable = () => {
298
- return !!(0, import_angie_sdk3.getAngieIframe)();
299
- };
300
-
301
- // src/init.ts
302
- function init() {
303
- if ((0, import_editor_v1_adapters.isExperimentActive)("editor_mcp") && isAngieAvailable()) {
304
- return getSDK().waitForReady();
305
- }
306
- return Promise.resolve();
307
- }
308
- function startMCPServer() {
309
- if ((0, import_editor_v1_adapters.isExperimentActive)("editor_mcp") && isAngieAvailable()) {
310
- const sdk2 = getSDK();
311
- sdk2.waitForReady().then(() => activateMcpRegistration(sdk2));
312
- }
313
- return Promise.resolve();
314
- }
315
- document.addEventListener(
316
- "DOMContentLoaded",
317
- () => {
318
- startMCPServer();
319
- },
320
- {
321
- once: true
322
- }
323
- );
324
-
325
- // src/utils/is-angie-sidebar-open.ts
326
- var import_angie_sdk4 = require("@elementor-external/angie-sdk");
327
- var isAngieSidebarOpen = () => {
328
- return (0, import_angie_sdk4.getAngieSidebarSavedState)() === import_angie_sdk4.ANGIE_SIDEBAR_STATE_OPEN;
329
- };
330
-
331
339
  // src/sampler.ts
332
340
  var import_types = require("@modelcontextprotocol/sdk/types.js");
333
341
  var DEFAULT_OPTS = {
@@ -431,6 +439,22 @@ var toolPrompts = (name) => {
431
439
  return new ToolPrompts(name);
432
440
  };
433
441
 
442
+ // src/utils/get-active-chat-info.ts
443
+ var getActiveChatInfo = () => {
444
+ const info = localStorage.getItem("angie_active_chat_id");
445
+ if (!info) {
446
+ return {
447
+ expiresAt: 0,
448
+ sessionId: ""
449
+ };
450
+ }
451
+ const rawData = JSON.parse(info);
452
+ return {
453
+ expiresAt: rawData.expiresAt,
454
+ sessionId: rawData.sessionId
455
+ };
456
+ };
457
+
434
458
  // src/utils/send-prompt-to-angie.ts
435
459
  var import_angie_sdk5 = require("@elementor-external/angie-sdk");
436
460
  var sendPromptToAngie = (prompt) => {
@@ -509,6 +533,189 @@ var installAngiePlugin = async () => {
509
533
  }
510
534
  };
511
535
 
536
+ // src/adapters/angie-adapter.ts
537
+ var MAX_RETRIES = 3;
538
+ var AngieMcpAdapter = class {
539
+ constructor(sdk2) {
540
+ this.sdk = sdk2;
541
+ }
542
+ async activate() {
543
+ await this.sdk.waitForReady();
544
+ await this.registerEntries(getRegisteredMcpServers(), MAX_RETRIES);
545
+ }
546
+ async registerEntries(entries, retry) {
547
+ if (retry === 0) {
548
+ console.error(
549
+ "Failed to register MCP after 3 retries. failed entries: ",
550
+ entries.map(([key]) => key)
551
+ );
552
+ return;
553
+ }
554
+ const failed = [];
555
+ for (const [key, mcpServer, description] of entries) {
556
+ try {
557
+ await this.sdk.registerLocalServer({
558
+ title: toMCPTitle(key),
559
+ name: `editor-${key}`,
560
+ server: mcpServer,
561
+ version: "1.0.0",
562
+ description
563
+ });
564
+ } catch {
565
+ failed.push([key, mcpServer, description]);
566
+ }
567
+ }
568
+ if (failed.length > 0) {
569
+ return this.registerEntries(failed, retry - 1);
570
+ }
571
+ }
572
+ onToolRegistered() {
573
+ }
574
+ onResourceRegistered() {
575
+ }
576
+ sendResourceUpdated() {
577
+ }
578
+ };
579
+
580
+ // src/adapters/web-mcp-adapter.ts
581
+ var import_zod_to_json_schema = require("zod-to-json-schema");
582
+ var import_schema2 = require("@elementor/schema");
583
+ var WebMCPAdapter = class {
584
+ constructor(ctx) {
585
+ this.ctx = ctx;
586
+ }
587
+ registeredToolNames = /* @__PURE__ */ new Set();
588
+ resourceEntries = [];
589
+ activated = false;
590
+ activate() {
591
+ if (this.activated) {
592
+ return;
593
+ }
594
+ this.activated = true;
595
+ this.ctx.registerTool({
596
+ name: "editor-resource-getter",
597
+ description: "Get an editor resource by URI, or search for available resources by partial URI. Pass a full URI to retrieve content, or a partial string to discover matching patterns.",
598
+ inputSchema: {
599
+ type: "object",
600
+ properties: {
601
+ uri: {
602
+ type: "string",
603
+ description: "A full resource URI (e.g. elementor://styles/best-practices) or a partial string to search across available resource patterns."
604
+ }
605
+ },
606
+ required: ["uri"]
607
+ },
608
+ execute: async (params) => {
609
+ const query = params.uri;
610
+ const entries = this.resourceEntries;
611
+ if (entries.length === 0) {
612
+ return "No resources are registered yet.";
613
+ }
614
+ for (const entry of entries) {
615
+ const variables = entry.match(query);
616
+ if (variables !== null) {
617
+ let resourceUrl;
618
+ try {
619
+ resourceUrl = new URL(query);
620
+ } catch {
621
+ return `Invalid URI '${query}'. Provide a valid resource URI or a partial string to search patterns.`;
622
+ }
623
+ const result = await entry.handler(resourceUrl, variables);
624
+ return result.contents?.[0]?.text ?? JSON.stringify(result);
625
+ }
626
+ }
627
+ const matches = entries.map((e) => e.pattern).filter((pattern) => pattern.includes(query));
628
+ if (matches.length > 0) {
629
+ return `Found ${matches.length} matching resource pattern(s):
630
+ ${matches.join(
631
+ "\n"
632
+ )}
633
+
634
+ Provide a full URI to retrieve the resource content.`;
635
+ }
636
+ const available = entries.map((e) => e.pattern).join("\n");
637
+ throw new Error(`No resource matched '${query}'.
638
+
639
+ Available patterns:
640
+ ${available}`);
641
+ }
642
+ });
643
+ }
644
+ onToolRegistered(tool, extraData) {
645
+ let jsonSchema;
646
+ try {
647
+ jsonSchema = (0, import_zod_to_json_schema.zodToJsonSchema)(import_schema2.z.object(tool.inputSchema));
648
+ } catch {
649
+ jsonSchema = tool.inputSchema;
650
+ }
651
+ if (this.registeredToolNames.has(tool.name)) {
652
+ this.ctx.unregisterTool(tool.name);
653
+ }
654
+ let resourcesDescription = "";
655
+ if (extraData) {
656
+ if (extraData.resources?.length > 0) {
657
+ resourcesDescription += `#Resources:
658
+ ${extraData.resources?.join("\n")}
659
+
660
+ `;
661
+ }
662
+ if (extraData.requiredResources?.length > 0) {
663
+ resourcesDescription += `#Required Resources:
664
+ ${extraData.requiredResources?.join("\n")}
665
+
666
+ `;
667
+ }
668
+ resourcesDescription += `To read resources, use editor-resource-getter tool.
669
+
670
+ `;
671
+ }
672
+ this.ctx.registerTool({
673
+ name: tool.name,
674
+ description: `${resourcesDescription}${tool.description}`,
675
+ inputSchema: jsonSchema,
676
+ execute: tool.execute
677
+ });
678
+ this.registeredToolNames.add(tool.name);
679
+ }
680
+ onResourceRegistered(_name, uriOrTemplate, handler) {
681
+ if (typeof uriOrTemplate === "string") {
682
+ this.resourceEntries.push({
683
+ pattern: uriOrTemplate,
684
+ match: (uri) => uri === uriOrTemplate ? {} : null,
685
+ handler
686
+ });
687
+ } else {
688
+ const template = uriOrTemplate.uriTemplate;
689
+ this.resourceEntries.push({
690
+ pattern: template.toString(),
691
+ match: (uri) => template.match(uri),
692
+ handler
693
+ });
694
+ }
695
+ }
696
+ sendResourceUpdated() {
697
+ }
698
+ };
699
+
700
+ // src/init.ts
701
+ function startMCPServer() {
702
+ if (typeof navigator !== "undefined" && "modelContext" in navigator) {
703
+ registerMcpAdapter(
704
+ new WebMCPAdapter(navigator.modelContext)
705
+ );
706
+ }
707
+ if (isAngieAvailable()) {
708
+ registerMcpAdapter(new AngieMcpAdapter(getSDK()));
709
+ }
710
+ activateAdapters();
711
+ signalMcpReady();
712
+ }
713
+ if (typeof document !== "undefined") {
714
+ document.addEventListener("DOMContentLoaded", () => startMCPServer(), { once: true });
715
+ } else {
716
+ startMCPServer();
717
+ }
718
+
512
719
  // src/index.ts
513
720
  var getAngieSdk = () => getSDK();
514
721
  // Annotate the CommonJS export names for ESM import in node:
@@ -518,19 +725,23 @@ var getAngieSdk = () => getSDK();
518
725
  McpServer,
519
726
  ResourceTemplate,
520
727
  SamplingMessageSchema,
521
- activateMcpRegistration,
728
+ activateAdapters,
522
729
  createSampler,
730
+ getActiveChatInfo,
523
731
  getAngieIframe,
524
732
  getAngieSdk,
525
733
  getMCPByDomain,
526
- init,
734
+ getRegisteredMcpServers,
527
735
  installAngiePlugin,
528
736
  isAngieAvailable,
529
737
  isAngieSidebarOpen,
530
738
  redirectToAppAdmin,
531
739
  redirectToInstallation,
532
740
  registerMcp,
741
+ registerMcpAdapter,
533
742
  sendPromptToAngie,
743
+ signalMcpReady,
744
+ startMCPServer,
534
745
  toMCPTitle,
535
746
  toolPrompts
536
747
  });