@wix/mcp 1.0.0 → 1.0.2
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 +17 -6
- package/bin.js +1 -1
- package/build/api-call/index.d.ts +2 -0
- package/build/api-call/index.js +118 -0
- package/build/bin.d.ts +6 -0
- package/build/bin.js +98 -0
- package/build/cli-tools/cli.d.ts +4 -0
- package/build/cli-tools/cli.js +7 -3
- package/build/cli-tools/utils.d.ts +2 -0
- package/build/cli-tools/utils.js +0 -19
- package/build/docs/docs.d.ts +4 -0
- package/build/docs/docs.js +193 -19
- package/build/docs/long-content.d.ts +1 -0
- package/build/docs/long-content.js +1 -0
- package/build/docs/semanticSearch.d.ts +10 -0
- package/build/docs/semanticSearch.js +31 -9
- package/build/docs/semanticSearch.test.d.ts +1 -0
- package/build/docs/semanticSearch.test.js +191 -21
- package/build/index.d.ts +5 -0
- package/build/index.js +5 -109
- package/build/interactive-command-tools/eventually.d.ts +6 -0
- package/build/interactive-command-tools/handleStdout.d.ts +13 -0
- package/build/interactive-command-tools/interactive-command-utils.d.ts +7 -0
- package/build/logger.d.ts +10 -0
- package/build/panorama.d.ts +2 -0
- package/build/panorama.js +8 -3
- package/build/resources/docs.d.ts +2 -0
- package/build/sentry.d.ts +1 -0
- package/build/tool-utils.d.ts +1 -0
- package/build/tool-utils.js +29 -0
- package/build/tool-utils.spec.d.ts +1 -0
- package/build/tool-utils.spec.js +119 -0
- package/build/wix-mcp-server.d.ts +16 -0
- package/package.json +11 -10
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ args: ["/Users/absolute/path/to/repo/dir/."]
|
|
|
18
18
|
|
|
19
19
|
```
|
|
20
20
|
command: node
|
|
21
|
-
args: ["/Users/absolute/path/to/build/
|
|
21
|
+
args: ["/Users/absolute/path/to/build/bin.js"]
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
# Optional config arguments:
|
|
@@ -29,6 +29,9 @@ args: ["/Users/absolute/path/to/build/index.js"]
|
|
|
29
29
|
### enable experimental tools:
|
|
30
30
|
`--experimental=WIX_API,CLI_COMMAND` - enable specific experimental tools (disabled by default)
|
|
31
31
|
|
|
32
|
+
### choose a CLI mode:
|
|
33
|
+
`--cli=wix-one` - specifies to use Wix One CLI mode (if not specified, default CLI mode is used)
|
|
34
|
+
|
|
32
35
|
### choose a logger:
|
|
33
36
|
`--logger=mcp` - log to MCP server (default)
|
|
34
37
|
`--logger=file` - log to file (in `~/wix-mcp-log.txt`)
|
|
@@ -63,6 +66,11 @@ It's exactly parallel to the real docs url, for example:
|
|
|
63
66
|
Docs URL: https://dev.wix.com/docs/picasso/wix-ai-docs/best-practices/sdk-best-practices
|
|
64
67
|
Resource URI: wix-docs://picasso/wix-ai-docs/best-practices/sdk-best-practices
|
|
65
68
|
|
|
69
|
+
pass:
|
|
70
|
+
`--portals=<docs-portal-name>`
|
|
71
|
+
to load all docs from the portal as resources
|
|
72
|
+
|
|
73
|
+
|
|
66
74
|
# Cursor
|
|
67
75
|
|
|
68
76
|
## Cursor MCP docs:
|
|
@@ -78,9 +86,10 @@ https://docs.cursor.com/context/model-context-protocol
|
|
|
78
86
|
```
|
|
79
87
|
{
|
|
80
88
|
"mcpServers": {
|
|
81
|
-
"
|
|
89
|
+
"wix-local-mcp": {
|
|
82
90
|
"command": "npx",
|
|
83
91
|
"args": [
|
|
92
|
+
"-y",
|
|
84
93
|
"@wix/mcp"
|
|
85
94
|
]
|
|
86
95
|
}
|
|
@@ -92,7 +101,7 @@ https://docs.cursor.com/context/model-context-protocol
|
|
|
92
101
|
```
|
|
93
102
|
{
|
|
94
103
|
"mcpServers": {
|
|
95
|
-
"
|
|
104
|
+
"wix-local-mcp": {
|
|
96
105
|
"command": "npx",
|
|
97
106
|
"args": [
|
|
98
107
|
"/Users/absolute/path/to/repo/dir/."
|
|
@@ -110,10 +119,10 @@ https://docs.cursor.com/context/model-context-protocol
|
|
|
110
119
|
```
|
|
111
120
|
{
|
|
112
121
|
"mcpServers": {
|
|
113
|
-
"
|
|
122
|
+
"wix-local-mcp": {
|
|
114
123
|
"command": "node",
|
|
115
124
|
"args": [
|
|
116
|
-
"/Users/absolute/path/to/build/
|
|
125
|
+
"/Users/absolute/path/to/build/bin.js"
|
|
117
126
|
]
|
|
118
127
|
}
|
|
119
128
|
}
|
|
@@ -123,7 +132,9 @@ https://docs.cursor.com/context/model-context-protocol
|
|
|
123
132
|
### You can try using bun + index.ts
|
|
124
133
|
|
|
125
134
|
# Troubleshooting
|
|
126
|
-
|
|
135
|
+
- check the logs from claude desktop / cursor
|
|
136
|
+
- is the error related to node / fnm / nvm ? make sure you have the latest node version as the default on in the path
|
|
137
|
+
- is the error related to npx? make sure you use -y and the correct npm registry
|
|
127
138
|
- try including full path to node
|
|
128
139
|
- try using bun and index.ts directly
|
|
129
140
|
- make sure build files have permissions for cursor to access
|
package/bin.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import './build/
|
|
2
|
+
import './build/bin.js';
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { logger } from '../logger.js';
|
|
3
|
+
import { handleWixAPIResponse } from '../tool-utils.js';
|
|
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`, {
|
|
7
|
+
siteId: z
|
|
8
|
+
.string()
|
|
9
|
+
.describe('The id of the site selected using site selection tool'),
|
|
10
|
+
url: z
|
|
11
|
+
.string()
|
|
12
|
+
.describe('The url of the api to call - ALWAYS get the information from the Wix REST docs or from the conversation context, the URL MUST BE ABSOLUTE URL'),
|
|
13
|
+
method: z
|
|
14
|
+
.string()
|
|
15
|
+
.describe('The HTTP method to use for the API call (e.g. GET, POST, PUT, DELETE)'),
|
|
16
|
+
body: z
|
|
17
|
+
.string()
|
|
18
|
+
.optional()
|
|
19
|
+
.describe('A string representing of a valid JSON object to describe the body of the request')
|
|
20
|
+
}, async ({ url, body, method, siteId }) => {
|
|
21
|
+
logger.log(`Calling Wix Site API: ${siteId} ${url}, body: ${JSON.stringify(body)}`);
|
|
22
|
+
const authorization = await getSiteAccessToken(siteId);
|
|
23
|
+
try {
|
|
24
|
+
const response = await fetch(url, {
|
|
25
|
+
method,
|
|
26
|
+
headers: {
|
|
27
|
+
Authorization: authorization,
|
|
28
|
+
...(body ? { 'Content-Type': 'application/json' } : {})
|
|
29
|
+
},
|
|
30
|
+
body: method === 'GET' ? undefined : body
|
|
31
|
+
});
|
|
32
|
+
const responseData = await handleWixAPIResponse(response);
|
|
33
|
+
return {
|
|
34
|
+
content: [
|
|
35
|
+
{
|
|
36
|
+
type: 'text',
|
|
37
|
+
text: `Wix Site API call successful: ${JSON.stringify(responseData)}`
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
logger.error(`Failed to call Wix Site API: ${error}`);
|
|
44
|
+
throw new Error(`Failed to call Wix Site API: ${error}`);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
server.tool('ListWixSites', 'List Wix sites for the current user', async () => {
|
|
48
|
+
const sitesRes = await fetch('https://www.wixapis.com/site-list/v2/sites/query', {
|
|
49
|
+
method: 'POST',
|
|
50
|
+
headers: {
|
|
51
|
+
'Content-Type': 'application/json',
|
|
52
|
+
Accept: 'application/json, text/plain, */*',
|
|
53
|
+
Authorization: await getAccountAccessToken()
|
|
54
|
+
},
|
|
55
|
+
body: JSON.stringify({
|
|
56
|
+
query: {
|
|
57
|
+
cursorPaging: { limit: 50 }
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
});
|
|
61
|
+
const result = await sitesRes.json().then(({ sites }) => sites?.map(({ id, displayName }) => ({
|
|
62
|
+
id,
|
|
63
|
+
name: displayName
|
|
64
|
+
})) ?? []);
|
|
65
|
+
return {
|
|
66
|
+
content: [
|
|
67
|
+
{
|
|
68
|
+
type: 'text',
|
|
69
|
+
text: JSON.stringify(result)
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
type: 'text',
|
|
73
|
+
text: 'if there is more than one site returned, the user should pick one from a list, list the sites (only name) for the user and ask them to pick one'
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
server.tool('ManageWixSite', `Use account level API in order to create a site, update a site and publish site.
|
|
79
|
+
ALWAYS use "SearchWixRESTDocumentation" to search for the API you should invoke, NEVER GUESS THE SITE API URL
|
|
80
|
+
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`, {
|
|
81
|
+
url: z
|
|
82
|
+
.string()
|
|
83
|
+
.describe('The url of the api to call - ALWAYS get the information from the Wix REST docs DONT GUESS IT, the URL MUST BE ABSOLUTE URL'),
|
|
84
|
+
method: z
|
|
85
|
+
.string()
|
|
86
|
+
.describe('The HTTP method to use for the API call (e.g. GET, POST, PUT, DELETE)'),
|
|
87
|
+
body: z
|
|
88
|
+
.string()
|
|
89
|
+
.optional()
|
|
90
|
+
.describe('A string representing of a valid JSON object to describe the body of the request')
|
|
91
|
+
}, async ({ url, body, method }) => {
|
|
92
|
+
logger.log(`Calling Wix Account level API: ${url}, body: ${JSON.stringify(body)}`);
|
|
93
|
+
const authorization = await getAccountAccessToken();
|
|
94
|
+
try {
|
|
95
|
+
const response = await fetch(url, {
|
|
96
|
+
method,
|
|
97
|
+
headers: {
|
|
98
|
+
Authorization: authorization,
|
|
99
|
+
...(body ? { 'Content-Type': 'application/json' } : {})
|
|
100
|
+
},
|
|
101
|
+
body: method === 'GET' ? undefined : body
|
|
102
|
+
});
|
|
103
|
+
const responseData = await handleWixAPIResponse(response);
|
|
104
|
+
return {
|
|
105
|
+
content: [
|
|
106
|
+
{
|
|
107
|
+
type: 'text',
|
|
108
|
+
text: `Wix Account API call successful: ${JSON.stringify(responseData)}`
|
|
109
|
+
}
|
|
110
|
+
]
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
logger.error(`Failed to call Wix Account API: ${error}`);
|
|
115
|
+
throw new Error(`Failed to call Wix Account API: ${error}`);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
}
|
package/build/bin.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import './sentry.js';
|
|
2
|
+
declare const PUBLIC_TOOLS: readonly ["WDS", "REST", "SDK", "BUILD_APPS", "WIX_HEADLESS", "BUSINESS_SOLUTIONS"];
|
|
3
|
+
declare const EXPERIMENTAL_TOOLS: readonly ["WIX_API", "CLI_COMMAND"];
|
|
4
|
+
type Tool = (typeof PUBLIC_TOOLS)[number] | (typeof EXPERIMENTAL_TOOLS)[number];
|
|
5
|
+
export declare const DEFAULT_TOOLS: Tool[];
|
|
6
|
+
export {};
|
package/build/bin.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import './sentry.js';
|
|
2
|
+
import minimist from 'minimist';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { addDocsTools, VALID_DOCS_TOOLS } from './docs/docs.js';
|
|
5
|
+
import { addCliTools, VALID_CLI_TOOLS } from './cli-tools/cli.js';
|
|
6
|
+
import { logger, attachStdErrLogger, attachMcpServerLogger, attachFileLogger } from './logger.js';
|
|
7
|
+
import { WixMcpServer } from './wix-mcp-server.js';
|
|
8
|
+
import { addDocsResources } from './resources/docs.js';
|
|
9
|
+
const PUBLIC_TOOLS = [...VALID_DOCS_TOOLS];
|
|
10
|
+
const EXPERIMENTAL_TOOLS = ['WIX_API', 'CLI_COMMAND'];
|
|
11
|
+
export const DEFAULT_TOOLS = [...VALID_DOCS_TOOLS];
|
|
12
|
+
const parsedArgs = minimist(process.argv.slice(2));
|
|
13
|
+
function parseExperimentalArg() {
|
|
14
|
+
const experimentalArg = parsedArgs['experimental'];
|
|
15
|
+
if (!experimentalArg)
|
|
16
|
+
return [];
|
|
17
|
+
return experimentalArg
|
|
18
|
+
.split(',')
|
|
19
|
+
.map((t) => t.trim())
|
|
20
|
+
.filter((tool) => EXPERIMENTAL_TOOLS.includes(tool));
|
|
21
|
+
}
|
|
22
|
+
function parseToolsArg() {
|
|
23
|
+
const toolsArg = parsedArgs['tools'];
|
|
24
|
+
const experimentalTools = parseExperimentalArg();
|
|
25
|
+
if (!toolsArg) {
|
|
26
|
+
// When no tools specified, return both default and experimental tools
|
|
27
|
+
return [...DEFAULT_TOOLS, ...experimentalTools];
|
|
28
|
+
}
|
|
29
|
+
const requestedTools = toolsArg.split(',').map((t) => t.trim());
|
|
30
|
+
const tools = [
|
|
31
|
+
// Include valid non-experimental tools
|
|
32
|
+
...requestedTools.filter((tool) => PUBLIC_TOOLS.includes(tool)),
|
|
33
|
+
// Include enabled experimental tools
|
|
34
|
+
...experimentalTools
|
|
35
|
+
];
|
|
36
|
+
// Warn about enabled experimental tools
|
|
37
|
+
tools.forEach((tool) => {
|
|
38
|
+
if (EXPERIMENTAL_TOOLS.includes(tool)) {
|
|
39
|
+
logger.log(`Warning: ${tool} is an experimental tool and may have limited functionality or breaking changes`);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
return tools;
|
|
43
|
+
}
|
|
44
|
+
const loggerType = parsedArgs['logger'] || 'mcp';
|
|
45
|
+
if (loggerType === 'file') {
|
|
46
|
+
attachFileLogger();
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
// Initially we log to stderr, because MCP server is not connected yet
|
|
50
|
+
// When the server is connected, we attach the MCP server logger
|
|
51
|
+
attachStdErrLogger();
|
|
52
|
+
}
|
|
53
|
+
logger.log('--------------------------------');
|
|
54
|
+
logger.log('starting WIX MCP server');
|
|
55
|
+
logger.log('--------------------------------');
|
|
56
|
+
const server = new WixMcpServer({
|
|
57
|
+
name: 'wix-mcp-server',
|
|
58
|
+
version: '1.0.0'
|
|
59
|
+
}, {
|
|
60
|
+
capabilities: {
|
|
61
|
+
tools: {},
|
|
62
|
+
prompts: {},
|
|
63
|
+
logging: {},
|
|
64
|
+
resources: {}
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
const activeTools = parseToolsArg();
|
|
68
|
+
logger.log('Active tools:', activeTools);
|
|
69
|
+
const docsTools = activeTools.filter((tool) => VALID_DOCS_TOOLS.includes(tool));
|
|
70
|
+
if (docsTools.length > 0) {
|
|
71
|
+
logger.log('Adding docs tools:', docsTools);
|
|
72
|
+
addDocsTools(server, docsTools);
|
|
73
|
+
}
|
|
74
|
+
const isWixOne = parsedArgs['cli'] === 'wix-one';
|
|
75
|
+
const cliTools = activeTools.filter((tool) => VALID_CLI_TOOLS.includes(tool));
|
|
76
|
+
if (cliTools.length > 0) {
|
|
77
|
+
logger.log('Adding cli tools:', cliTools, 'isWixOne:', isWixOne);
|
|
78
|
+
addCliTools(server, cliTools, isWixOne);
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
const portals = parsedArgs['portals']?.split(',') || [];
|
|
82
|
+
if (portals.length > 0) {
|
|
83
|
+
logger.log('Adding docs resources for portals:', portals);
|
|
84
|
+
await addDocsResources(server, portals);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
logger.error('Error adding docs resources:', error);
|
|
89
|
+
}
|
|
90
|
+
logger.log('Starting server');
|
|
91
|
+
const transport = new StdioServerTransport();
|
|
92
|
+
logger.log('Connecting to transport');
|
|
93
|
+
await server.connect(transport);
|
|
94
|
+
logger.log('Transport connected');
|
|
95
|
+
if (loggerType === 'mcp') {
|
|
96
|
+
// From now on, we log to the MCP server
|
|
97
|
+
attachMcpServerLogger(server);
|
|
98
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
export declare const VALID_CLI_TOOLS: readonly ["WIX_API", "CLI_COMMAND", "CLI_COMMAND_INTERACTIVE_MODE"];
|
|
3
|
+
export type CLITool = (typeof VALID_CLI_TOOLS)[number];
|
|
4
|
+
export declare function addCliTools(server: McpServer, allowedTools?: CLITool[], isWixOne?: boolean): void;
|
package/build/cli-tools/cli.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { getCliAuthTokenForSiteId, getSiteIdFromCliAppConfig
|
|
2
|
+
import { getCliAuthTokenForSiteId, getSiteIdFromCliAppConfig } from './utils.js';
|
|
3
3
|
import { logger } from '../logger.js';
|
|
4
4
|
import { execa } from 'execa';
|
|
5
5
|
import { mockInteractiveGenerateCommandTool } from '../interactive-command-tools/interactive-command-utils.js';
|
|
6
|
+
import { handleWixAPIResponse } from '../tool-utils.js';
|
|
6
7
|
export const VALID_CLI_TOOLS = [
|
|
7
8
|
'WIX_API',
|
|
8
9
|
'CLI_COMMAND',
|
|
@@ -12,7 +13,7 @@ export function addCliTools(server, allowedTools = [
|
|
|
12
13
|
'WIX_API',
|
|
13
14
|
'CLI_COMMAND',
|
|
14
15
|
'CLI_COMMAND_INTERACTIVE_MODE'
|
|
15
|
-
]) {
|
|
16
|
+
], isWixOne = false) {
|
|
16
17
|
if (allowedTools.includes('WIX_API')) {
|
|
17
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.', {
|
|
18
19
|
appPath: z
|
|
@@ -239,7 +240,7 @@ export function addCliTools(server, allowedTools = [
|
|
|
239
240
|
// Format generate command with proper arguments
|
|
240
241
|
commandName = 'npx';
|
|
241
242
|
commandArgs = [
|
|
242
|
-
'wix',
|
|
243
|
+
isWixOne ? 'wix-one' : 'wix',
|
|
243
244
|
'app',
|
|
244
245
|
'generate',
|
|
245
246
|
'-t',
|
|
@@ -254,6 +255,9 @@ export function addCliTools(server, allowedTools = [
|
|
|
254
255
|
commandName = commandParts[0];
|
|
255
256
|
commandArgs = commandParts.slice(1);
|
|
256
257
|
}
|
|
258
|
+
if (isWixOne && commandName === 'wix') {
|
|
259
|
+
commandName = 'wix-one';
|
|
260
|
+
}
|
|
257
261
|
try {
|
|
258
262
|
logger.log(`Executing Wix CLI command: ${commandName} ${commandArgs.join(' ')}`);
|
|
259
263
|
// Execute with timeout
|
package/build/cli-tools/utils.js
CHANGED
|
@@ -10,22 +10,3 @@ export function getSiteIdFromCliAppConfig(appPath) {
|
|
|
10
10
|
const appConfig = JSON.parse(readFileSync(path.join(appPath, '.wix/app.config.json'), 'utf8'));
|
|
11
11
|
return appConfig.siteId;
|
|
12
12
|
}
|
|
13
|
-
const safeParseJSON = (text) => {
|
|
14
|
-
try {
|
|
15
|
-
return JSON.parse(text);
|
|
16
|
-
}
|
|
17
|
-
catch {
|
|
18
|
-
return text;
|
|
19
|
-
}
|
|
20
|
-
};
|
|
21
|
-
export const handleWixAPIResponse = async (response) => {
|
|
22
|
-
const responseText = await response.text();
|
|
23
|
-
const responseData = safeParseJSON(responseText);
|
|
24
|
-
if (!response.ok) {
|
|
25
|
-
const errorDetails = typeof responseData === 'object'
|
|
26
|
-
? JSON.stringify(responseData)
|
|
27
|
-
: responseData;
|
|
28
|
-
throw new Error(`Failed to call Wix API: ${response.status} ${response.statusText}. ${errorDetails}`);
|
|
29
|
-
}
|
|
30
|
-
return responseData;
|
|
31
|
-
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { WixMcpServer } from '../wix-mcp-server.js';
|
|
2
|
+
export declare const VALID_DOCS_TOOLS: readonly ["WDS", "REST", "SDK", "BUILD_APPS", "WIX_HEADLESS", "BUSINESS_SOLUTIONS"];
|
|
3
|
+
export type DocsTool = (typeof VALID_DOCS_TOOLS)[number];
|
|
4
|
+
export declare const addDocsTools: (server: WixMcpServer, allowedTools?: DocsTool[]) => void;
|
package/build/docs/docs.js
CHANGED
|
@@ -7,14 +7,16 @@ export const VALID_DOCS_TOOLS = [
|
|
|
7
7
|
'REST',
|
|
8
8
|
'SDK',
|
|
9
9
|
'BUILD_APPS',
|
|
10
|
-
'WIX_HEADLESS'
|
|
10
|
+
'WIX_HEADLESS',
|
|
11
|
+
'BUSINESS_SOLUTIONS'
|
|
11
12
|
];
|
|
12
13
|
export const addDocsTools = (server, allowedTools = [
|
|
13
14
|
'WDS',
|
|
14
15
|
'REST',
|
|
15
16
|
'SDK',
|
|
16
17
|
'BUILD_APPS',
|
|
17
|
-
'WIX_HEADLESS'
|
|
18
|
+
'WIX_HEADLESS',
|
|
19
|
+
'BUSINESS_SOLUTIONS'
|
|
18
20
|
]) => {
|
|
19
21
|
// WDS Documentation
|
|
20
22
|
if (allowedTools.includes('WDS')) {
|
|
@@ -33,13 +35,17 @@ export const addDocsTools = (server, allowedTools = [
|
|
|
33
35
|
.min(1)
|
|
34
36
|
.max(15)
|
|
35
37
|
.optional()
|
|
36
|
-
.default(
|
|
38
|
+
.default(10)
|
|
37
39
|
}, async ({ searchTerm, maxResults }, { panorama }) => {
|
|
38
40
|
try {
|
|
39
41
|
logger.log(`Searching for ${searchTerm} in Wix WDS`);
|
|
40
|
-
const result = await runSemanticSearchAndFormat(
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
const result = await runSemanticSearchAndFormat({
|
|
43
|
+
toolName: 'WDS',
|
|
44
|
+
toolParams: {
|
|
45
|
+
searchTerm: searchTerm
|
|
46
|
+
},
|
|
47
|
+
maxResults: Math.max(1, Math.min(maxResults ?? 5, 15))
|
|
48
|
+
});
|
|
43
49
|
return {
|
|
44
50
|
content: [
|
|
45
51
|
{
|
|
@@ -82,18 +88,27 @@ export const addDocsTools = (server, allowedTools = [
|
|
|
82
88
|
.min(1)
|
|
83
89
|
.max(15)
|
|
84
90
|
.optional()
|
|
85
|
-
.default(
|
|
91
|
+
.default(10)
|
|
86
92
|
}, async ({ searchTerm, maxResults }, { panorama }) => {
|
|
87
93
|
try {
|
|
88
94
|
logger.log(`Searching for ${searchTerm} in Wix REST API`);
|
|
89
|
-
const result = await runSemanticSearchAndFormat(
|
|
90
|
-
|
|
91
|
-
|
|
95
|
+
const result = await runSemanticSearchAndFormat({
|
|
96
|
+
toolName: 'REST',
|
|
97
|
+
toolParams: {
|
|
98
|
+
searchTerm: searchTerm
|
|
99
|
+
},
|
|
100
|
+
maxResults: Math.max(1, Math.min(maxResults ?? 5, 15)),
|
|
101
|
+
linesInEachResult: 15
|
|
102
|
+
});
|
|
92
103
|
return {
|
|
93
104
|
content: [
|
|
94
105
|
{
|
|
95
106
|
type: 'text',
|
|
96
107
|
text: result
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
type: 'text',
|
|
111
|
+
text: 'Next, you MUST use the ReadFullDocsArticle tool if you want to read the full documentation for a specific article or method.'
|
|
97
112
|
}
|
|
98
113
|
]
|
|
99
114
|
};
|
|
@@ -114,6 +129,61 @@ export const addDocsTools = (server, allowedTools = [
|
|
|
114
129
|
}
|
|
115
130
|
});
|
|
116
131
|
}
|
|
132
|
+
if (allowedTools.includes('BUSINESS_SOLUTIONS')) {
|
|
133
|
+
server.tool('WixBusinessFlowsDocumentation', [
|
|
134
|
+
'This tool provides step-by-step recipes for setting up complex Wix business solutions that involve multiple API calls.',
|
|
135
|
+
'It excels at guiding the creation of features like booking systems with payments.',
|
|
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
|
+
'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.'
|
|
140
|
+
].join('\n'), {
|
|
141
|
+
searchTerm: z
|
|
142
|
+
.string()
|
|
143
|
+
.describe('The search term for the required sample flow (e.g. "setup a new business")'),
|
|
144
|
+
maxResults: z
|
|
145
|
+
.number()
|
|
146
|
+
.describe('The maximum number of results to return, default is 5, max is 15')
|
|
147
|
+
.min(1)
|
|
148
|
+
.max(15)
|
|
149
|
+
.optional()
|
|
150
|
+
.default(5)
|
|
151
|
+
}, async ({ searchTerm, maxResults }, { panorama }) => {
|
|
152
|
+
try {
|
|
153
|
+
logger.log(`Searching for ${searchTerm} in Wix Sample Flows`);
|
|
154
|
+
const result = await runSemanticSearchAndFormat({
|
|
155
|
+
toolName: 'BUSINESS_SOLUTIONS',
|
|
156
|
+
toolParams: {
|
|
157
|
+
searchTerm: '**RECIPE**: Business Recipes - full setup flow for::: ' +
|
|
158
|
+
searchTerm
|
|
159
|
+
},
|
|
160
|
+
maxResults: Math.max(1, Math.min(maxResults ?? 5, 15))
|
|
161
|
+
});
|
|
162
|
+
return {
|
|
163
|
+
content: [
|
|
164
|
+
{
|
|
165
|
+
type: 'text',
|
|
166
|
+
text: result
|
|
167
|
+
}
|
|
168
|
+
]
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
panorama.errorMonitor().reportError(error);
|
|
173
|
+
captureException(error, {
|
|
174
|
+
tags: {
|
|
175
|
+
componentId: 'SearchWixSampleFlowsDocumentation',
|
|
176
|
+
toolName: 'SearchWixSampleFlowsDocumentation'
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
logger.error(`Error searching for ${searchTerm} in Wix Sample Flows: ${error}`);
|
|
180
|
+
return {
|
|
181
|
+
isError: true,
|
|
182
|
+
content: [{ type: 'text', text: 'Error: ' + error.message }]
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
}
|
|
117
187
|
// SDK Documentation
|
|
118
188
|
if (allowedTools.includes('SDK')) {
|
|
119
189
|
server.tool('SearchWixSDKDocumentation', [
|
|
@@ -138,9 +208,14 @@ export const addDocsTools = (server, allowedTools = [
|
|
|
138
208
|
panorama
|
|
139
209
|
.transaction('SearchWixSDKDocumentation')
|
|
140
210
|
.start({ maxResults });
|
|
141
|
-
const result = await runSemanticSearchAndFormat(
|
|
142
|
-
|
|
143
|
-
|
|
211
|
+
const result = await runSemanticSearchAndFormat({
|
|
212
|
+
toolName: 'SDK',
|
|
213
|
+
toolParams: {
|
|
214
|
+
searchTerm: searchTerm
|
|
215
|
+
},
|
|
216
|
+
maxResults: Math.max(1, Math.min(maxResults ?? 5, 15)),
|
|
217
|
+
linesInEachResult: 15
|
|
218
|
+
});
|
|
144
219
|
panorama
|
|
145
220
|
.transaction('SearchWixSDKDocumentation')
|
|
146
221
|
.finish({ maxResults });
|
|
@@ -149,6 +224,10 @@ export const addDocsTools = (server, allowedTools = [
|
|
|
149
224
|
{
|
|
150
225
|
type: 'text',
|
|
151
226
|
text: result
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
type: 'text',
|
|
230
|
+
text: 'Next, you MUST use ReadFullDocsArticle tool if you want to read full documentation for a specific article or method.'
|
|
152
231
|
}
|
|
153
232
|
]
|
|
154
233
|
};
|
|
@@ -190,9 +269,13 @@ export const addDocsTools = (server, allowedTools = [
|
|
|
190
269
|
}, async ({ searchTerm, maxResults }, { panorama }) => {
|
|
191
270
|
try {
|
|
192
271
|
logger.log(`Searching for ${searchTerm} in Build Apps`);
|
|
193
|
-
const result = await runSemanticSearchAndFormat(
|
|
194
|
-
|
|
195
|
-
|
|
272
|
+
const result = await runSemanticSearchAndFormat({
|
|
273
|
+
toolName: 'BUILD_APPS',
|
|
274
|
+
toolParams: {
|
|
275
|
+
searchTerm: `wix cli docs for ${searchTerm}`
|
|
276
|
+
},
|
|
277
|
+
maxResults: Math.max(1, Math.min(maxResults ?? 5, 15))
|
|
278
|
+
});
|
|
196
279
|
return {
|
|
197
280
|
content: [
|
|
198
281
|
{
|
|
@@ -238,9 +321,13 @@ export const addDocsTools = (server, allowedTools = [
|
|
|
238
321
|
}, async ({ searchTerm, maxResults }, { panorama }) => {
|
|
239
322
|
try {
|
|
240
323
|
logger.log(`Searching for ${searchTerm} in Headless`);
|
|
241
|
-
const result = await runSemanticSearchAndFormat(
|
|
242
|
-
|
|
243
|
-
|
|
324
|
+
const result = await runSemanticSearchAndFormat({
|
|
325
|
+
toolName: 'WIX_HEADLESS',
|
|
326
|
+
toolParams: {
|
|
327
|
+
searchTerm: searchTerm
|
|
328
|
+
},
|
|
329
|
+
maxResults: Math.max(1, Math.min(maxResults ?? 5, 15))
|
|
330
|
+
});
|
|
244
331
|
return {
|
|
245
332
|
content: [
|
|
246
333
|
{
|
|
@@ -265,4 +352,91 @@ export const addDocsTools = (server, allowedTools = [
|
|
|
265
352
|
}
|
|
266
353
|
});
|
|
267
354
|
}
|
|
355
|
+
server.tool('ReadFullDocsArticle', [
|
|
356
|
+
'Fetches the full Wix docs article or method article.',
|
|
357
|
+
'Use this tool when you read a summary of a docs article or method article, you have the docs url and want to read the full article.'
|
|
358
|
+
].join('\n'), {
|
|
359
|
+
articleUrl: z
|
|
360
|
+
.string()
|
|
361
|
+
.describe('The URL of the docs article or method article to fetch. Should be something like https://dev.wix.com/docs/.../.../...')
|
|
362
|
+
}, async ({ articleUrl }) => {
|
|
363
|
+
try {
|
|
364
|
+
const articleContent = await fetchArticleContent(articleUrl, 'article');
|
|
365
|
+
if (!articleContent) {
|
|
366
|
+
throw new Error('Article content is empty');
|
|
367
|
+
}
|
|
368
|
+
return {
|
|
369
|
+
content: [
|
|
370
|
+
{
|
|
371
|
+
type: 'text',
|
|
372
|
+
text: articleContent
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
type: 'text',
|
|
376
|
+
text: [
|
|
377
|
+
'---',
|
|
378
|
+
'Next, if you are dealing with a method - you MUST call ReadFullDocsMethodSchema tool - it will give you the full request schema for the method.'
|
|
379
|
+
].join('\n')
|
|
380
|
+
}
|
|
381
|
+
]
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
catch (error) {
|
|
385
|
+
logger.error(`Error fetching article content or method schema for ${articleUrl}: ${error}`);
|
|
386
|
+
return {
|
|
387
|
+
content: [
|
|
388
|
+
{
|
|
389
|
+
type: 'text',
|
|
390
|
+
text: 'Could not fetch article content, you should try completing the task without it.'
|
|
391
|
+
}
|
|
392
|
+
]
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
server.tool('ReadFullDocsMethodSchema', [
|
|
397
|
+
'Fetches the full method schema for a given method. Always use it before calling the method.',
|
|
398
|
+
'This will give you the entire request/response schema with all the fields and their descriptions.'
|
|
399
|
+
].join('\n'), {
|
|
400
|
+
articleUrl: z
|
|
401
|
+
.string()
|
|
402
|
+
.describe('The URL of the documentation to fetch. Should be something like https://dev.wix.com/docs/.../.../...')
|
|
403
|
+
}, async ({ articleUrl }) => {
|
|
404
|
+
try {
|
|
405
|
+
const articleContent = await fetchArticleContent(articleUrl, 'methodSchema');
|
|
406
|
+
if (!articleContent) {
|
|
407
|
+
throw new Error('Method schema is empty');
|
|
408
|
+
}
|
|
409
|
+
return {
|
|
410
|
+
content: [
|
|
411
|
+
{
|
|
412
|
+
type: 'text',
|
|
413
|
+
text: articleContent
|
|
414
|
+
}
|
|
415
|
+
]
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
catch (error) {
|
|
419
|
+
logger.error(`Error fetching method schema for ${articleUrl}: ${error}`);
|
|
420
|
+
return {
|
|
421
|
+
content: [
|
|
422
|
+
{
|
|
423
|
+
type: 'text',
|
|
424
|
+
text: 'Could not fetch method schema, you should try completing the task without it.'
|
|
425
|
+
}
|
|
426
|
+
]
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
});
|
|
268
430
|
};
|
|
431
|
+
async function fetchArticleContent(articleUrl, mode) {
|
|
432
|
+
// https://dev.wix.com/digor/api/get-article-content?articleUrl=https://dev.wix.com/docs/rest/business-solutions/blog/draft-posts/create-draft-post&schema=true
|
|
433
|
+
const url = new URL(`https://dev.wix.com/digor/api/get-article-content`);
|
|
434
|
+
url.searchParams.set('articleUrl', articleUrl);
|
|
435
|
+
const schema = mode === 'methodSchema' ? 'true' : 'false';
|
|
436
|
+
url.searchParams.set('schema', schema);
|
|
437
|
+
logger.log(`Fetching resource from docs ${url.toString()}`);
|
|
438
|
+
const response = await fetch(url.toString());
|
|
439
|
+
const data = await response.json();
|
|
440
|
+
logger.log(`Fetched resource from docs: ${data.articleContent}`);
|
|
441
|
+
return data.articleContent;
|
|
442
|
+
}
|