@elementor/editor-mcp 4.1.0-789 → 4.1.0-791
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.d.mts +55 -10
- package/dist/index.d.ts +55 -10
- package/dist/index.js +301 -90
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +295 -88
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
- package/src/adapters/angie-adapter.ts +60 -0
- package/src/adapters/types.ts +48 -0
- package/src/adapters/web-mcp-adapter.ts +143 -0
- package/src/index.ts +2 -1
- package/src/init.ts +18 -22
- package/src/mcp-registry.ts +92 -57
- package/src/test-utils/mock-mcp-registry.ts +0 -3
- package/src/utils/get-active-chat-info.ts +19 -0
package/src/mcp-registry.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { z, type z3 } from '@elementor/schema';
|
|
2
|
-
import { type AngieMcpSdk } from '@elementor-external/angie-sdk';
|
|
3
2
|
import { McpServer, type ToolCallback } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
4
3
|
import { type RequestHandlerExtra } from '@modelcontextprotocol/sdk/shared/protocol.js';
|
|
4
|
+
import { UriTemplate } from '@modelcontextprotocol/sdk/shared/uriTemplate.js';
|
|
5
5
|
import { type ServerNotification, type ServerRequest } from '@modelcontextprotocol/sdk/types.js';
|
|
6
6
|
|
|
7
|
+
import { type IMcpRegistrationAdapter, type McpResourceHandler, type McpResourceUriOrTemplate } from './adapters/types';
|
|
7
8
|
import {
|
|
8
9
|
ANGIE_MODEL_PREFERENCES,
|
|
9
10
|
ANGIE_REQUIRED_RESOURCES,
|
|
@@ -11,7 +12,6 @@ import {
|
|
|
11
12
|
createDefaultModelPreferences,
|
|
12
13
|
} from './angie-annotations';
|
|
13
14
|
import { mockMcpRegistry } from './test-utils/mock-mcp-registry';
|
|
14
|
-
import { getSDK } from './utils/get-sdk';
|
|
15
15
|
|
|
16
16
|
type ZodRawShape = z3.ZodRawShape;
|
|
17
17
|
|
|
@@ -20,40 +20,56 @@ const mcpDescriptions: { [ namespace: string ]: string } = {};
|
|
|
20
20
|
// @ts-ignore - QUnit fails this
|
|
21
21
|
const isMcpRegistrationActivated = false || typeof globalThis.jest !== 'undefined';
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
};
|
|
23
|
+
const registrationAdapters: IMcpRegistrationAdapter[] = [];
|
|
24
|
+
const bufferedTools: Parameters< IMcpRegistrationAdapter[ 'onToolRegistered' ] >[] = [];
|
|
25
|
+
const bufferedResources: Parameters< IMcpRegistrationAdapter[ 'onResourceRegistered' ] >[] = [];
|
|
27
26
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
27
|
+
let resolveReady!: () => void;
|
|
28
|
+
const readyPromise = new Promise< void >( ( resolve ) => {
|
|
29
|
+
resolveReady = resolve;
|
|
30
|
+
} );
|
|
31
|
+
|
|
32
|
+
export const registerMcpAdapter = ( adapter: IMcpRegistrationAdapter ): void => {
|
|
33
|
+
registrationAdapters.push( adapter );
|
|
34
|
+
for ( const tool of bufferedTools ) {
|
|
35
|
+
try {
|
|
36
|
+
adapter.onToolRegistered( tool[ 0 ], tool[ 1 ] );
|
|
37
|
+
} catch {
|
|
38
|
+
// exit quietly
|
|
39
|
+
}
|
|
36
40
|
}
|
|
37
|
-
const
|
|
38
|
-
for await ( const entry of entries ) {
|
|
39
|
-
const [ key, mcpServer ] = entry;
|
|
41
|
+
for ( const resource of bufferedResources ) {
|
|
40
42
|
try {
|
|
41
|
-
|
|
42
|
-
title: toMCPTitle( key ),
|
|
43
|
-
name: `editor-${ key }`,
|
|
44
|
-
server: mcpServer,
|
|
45
|
-
version: '1.0.0',
|
|
46
|
-
description: mcpDescriptions[ key ] || key,
|
|
47
|
-
} );
|
|
43
|
+
adapter.onResourceRegistered( ...resource );
|
|
48
44
|
} catch {
|
|
49
|
-
|
|
45
|
+
// exit quietly
|
|
50
46
|
}
|
|
51
47
|
}
|
|
52
|
-
|
|
53
|
-
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export const signalMcpReady = (): void => resolveReady();
|
|
51
|
+
|
|
52
|
+
export const activateAdapters = (): void => callAdapters( ( adapter ) => adapter.activate() );
|
|
53
|
+
|
|
54
|
+
function callAdapters( fn: ( adapter: IMcpRegistrationAdapter ) => void ): void {
|
|
55
|
+
for ( const adapter of registrationAdapters ) {
|
|
56
|
+
try {
|
|
57
|
+
fn( adapter );
|
|
58
|
+
} catch {
|
|
59
|
+
// adapter failed — exit quietly, continue to next
|
|
60
|
+
}
|
|
54
61
|
}
|
|
55
62
|
}
|
|
56
63
|
|
|
64
|
+
export const registerMcp = ( mcp: McpServer, name: string ) => {
|
|
65
|
+
const mcpName = isAlphabet( name );
|
|
66
|
+
mcpRegistry[ mcpName ] = mcp;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export const getRegisteredMcpServers = (): Array< [ string, McpServer, string ] > => {
|
|
70
|
+
return Object.entries( mcpRegistry ).map( ( [ key, server ] ) => [ key, server, mcpDescriptions[ key ] || key ] );
|
|
71
|
+
};
|
|
72
|
+
|
|
57
73
|
const isAlphabet = ( str: string ): string | never => {
|
|
58
74
|
const passes = !! str && /^[a-z_]+$/.test( str );
|
|
59
75
|
if ( ! passes ) {
|
|
@@ -89,48 +105,50 @@ export const getMCPByDomain = ( namespace: string, options?: { instructions?: st
|
|
|
89
105
|
},
|
|
90
106
|
{
|
|
91
107
|
instructions: options?.instructions,
|
|
108
|
+
capabilities: { resources: { subscribe: true } },
|
|
92
109
|
}
|
|
93
110
|
);
|
|
111
|
+
if ( !! options?.instructions ) {
|
|
112
|
+
callAdapters( ( adapter ) =>
|
|
113
|
+
adapter.onResourceRegistered( `${ mcpName }`, { uriTemplate: new UriTemplate( mcpName ) }, () =>
|
|
114
|
+
Promise.resolve( { contents: [ { text: options.instructions ?? '' } ] } )
|
|
115
|
+
)
|
|
116
|
+
);
|
|
117
|
+
}
|
|
94
118
|
}
|
|
95
119
|
const mcpServer = mcpRegistry[ namespace ];
|
|
96
|
-
const { addTool } = createToolRegistry( mcpServer );
|
|
120
|
+
const { addTool } = createToolRegistry( mcpServer, mcpName );
|
|
97
121
|
return {
|
|
98
|
-
waitForReady: () =>
|
|
122
|
+
waitForReady: () => readyPromise,
|
|
99
123
|
// @ts-expect-error: TS is unable to infer the type here
|
|
100
124
|
resource: async ( ...args: Parameters< McpServer[ 'registerResource' ] > ) => {
|
|
101
|
-
|
|
125
|
+
const [ name, uriOrTemplate, ...rest ] = args as [ string, unknown, ...unknown[] ];
|
|
126
|
+
const handler = rest[ rest.length - 1 ] as McpResourceHandler;
|
|
127
|
+
const resourceArgs: Parameters< IMcpRegistrationAdapter[ 'onResourceRegistered' ] > = [
|
|
128
|
+
name,
|
|
129
|
+
uriOrTemplate as McpResourceUriOrTemplate,
|
|
130
|
+
handler,
|
|
131
|
+
];
|
|
132
|
+
bufferedResources.push( resourceArgs );
|
|
133
|
+
callAdapters( ( adapter ) => adapter.onResourceRegistered( ...resourceArgs ) );
|
|
102
134
|
return mcpServer.registerResource( ...args );
|
|
103
135
|
},
|
|
104
136
|
sendResourceUpdated: ( ...args: Parameters< McpServer[ 'server' ][ 'sendResourceUpdated' ] > ) => {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
137
|
+
callAdapters( ( adapter ) => adapter.sendResourceUpdated( { uri: args[ 0 ].uri } ) );
|
|
138
|
+
return Promise.resolve( mcpServer.server.sendResourceUpdated( ...args ) ).catch( ( error: Error ) => {
|
|
139
|
+
if ( error?.message?.includes( 'Not connected' ) ) {
|
|
140
|
+
return; // Expected when no MCP client is connected yet
|
|
141
|
+
}
|
|
142
|
+
if ( error?.message?.includes( 'does not support notifying about resources' ) ) {
|
|
143
|
+
return; // Server capability not declared — safe to ignore
|
|
144
|
+
}
|
|
145
|
+
throw error;
|
|
146
|
+
} );
|
|
114
147
|
},
|
|
115
|
-
mcpServer,
|
|
116
148
|
addTool,
|
|
117
149
|
setMCPDescription: ( description: string ) => {
|
|
118
150
|
mcpDescriptions[ namespace ] = description;
|
|
119
151
|
},
|
|
120
|
-
getActiveChatInfo: () => {
|
|
121
|
-
const info = localStorage.getItem( 'angie_active_chat_id' );
|
|
122
|
-
if ( ! info ) {
|
|
123
|
-
return {
|
|
124
|
-
expiresAt: 0,
|
|
125
|
-
sessionId: '',
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
const rawData = JSON.parse( info );
|
|
129
|
-
return {
|
|
130
|
-
expiresAt: rawData.expiresAt as number,
|
|
131
|
-
sessionId: rawData.sessionId as string,
|
|
132
|
-
};
|
|
133
|
-
},
|
|
134
152
|
};
|
|
135
153
|
};
|
|
136
154
|
|
|
@@ -139,10 +157,8 @@ export interface MCPRegistryEntry {
|
|
|
139
157
|
opts: ToolRegistrationOptions< T, O >
|
|
140
158
|
) => void;
|
|
141
159
|
setMCPDescription: ( description: string ) => void;
|
|
142
|
-
getActiveChatInfo: () => { sessionId: string; expiresAt: number };
|
|
143
160
|
sendResourceUpdated: McpServer[ 'server' ][ 'sendResourceUpdated' ];
|
|
144
161
|
resource: McpServer[ 'registerResource' ];
|
|
145
|
-
mcpServer: McpServer;
|
|
146
162
|
waitForReady: () => Promise< void >;
|
|
147
163
|
}
|
|
148
164
|
|
|
@@ -178,7 +194,7 @@ type ToolRegistrationOptions<
|
|
|
178
194
|
modelPreferences?: AngieModelPreferences;
|
|
179
195
|
};
|
|
180
196
|
|
|
181
|
-
function createToolRegistry( server: McpServer ) {
|
|
197
|
+
function createToolRegistry( server: McpServer, serverName: string ) {
|
|
182
198
|
function addTool<
|
|
183
199
|
T extends undefined | z.ZodRawShape = undefined,
|
|
184
200
|
O extends undefined | z.ZodRawShape = undefined,
|
|
@@ -246,6 +262,25 @@ function createToolRegistry( server: McpServer ) {
|
|
|
246
262
|
},
|
|
247
263
|
toolCallback
|
|
248
264
|
);
|
|
265
|
+
const toolDescriptor = {
|
|
266
|
+
name: opts.name,
|
|
267
|
+
description: opts.description,
|
|
268
|
+
inputSchema: inputSchema as object,
|
|
269
|
+
execute: ( params: Record< string, unknown > ) =>
|
|
270
|
+
Promise.resolve(
|
|
271
|
+
toolCallback(
|
|
272
|
+
params as Parameters< typeof toolCallback >[ 0 ],
|
|
273
|
+
/* WebMCP: no protocol session — handlers must not rely on `extra` here */
|
|
274
|
+
{} as RequestHandlerExtra< ServerRequest, ServerNotification >
|
|
275
|
+
)
|
|
276
|
+
),
|
|
277
|
+
};
|
|
278
|
+
const extraData = {
|
|
279
|
+
resources: [ `Server resource name: ${ serverName }, Required to fetch!` ],
|
|
280
|
+
requiredResources: opts.requiredResources?.map( ( resource ) => resource.uri ) ?? [],
|
|
281
|
+
};
|
|
282
|
+
bufferedTools.push( [ toolDescriptor, extraData ] );
|
|
283
|
+
callAdapters( ( adapter ) => adapter.onToolRegistered( toolDescriptor, extraData ) );
|
|
249
284
|
if ( isMcpRegistrationActivated ) {
|
|
250
285
|
server.sendToolListChanged();
|
|
251
286
|
}
|
|
@@ -21,9 +21,6 @@ export const mockMcpRegistry = (): MCPRegistryEntry => {
|
|
|
21
21
|
sendResourceUpdated: () => {},
|
|
22
22
|
addTool: () => {},
|
|
23
23
|
setMCPDescription: () => {},
|
|
24
|
-
getActiveChatInfo() {
|
|
25
|
-
return { sessionId: 'mock-session-id', expiresAt: Date.now() + 3600000 };
|
|
26
|
-
},
|
|
27
24
|
mcpServer: mock as McpServer,
|
|
28
25
|
};
|
|
29
26
|
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type ActiveChatInfo = {
|
|
2
|
+
sessionId: string;
|
|
3
|
+
expiresAt: number;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
export const getActiveChatInfo = (): ActiveChatInfo => {
|
|
7
|
+
const info = localStorage.getItem( 'angie_active_chat_id' );
|
|
8
|
+
if ( ! info ) {
|
|
9
|
+
return {
|
|
10
|
+
expiresAt: 0,
|
|
11
|
+
sessionId: '',
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
const rawData = JSON.parse( info );
|
|
15
|
+
return {
|
|
16
|
+
expiresAt: rawData.expiresAt as number,
|
|
17
|
+
sessionId: rawData.sessionId as string,
|
|
18
|
+
};
|
|
19
|
+
};
|