@wix/mcp 1.0.2 → 1.0.4

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/README.md CHANGED
@@ -140,3 +140,37 @@ https://docs.cursor.com/context/model-context-protocol
140
140
  - make sure build files have permissions for cursor to access
141
141
  - log should be written to `~/wix-mcp-log.txt`
142
142
  - add .env file with `WIX_COOKIE=` to avoid rate limits on SDK tool use
143
+
144
+ ## NVM possible fix:
145
+ ```
146
+ "wix-mcp-remote-prod": {
147
+ "command": "npx",
148
+ "args": [
149
+ "-y",
150
+ "@wix/mcp-remote",
151
+ "https://mcp.wix.com/sse"
152
+ ],
153
+ "env": {
154
+ "PATH": "<path-to-your-nvm-node-version>/bin"
155
+ }
156
+ }
157
+ ```
158
+
159
+ ## fnm possible fix:
160
+
161
+ ```
162
+ {
163
+ "mcpServers": {
164
+ "wix-mcp-remote-prod": {
165
+ "command": "sh",
166
+ "args": [
167
+ "-c",
168
+ "eval $(fnm env) && npx -y @wix/mcp-remote https://mcp.wix.com/sse"
169
+ ]
170
+ }
171
+ }
172
+ }
173
+ ```
174
+
175
+
176
+
@@ -2,8 +2,14 @@ import { z } from 'zod';
2
2
  import { logger } from '../logger.js';
3
3
  import { handleWixAPIResponse } from '../tool-utils.js';
4
4
  export function addApiCallTool(server, getSiteAccessToken, getAccountAccessToken) {
5
- server.tool('CallWixSiteAPI', 'Call Wix apis on a business or site. Use this to create, read, update, and delete data and other Wix entities in your Wix site,' +
6
- `You should ALWAYS check the rest docs - "SearchWixRESTDocumentation" for the specific API you want to call, don't just call it without knowing what it does, CHECK THE DOCS`, {
5
+ server.tool('CallWixSiteAPI', [
6
+ 'Call Wix apis on a business or site. Use this to create, read, update, and delete data and other Wix entities in your Wix site,',
7
+ `You should ALWAYS check the rest docs - "SearchWixRESTDocumentation" for the specific API you want to call, don't just call it without knowing what it does, CHECK THE DOCS`,
8
+ 'Error Handling:',
9
+ 'If the error is related to missing installed app or "WDE0110: Wix Code not enabled", you should install the missing app by using ReadFullDocsArticle tool to fetch the article - https://dev.wix.com/docs/kb-only/MCP_REST_RECIPES_KB_ID/TRAIN_wix.devcenter.apps.installer.v1.AppsInstallerService.InstallApp',
10
+ '**Note:** there is no need to check if an app is installed/ Wix Code enabled in advance, just call the API and handle the error if it occurs, the API error message will state it clearly.',
11
+ 'For any other error, use your default error handling mechanism'
12
+ ].join('\n'), {
7
13
  siteId: z
8
14
  .string()
9
15
  .describe('The id of the site selected using site selection tool'),
@@ -18,7 +18,12 @@ export function addCliTools(server, allowedTools = [
18
18
  server.tool('CallWixAPI', 'Call Wix apis on an app. Use this to create, read, update, and delete data and other Wix entities in your Wix app.', {
19
19
  appPath: z
20
20
  .string()
21
- .describe('The dir path to the wix backoffice cli app to call the api on behalf of'), // should we have appPath or siteId here? (appPath encapsulates this more since we can get the siteId from the appPath then perform the call)
21
+ .describe('The dir path to the wix backoffice cli app to call the api on behalf of. should have {appPath}/.wix/app.config.json file with a siteId field. if passed, siteId is not required')
22
+ .optional(), // should we have appPath or siteId here? (appPath encapsulates this more since we can get the siteId from the appPath then perform the call)
23
+ siteId: z
24
+ .string()
25
+ .describe('The siteId of the wix backoffice cli app to call the api on behalf of. You can find the siteId in the {appPath}/.wix/app.config.json file. You can pass any other siteId if you want to call the api on behalf of a different site. If passed, appPath is not required. if not passed, the appPath must be provided.')
26
+ .optional(),
22
27
  url: z
23
28
  .string()
24
29
  .describe('The url of the api to call - usually you get this from the Wix REST docs or from the conversation context'),
@@ -29,11 +34,44 @@ export function addCliTools(server, allowedTools = [
29
34
  .string()
30
35
  .optional()
31
36
  .describe('A string representing of a valid JSON object to describe the body of the request')
32
- }, async ({ method, url, body, appPath }) => {
33
- logger.log(`Calling Wix API: ${appPath} ${method} ${url}, body: ${JSON.stringify(body)}`);
34
- const siteId = getSiteIdFromCliAppConfig(appPath);
35
- logger.log(`Site ID for Wix API call: ${siteId}`);
36
- const authorization = getCliAuthTokenForSiteId(siteId);
37
+ }, async ({ method, url, body, appPath, siteId }) => {
38
+ logger.log(`Calling Wix API: ${appPath} ${siteId} ${method} ${url}, body: ${JSON.stringify(body)}`);
39
+ if (!siteId && !appPath) {
40
+ return {
41
+ content: [
42
+ {
43
+ type: 'text',
44
+ text: 'Either appPath or siteId must be provided'
45
+ }
46
+ ]
47
+ };
48
+ }
49
+ let siteIdToUse = siteId;
50
+ if (!siteIdToUse && appPath) {
51
+ siteIdToUse = getSiteIdFromCliAppConfig(appPath);
52
+ }
53
+ if (!siteIdToUse) {
54
+ return {
55
+ content: [
56
+ {
57
+ type: 'text',
58
+ text: 'Either appPath or siteId must be provided'
59
+ }
60
+ ]
61
+ };
62
+ }
63
+ logger.log(`Site ID for Wix API call: ${siteIdToUse}`);
64
+ const authorization = getCliAuthTokenForSiteId(siteIdToUse);
65
+ if (!authorization) {
66
+ return {
67
+ content: [
68
+ {
69
+ type: 'text',
70
+ text: 'Failed to get authorization token. Please check your siteId and appPath'
71
+ }
72
+ ]
73
+ };
74
+ }
37
75
  try {
38
76
  const response = await fetch(url, {
39
77
  method,
@@ -184,7 +222,7 @@ export function addCliTools(server, allowedTools = [
184
222
  DO NOT USE THIS TOOL FOR ANY OTHER PURPOSE. IT IS ONLY FOR WIX CLI COMMANDS.`, {
185
223
  appPath: z
186
224
  .string()
187
- .describe('The full path to the Wix CLI app to run the command on'),
225
+ .describe('The full path to the Wix CLI app to run the command on.'),
188
226
  extensionType: z
189
227
  .enum([
190
228
  'dashboard-page',
@@ -36,7 +36,7 @@ export const addDocsTools = (server, allowedTools = [
36
36
  .max(15)
37
37
  .optional()
38
38
  .default(10)
39
- }, async ({ searchTerm, maxResults }, { panorama }) => {
39
+ }, async ({ searchTerm, maxResults }) => {
40
40
  try {
41
41
  logger.log(`Searching for ${searchTerm} in Wix WDS`);
42
42
  const result = await runSemanticSearchAndFormat({
@@ -56,7 +56,7 @@ export const addDocsTools = (server, allowedTools = [
56
56
  };
57
57
  }
58
58
  catch (error) {
59
- panorama.errorMonitor().reportError(error);
59
+ // panorama.errorMonitor().reportError(error);
60
60
  captureException(error, {
61
61
  tags: {
62
62
  componentId: 'SearchWixWDSDocumentation',
@@ -89,7 +89,7 @@ export const addDocsTools = (server, allowedTools = [
89
89
  .max(15)
90
90
  .optional()
91
91
  .default(10)
92
- }, async ({ searchTerm, maxResults }, { panorama }) => {
92
+ }, async ({ searchTerm, maxResults }) => {
93
93
  try {
94
94
  logger.log(`Searching for ${searchTerm} in Wix REST API`);
95
95
  const result = await runSemanticSearchAndFormat({
@@ -114,7 +114,7 @@ export const addDocsTools = (server, allowedTools = [
114
114
  };
115
115
  }
116
116
  catch (error) {
117
- panorama.errorMonitor().reportError(error);
117
+ // panorama.errorMonitor().reportError(error);
118
118
  captureException(error, {
119
119
  tags: {
120
120
  componentId: 'SearchWixRESTDocumentation',
@@ -135,8 +135,10 @@ export const addDocsTools = (server, allowedTools = [
135
135
  'It excels at guiding the creation of features like booking systems with payments.',
136
136
  'For example, it can guide the setup of a service in Wix Bookings where customers can pay using Wix Payments, such as creating a bookable yoga class',
137
137
  'It searches the Wix Business Solutions documentation for these integrated workflows involving services, bookings, payments, stores, blogs, and more.',
138
- 'Before attempting to implement a multi step API calls on Wix, YOU MUST TRY THIS TOOL FIRST.',
139
- 'If the result includes a link to another article, use ReadFullDocsArticle tool to fetch the full article.'
138
+ 'This tool returns a list of articles that are potentially relevant to the input search term.',
139
+ '**IMPORTANT NOTES:**',
140
+ '1. Before attempting to implement a multi step API calls on Wix, YOU MUST TRY THIS TOOL FIRST.',
141
+ '2. Out of the returned list of articles that you will receive, you MUST select the most relevant one and use the ReadFullDocsArticle tool to fetch it.'
140
142
  ].join('\n'), {
141
143
  searchTerm: z
142
144
  .string()
@@ -148,7 +150,7 @@ export const addDocsTools = (server, allowedTools = [
148
150
  .max(15)
149
151
  .optional()
150
152
  .default(5)
151
- }, async ({ searchTerm, maxResults }, { panorama }) => {
153
+ }, async ({ searchTerm, maxResults }) => {
152
154
  try {
153
155
  logger.log(`Searching for ${searchTerm} in Wix Sample Flows`);
154
156
  const result = await runSemanticSearchAndFormat({
@@ -164,12 +166,16 @@ export const addDocsTools = (server, allowedTools = [
164
166
  {
165
167
  type: 'text',
166
168
  text: result
169
+ },
170
+ {
171
+ type: 'text',
172
+ text: `Out of the included list of articles, you **MUST** select the one that is most relevant to the user's request and use the ReadFullDocsArticle tool to fetch it.`
167
173
  }
168
174
  ]
169
175
  };
170
176
  }
171
177
  catch (error) {
172
- panorama.errorMonitor().reportError(error);
178
+ // panorama.errorMonitor().reportError(error);
173
179
  captureException(error, {
174
180
  tags: {
175
181
  componentId: 'SearchWixSampleFlowsDocumentation',
@@ -202,12 +208,12 @@ export const addDocsTools = (server, allowedTools = [
202
208
  .max(15)
203
209
  .optional()
204
210
  .default(5)
205
- }, async ({ searchTerm, maxResults }, { panorama }) => {
211
+ }, async ({ searchTerm, maxResults }) => {
206
212
  try {
207
213
  logger.log(`Searching for ${searchTerm} in Wix SDK`);
208
- panorama
209
- .transaction('SearchWixSDKDocumentation')
210
- .start({ maxResults });
214
+ // panorama
215
+ // .transaction('SearchWixSDKDocumentation')
216
+ // .start({ maxResults });
211
217
  const result = await runSemanticSearchAndFormat({
212
218
  toolName: 'SDK',
213
219
  toolParams: {
@@ -216,9 +222,9 @@ export const addDocsTools = (server, allowedTools = [
216
222
  maxResults: Math.max(1, Math.min(maxResults ?? 5, 15)),
217
223
  linesInEachResult: 15
218
224
  });
219
- panorama
220
- .transaction('SearchWixSDKDocumentation')
221
- .finish({ maxResults });
225
+ // panorama
226
+ // .transaction('SearchWixSDKDocumentation')
227
+ // .finish({ maxResults });
222
228
  return {
223
229
  content: [
224
230
  {
@@ -233,7 +239,7 @@ export const addDocsTools = (server, allowedTools = [
233
239
  };
234
240
  }
235
241
  catch (error) {
236
- panorama.errorMonitor().reportError(error);
242
+ // panorama.errorMonitor().reportError(error);
237
243
  captureException(error, {
238
244
  tags: {
239
245
  componentId: 'SearchWixSDKDocumentation',
@@ -266,7 +272,7 @@ export const addDocsTools = (server, allowedTools = [
266
272
  .max(15)
267
273
  .optional()
268
274
  .default(5)
269
- }, async ({ searchTerm, maxResults }, { panorama }) => {
275
+ }, async ({ searchTerm, maxResults }) => {
270
276
  try {
271
277
  logger.log(`Searching for ${searchTerm} in Build Apps`);
272
278
  const result = await runSemanticSearchAndFormat({
@@ -286,7 +292,7 @@ export const addDocsTools = (server, allowedTools = [
286
292
  };
287
293
  }
288
294
  catch (error) {
289
- panorama.errorMonitor().reportError(error);
295
+ // panorama.errorMonitor().reportError(error);
290
296
  captureException(error, {
291
297
  tags: {
292
298
  componentId: 'SearchBuildAppsDocumentation',
@@ -318,7 +324,7 @@ export const addDocsTools = (server, allowedTools = [
318
324
  .max(15)
319
325
  .optional()
320
326
  .default(5)
321
- }, async ({ searchTerm, maxResults }, { panorama }) => {
327
+ }, async ({ searchTerm, maxResults }) => {
322
328
  try {
323
329
  logger.log(`Searching for ${searchTerm} in Headless`);
324
330
  const result = await runSemanticSearchAndFormat({
@@ -338,7 +344,7 @@ export const addDocsTools = (server, allowedTools = [
338
344
  };
339
345
  }
340
346
  catch (error) {
341
- panorama.errorMonitor().reportError(error);
347
+ // panorama.errorMonitor().reportError(error);
342
348
  captureException(error, {
343
349
  tags: {
344
350
  componentId: 'SearchWixHeadlessDocumentation',
package/build/index.d.ts CHANGED
@@ -3,3 +3,4 @@ export { addDocsTools, DocsTool, VALID_DOCS_TOOLS } from './docs/docs.js';
3
3
  export { addApiCallTool } from './api-call/index.js';
4
4
  export { handleWixAPIResponse } from './tool-utils.js';
5
5
  export { addDocsResources } from './resources/docs.js';
6
+ export { addSupportTool } from './support/index.js';
package/build/index.js CHANGED
@@ -3,3 +3,4 @@ export { addDocsTools, VALID_DOCS_TOOLS } from './docs/docs.js';
3
3
  export { addApiCallTool } from './api-call/index.js';
4
4
  export { handleWixAPIResponse } from './tool-utils.js';
5
5
  export { addDocsResources } from './resources/docs.js';
6
+ export { addSupportTool } from './support/index.js';
@@ -0,0 +1,2 @@
1
+ import { WixMcpServer } from '../wix-mcp-server.js';
2
+ export declare function addSupportTool(server: WixMcpServer): void;
@@ -0,0 +1,32 @@
1
+ import { z } from 'zod';
2
+ export function addSupportTool(server) {
3
+ server.tool('SupportAndFeedback', [
4
+ 'If the user would like to provide Wix with some feedback (good or bad), about the tools in Wix MCP,',
5
+ 'for example they used the tools provided, and they reflected satisfaction or dissatisfaction with the tools.',
6
+ 'Also, if you encounter too many errors tyring to call the Wix API, you can also suggest the user to provide feedback to Wix using this tool.',
7
+ '**IMPORTANT NOTE**',
8
+ 'This tool is not sending the message, but formats it in order to another tool to actually send it'
9
+ ].join('\n'), {
10
+ requestId: z
11
+ .string()
12
+ .optional()
13
+ .describe('request id if returned from the server in a failed API call to Wix'),
14
+ message: z.string().describe('The message to send to Wix')
15
+ }, async ({ requestId, message }) => {
16
+ return {
17
+ content: [
18
+ {
19
+ type: 'text',
20
+ text: `${message} ${requestId ? `request id: ${requestId}` : ''}`
21
+ },
22
+ {
23
+ type: 'text',
24
+ text: 'You should present the user with the formatted message above and ask if they would like to send it to Wix.' +
25
+ 'If the user confirms, you can get the details about send feedback API from the article `https://dev.wix.com/docs/kb-only/MCP_REST_RECIPES_KB_ID/TRAIN_send_mcp_feedback_to_wix_from_user`.' +
26
+ 'You can use the `ReadFullDocsArticle` tool to fetch the article and get the details about the API call.' +
27
+ 'Once you have the details, you can use the `ManageWixSite` (if site id is in context) or `CallWixSiteAPI` (if site id is not in context) tool to call the API and send the feedback to Wix.'
28
+ }
29
+ ]
30
+ };
31
+ });
32
+ }
@@ -18,7 +18,7 @@ export const handleWixAPIResponse = async (response) => {
18
18
  `Failed to call Wix API: ${response.status} ${response.statusText}.`,
19
19
  requestId ? `request id: ${requestId}` : '',
20
20
  // Wix 404 for API does not exist is huge (generic 404 page) and loaded to the context
21
- response.status === 404 && errorDetails.includes('<html>')
21
+ response.status === 404 && errorDetails.includes('<html')
22
22
  ? 'Not found'
23
23
  : errorDetails
24
24
  ]
@@ -1,11 +1,8 @@
1
1
  import type { z, ZodRawShape, ZodTypeAny } from 'zod';
2
2
  import type { RequestHandlerExtra } from '@modelcontextprotocol/sdk/shared/protocol.js';
3
3
  import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
4
- import type { PanoramaClientForComponent } from '@wix/panorama-client-node';
5
4
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
6
- type WixRequestHandlerExtra = RequestHandlerExtra & {
7
- panorama: PanoramaClientForComponent;
8
- };
5
+ type WixRequestHandlerExtra = RequestHandlerExtra & {};
9
6
  type WixToolCallback<Args extends undefined | ZodRawShape = undefined> = Args extends ZodRawShape ? (args: z.objectOutputType<Args, ZodTypeAny>, extra: WixRequestHandlerExtra) => CallToolResult | Promise<CallToolResult> : (extra: WixRequestHandlerExtra) => CallToolResult | Promise<CallToolResult>;
10
7
  export declare class WixMcpServer extends McpServer {
11
8
  tool(name: string, cb: WixToolCallback): void;
@@ -1,6 +1,7 @@
1
+ // import type { PanoramaClientForComponent } from '@wix/panorama-client-node';
1
2
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
- import { globalConfig, panoramaFactory } from './panorama.js';
3
- import { captureException, setTags } from '@sentry/node';
3
+ //import { globalConfig, panoramaFactory } from './panorama.js';
4
+ import { captureException } from '@sentry/node';
4
5
  export class WixMcpServer extends McpServer {
5
6
  tool(...args) {
6
7
  const cbIndex = args.findIndex((arg) => typeof arg === 'function');
@@ -8,29 +9,29 @@ export class WixMcpServer extends McpServer {
8
9
  const originalCb = args[cbIndex];
9
10
  const toolName = args[0];
10
11
  const panoramaComponentId = toolName;
11
- const panorama = panoramaFactory.client({
12
- baseParams: {
13
- componentId: panoramaComponentId
14
- }
15
- });
16
- setTags({
17
- panoramaSessionId: globalConfig.getSessionId()
18
- });
12
+ /*const panorama = panoramaFactory.client({
13
+ baseParams: {
14
+ componentId: panoramaComponentId
15
+ }
16
+ });*/
17
+ /*setTags({
18
+ panoramaSessionId: globalConfig.getSessionId()
19
+ });*/
19
20
  const wrappedCb = async (...cbArgs) => {
20
21
  const argsBeforeExtra = cbArgs.slice(0, cbArgs.length - 1);
21
22
  const extra = cbArgs[cbArgs.length - 1];
22
23
  const wrappedExtra = {
23
- ...extra,
24
- panorama: panorama.createClientForComponent()
24
+ ...extra
25
+ // panorama: panorama.createClientForComponent()
25
26
  };
26
- panorama.transaction(toolName).start();
27
+ //panorama.transaction(toolName).start();
27
28
  try {
28
29
  const cbResult = await originalCb(...argsBeforeExtra, wrappedExtra);
29
- panorama.transaction(toolName).finish();
30
+ //panorama.transaction(toolName).finish();
30
31
  return cbResult;
31
32
  }
32
33
  catch (e) {
33
- panorama.errorMonitor().reportError(e);
34
+ //panorama.errorMonitor().reportError(e as Error);
34
35
  captureException(e, {
35
36
  tags: {
36
37
  componentId: panoramaComponentId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/mcp",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "A Model Context Protocol server for Wix AI tools",
5
5
  "type": "module",
6
6
  "bin": "./bin.js",
@@ -23,7 +23,6 @@
23
23
  "dependencies": {
24
24
  "@modelcontextprotocol/sdk": "^1.9.0",
25
25
  "@sentry/node": "^9.13.0",
26
- "@wix/panorama-client-node": "^3.227.0",
27
26
  "execa": "^9.5.2",
28
27
  "minimist": "^1.2.8",
29
28
  "strip-ansi": "^7.1.0",
@@ -32,17 +31,17 @@
32
31
  "zod": "^3.24.3"
33
32
  },
34
33
  "devDependencies": {
35
- "@eslint/js": "^9.25.0",
34
+ "@eslint/js": "^9.25.1",
36
35
  "@types/express": "^5.0.1",
37
36
  "@types/minimist": "^1.2.5",
38
- "@types/node": "^20.17.30",
39
- "eslint": "^9.25.0",
37
+ "@types/node": "^20.17.31",
38
+ "eslint": "^9.25.1",
40
39
  "eslint-config-prettier": "^10.1.2",
41
40
  "eslint-plugin-prettier": "^5.2.6",
42
41
  "globals": "^16.0.0",
43
42
  "prettier": "^3.5.3",
44
43
  "typescript": "^5.8.3",
45
- "typescript-eslint": "^8.30.1",
44
+ "typescript-eslint": "^8.31.0",
46
45
  "vitest": "^3.1.2"
47
46
  },
48
47
  "exports": {
@@ -63,5 +62,5 @@
63
62
  ]
64
63
  }
65
64
  },
66
- "falconPackageHash": "bebb972f9d803a633e2609035dfd5fc65e5498fe3690a8393291520b"
65
+ "falconPackageHash": "4fdd1bedb002c7deddf1dd04c2810b00c9864cbed6168260ad3a32d0"
67
66
  }
@@ -1,2 +0,0 @@
1
- export declare const globalConfig: import("@wix/panorama-client-node").GlobalConfig<import("@wix/panorama-common-shared/dist/types/types/data-types.js").EventPayload, {}>;
2
- export declare const panoramaFactory: import("@wix/panorama-client").PanoramaClientFactory<import("@wix/panorama-common-shared/dist/types/types/data-types.js").EventPayload>;
package/build/panorama.js DELETED
@@ -1,23 +0,0 @@
1
- // import { createRequire } from 'module';
2
- import { createGlobalConfig, panoramaClientFactory, PanoramaPlatform } from '@wix/panorama-client-node';
3
- // const require = createRequire(import.meta.url);
4
- // const packageJson = require('../package.json');
5
- // TODO: use real package.json
6
- // I temporarily disabled this because it's not working in the remote server
7
- const packageJson = {
8
- version: '1.0.0'
9
- };
10
- export const globalConfig = createGlobalConfig();
11
- export const panoramaFactory = panoramaClientFactory({
12
- baseParams: {
13
- platform: PanoramaPlatform.Standalone,
14
- fullArtifactId: 'com.wixpress.spartans.wix-mcp',
15
- artifactVersion: packageJson.version
16
- },
17
- data: {
18
- packageVersion: packageJson.version,
19
- versions: process.versions,
20
- platform: process.platform,
21
- arch: process.arch
22
- }
23
- }).withGlobalConfig(globalConfig);