@wix/mcp 1.0.7 → 1.0.8
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/build/api-call/index.d.ts +2 -1
- package/build/api-call/index.js +149 -0
- package/build/auth/index.d.ts +5 -0
- package/build/bin-standalone.js +16370 -0
- package/build/bin-standalone.js.map +7 -0
- package/build/bin.d.ts +1 -1
- package/build/bin.js +82 -665
- package/build/cli-tools/cli.d.ts +2 -2
- package/build/cli-tools/cli.js +339 -0
- package/build/cli-tools/utils.js +25 -0
- package/build/docs/docs.js +447 -0
- package/build/docs/long-content.js +1 -0
- package/build/docs/semanticSearch.js +108 -0
- package/build/docs/semanticSearch.test.js +459 -0
- package/build/index-standalone.js +18849 -0
- package/build/index-standalone.js.map +7 -0
- package/build/index.d.ts +1 -0
- package/build/index.js +6 -201
- package/build/infra/bi-logger.d.ts +2 -0
- package/build/infra/bi-logger.js +10 -0
- package/build/infra/environment.d.ts +9 -0
- package/build/infra/environment.js +27 -0
- package/build/infra/logger.js +61 -0
- package/build/infra/panorama.d.ts +7 -0
- package/build/infra/panorama.js +35 -0
- package/build/infra/sentry.d.ts +1 -0
- package/build/infra/sentry.js +10 -0
- package/build/interactive-command-tools/eventually.js +15 -0
- package/build/interactive-command-tools/handleStdout.js +75 -0
- package/build/interactive-command-tools/interactive-command-utils.js +75 -0
- package/build/resources/docs.js +45 -0
- package/build/support/index.js +32 -0
- package/build/tool-utils.d.ts +2 -1
- package/build/tool-utils.js +30 -0
- package/build/tool-utils.spec.js +99 -0
- package/build/wix-mcp-server.d.ts +12 -1
- package/build/wix-mcp-server.js +114 -0
- package/package.json +15 -10
- package/bin.js +0 -2
- package/build/bin.js.map +0 -7
- package/build/chunk-QGIZNLF4.js +0 -8179
- package/build/chunk-QGIZNLF4.js.map +0 -7
- package/build/index.js.map +0 -7
- package/build/panorama.d.ts +0 -2
- /package/build/{sentry.d.ts → auth/index.js} +0 -0
- /package/build/{logger.d.ts → infra/logger.d.ts} +0 -0
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
import { describe, test, expect, beforeEach, vi, afterAll } from 'vitest';
|
|
2
|
+
import { DEFAULT_MAX_RESULTS, runSemanticSearchAndFormat } from './semanticSearch.js';
|
|
3
|
+
import { LONG_KB_CONTENT } from './long-content.js';
|
|
4
|
+
const sampleSearchResponse = {
|
|
5
|
+
results: {
|
|
6
|
+
SDK_DOCS_KB_ID: {
|
|
7
|
+
results: [
|
|
8
|
+
{
|
|
9
|
+
entry: {
|
|
10
|
+
content: 'SDK Documentation content 1\nline 2\nline 3'
|
|
11
|
+
},
|
|
12
|
+
scoresInfo: {
|
|
13
|
+
overallMatchScore: 0.95
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
entry: {
|
|
18
|
+
content: 'SDK Documentation content 2'
|
|
19
|
+
},
|
|
20
|
+
scoresInfo: {
|
|
21
|
+
overallMatchScore: 0.85
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
entry: {
|
|
26
|
+
content: LONG_KB_CONTENT,
|
|
27
|
+
chunkedContent: ['some-chunked-content']
|
|
28
|
+
},
|
|
29
|
+
scoresInfo: {
|
|
30
|
+
overallMatchScore: 0.83
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
SDK_SCHEMAS_KB_ID: {
|
|
36
|
+
results: [
|
|
37
|
+
{
|
|
38
|
+
entry: {
|
|
39
|
+
content: 'SDK Schema content 1'
|
|
40
|
+
},
|
|
41
|
+
scoresInfo: {
|
|
42
|
+
overallMatchScore: 0.9
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
},
|
|
47
|
+
BUILD_APPS_KB_ID: {
|
|
48
|
+
results: [
|
|
49
|
+
{
|
|
50
|
+
entry: {
|
|
51
|
+
content: 'Build Apps content 1'
|
|
52
|
+
},
|
|
53
|
+
scoresInfo: {
|
|
54
|
+
overallMatchScore: 0.88
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
MCP_REST_RECIPES_KB_ID: {
|
|
60
|
+
results: [
|
|
61
|
+
{
|
|
62
|
+
entry: {
|
|
63
|
+
content: 'Build Apps content 1'
|
|
64
|
+
},
|
|
65
|
+
scoresInfo: {
|
|
66
|
+
overallMatchScore: 0.92
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
const originalProcessEnv = process.env;
|
|
74
|
+
describe('Semantic Search', () => {
|
|
75
|
+
let fetchMock;
|
|
76
|
+
global.fetch = vi.fn();
|
|
77
|
+
beforeEach(() => {
|
|
78
|
+
vi.clearAllMocks();
|
|
79
|
+
process.env = { ...originalProcessEnv };
|
|
80
|
+
fetchMock = global.fetch;
|
|
81
|
+
fetchMock.mockReset();
|
|
82
|
+
fetchMock.mockResolvedValue({
|
|
83
|
+
ok: true,
|
|
84
|
+
status: 200,
|
|
85
|
+
statusText: 'OK',
|
|
86
|
+
json: async () => sampleSearchResponse
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
afterAll(() => {
|
|
90
|
+
process.env = originalProcessEnv;
|
|
91
|
+
});
|
|
92
|
+
test('performs SDK semantic search successfully', async () => {
|
|
93
|
+
const sdkResponse = {
|
|
94
|
+
results: {
|
|
95
|
+
SDK_DOCS_KB_ID: {
|
|
96
|
+
results: [
|
|
97
|
+
{
|
|
98
|
+
entry: {
|
|
99
|
+
content: 'SDK Documentation content 1'
|
|
100
|
+
},
|
|
101
|
+
scoresInfo: {
|
|
102
|
+
overallMatchScore: 0.95
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
entry: {
|
|
107
|
+
content: 'SDK Documentation content 2'
|
|
108
|
+
},
|
|
109
|
+
scoresInfo: {
|
|
110
|
+
overallMatchScore: 0.85
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
]
|
|
114
|
+
},
|
|
115
|
+
SDK_SCHEMAS_KB_ID: {
|
|
116
|
+
results: [
|
|
117
|
+
{
|
|
118
|
+
entry: {
|
|
119
|
+
content: 'SDK Schema content 1'
|
|
120
|
+
},
|
|
121
|
+
scoresInfo: {
|
|
122
|
+
overallMatchScore: 0.9
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
]
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
fetchMock.mockResolvedValueOnce({
|
|
130
|
+
ok: true,
|
|
131
|
+
status: 200,
|
|
132
|
+
json: async () => sdkResponse
|
|
133
|
+
});
|
|
134
|
+
const result = await runSemanticSearchAndFormat({
|
|
135
|
+
toolName: 'SDK',
|
|
136
|
+
toolParams: {
|
|
137
|
+
searchTerm: 'wix-data query'
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
141
|
+
const [url] = fetchMock.mock.calls[0];
|
|
142
|
+
expect(url).toContain('mcp-docs-search/v1/search');
|
|
143
|
+
expect(url).toContain(`maxResults=${DEFAULT_MAX_RESULTS}`);
|
|
144
|
+
expect(url).toContain('rerank=false');
|
|
145
|
+
expect(url).toContain('kbName=SDK_SCHEMAS_KB_ID');
|
|
146
|
+
expect(url).toContain('kbName=SDK_DOCS_KB_ID');
|
|
147
|
+
expect(url).toContain('searchTerm=wix-data+query');
|
|
148
|
+
// Results should be sorted by score and limited to 10
|
|
149
|
+
expect(result).toBe('SDK Documentation content 1\n\n---\n\nSDK Schema content 1\n\n---\n\nSDK Documentation content 2');
|
|
150
|
+
});
|
|
151
|
+
test('performs REST semantic search successfully', async () => {
|
|
152
|
+
const restResponse = {
|
|
153
|
+
results: {
|
|
154
|
+
REST_METHODS_KB_ID: {
|
|
155
|
+
results: [
|
|
156
|
+
{
|
|
157
|
+
entry: {
|
|
158
|
+
content: 'REST Methods content'
|
|
159
|
+
},
|
|
160
|
+
scoresInfo: {
|
|
161
|
+
overallMatchScore: 0.98
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
]
|
|
165
|
+
},
|
|
166
|
+
REST_DOCS_KB_ID: {
|
|
167
|
+
results: [
|
|
168
|
+
{
|
|
169
|
+
entry: {
|
|
170
|
+
content: 'REST Documentation content'
|
|
171
|
+
},
|
|
172
|
+
scoresInfo: {
|
|
173
|
+
overallMatchScore: 0.95
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
]
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
fetchMock.mockResolvedValueOnce({
|
|
181
|
+
ok: true,
|
|
182
|
+
status: 200,
|
|
183
|
+
json: async () => restResponse
|
|
184
|
+
});
|
|
185
|
+
const result = await runSemanticSearchAndFormat({
|
|
186
|
+
toolName: 'REST',
|
|
187
|
+
toolParams: {
|
|
188
|
+
searchTerm: 'create collection'
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
192
|
+
const [url] = fetchMock.mock.calls[0];
|
|
193
|
+
expect(url).toContain('kbName=REST_METHODS_KB_ID');
|
|
194
|
+
expect(url).toContain('kbName=REST_DOCS_KB_ID');
|
|
195
|
+
expect(url).toContain('kbName=MCP_REST_RECIPES_KB_ID');
|
|
196
|
+
expect(result).toBe('REST Methods content\n\n---\n\nREST Documentation content');
|
|
197
|
+
});
|
|
198
|
+
test('performs BUSINESS_SOLUTIONS semantic search successfully', async () => {
|
|
199
|
+
const restResponse = {
|
|
200
|
+
results: {
|
|
201
|
+
REST_DOCS_KB_ID: {
|
|
202
|
+
results: [
|
|
203
|
+
{
|
|
204
|
+
entry: {
|
|
205
|
+
content: 'REST Documentation content'
|
|
206
|
+
},
|
|
207
|
+
scoresInfo: {
|
|
208
|
+
overallMatchScore: 0.95
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
]
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
fetchMock.mockResolvedValueOnce({
|
|
216
|
+
ok: true,
|
|
217
|
+
status: 200,
|
|
218
|
+
json: async () => restResponse
|
|
219
|
+
});
|
|
220
|
+
const result = await runSemanticSearchAndFormat({
|
|
221
|
+
toolName: 'BUSINESS_SOLUTIONS',
|
|
222
|
+
toolParams: {
|
|
223
|
+
searchTerm: 'create collection'
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
227
|
+
const [url] = fetchMock.mock.calls[0];
|
|
228
|
+
expect(url).not.toContain('kbName=REST_METHODS_KB_ID');
|
|
229
|
+
expect(url).toContain('kbName=REST_DOCS_KB_ID');
|
|
230
|
+
expect(url).toContain('kbName=MCP_REST_RECIPES_KB_ID');
|
|
231
|
+
expect(result).toBe('REST Documentation content');
|
|
232
|
+
});
|
|
233
|
+
test('performs WDS semantic search successfully', async () => {
|
|
234
|
+
const wdsResponse = {
|
|
235
|
+
results: {
|
|
236
|
+
WDS_DOCS_KB_ID: {
|
|
237
|
+
results: [
|
|
238
|
+
{
|
|
239
|
+
entry: {
|
|
240
|
+
content: 'WDS Documentation content'
|
|
241
|
+
},
|
|
242
|
+
scoresInfo: {
|
|
243
|
+
overallMatchScore: 0.95
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
]
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
fetchMock.mockResolvedValueOnce({
|
|
251
|
+
ok: true,
|
|
252
|
+
status: 200,
|
|
253
|
+
json: async () => wdsResponse
|
|
254
|
+
});
|
|
255
|
+
const result = await runSemanticSearchAndFormat({
|
|
256
|
+
toolName: 'WDS',
|
|
257
|
+
toolParams: {
|
|
258
|
+
searchTerm: 'Button component'
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
262
|
+
const [url] = fetchMock.mock.calls[0];
|
|
263
|
+
expect(url).toContain('kbName=WDS_DOCS_KB_ID');
|
|
264
|
+
expect(result).toBe('WDS Documentation content');
|
|
265
|
+
});
|
|
266
|
+
test('performs BUILD_APPS semantic search successfully', async () => {
|
|
267
|
+
const buildAppsResponse = {
|
|
268
|
+
results: {
|
|
269
|
+
BUILD_APPS_KB_ID: {
|
|
270
|
+
results: [
|
|
271
|
+
{
|
|
272
|
+
entry: {
|
|
273
|
+
content: 'Build Apps content 1'
|
|
274
|
+
},
|
|
275
|
+
scoresInfo: {
|
|
276
|
+
overallMatchScore: 0.88
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
]
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
fetchMock.mockResolvedValueOnce({
|
|
284
|
+
ok: true,
|
|
285
|
+
status: 200,
|
|
286
|
+
json: async () => buildAppsResponse
|
|
287
|
+
});
|
|
288
|
+
const result = await runSemanticSearchAndFormat({
|
|
289
|
+
toolName: 'BUILD_APPS',
|
|
290
|
+
toolParams: {
|
|
291
|
+
searchTerm: 'deploy app'
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
295
|
+
const [url] = fetchMock.mock.calls[0];
|
|
296
|
+
expect(url).toContain('kbName=BUILD_APPS_KB_ID');
|
|
297
|
+
expect(result).toBe('Build Apps content 1');
|
|
298
|
+
});
|
|
299
|
+
test('performs WIX_HEADLESS semantic search successfully', async () => {
|
|
300
|
+
const wixHeadlessResponse = {
|
|
301
|
+
results: {
|
|
302
|
+
WIX_HEADLESS_KB_ID: {
|
|
303
|
+
results: [
|
|
304
|
+
{
|
|
305
|
+
entry: {
|
|
306
|
+
content: 'Wix Headless content 1'
|
|
307
|
+
},
|
|
308
|
+
scoresInfo: {
|
|
309
|
+
overallMatchScore: 0.92
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
]
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
fetchMock.mockResolvedValueOnce({
|
|
317
|
+
ok: true,
|
|
318
|
+
status: 200,
|
|
319
|
+
json: async () => wixHeadlessResponse
|
|
320
|
+
});
|
|
321
|
+
const result = await runSemanticSearchAndFormat({
|
|
322
|
+
toolName: 'WIX_HEADLESS',
|
|
323
|
+
toolParams: {
|
|
324
|
+
searchTerm: 'query'
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
328
|
+
const [url] = fetchMock.mock.calls[0];
|
|
329
|
+
expect(url).toContain('kbName=HEADLESS_KB_ID');
|
|
330
|
+
expect(result).toBe('Wix Headless content 1');
|
|
331
|
+
});
|
|
332
|
+
test('handles API error response', async () => {
|
|
333
|
+
fetchMock.mockResolvedValueOnce({
|
|
334
|
+
ok: false,
|
|
335
|
+
status: 500,
|
|
336
|
+
statusText: 'Internal Server Error'
|
|
337
|
+
});
|
|
338
|
+
await expect(runSemanticSearchAndFormat({
|
|
339
|
+
toolName: 'SDK',
|
|
340
|
+
toolParams: {
|
|
341
|
+
searchTerm: 'query'
|
|
342
|
+
}
|
|
343
|
+
})).rejects.toThrow('Failed to run rag search: Internal Server Error');
|
|
344
|
+
});
|
|
345
|
+
test('handles empty results', async () => {
|
|
346
|
+
fetchMock.mockResolvedValueOnce({
|
|
347
|
+
ok: true,
|
|
348
|
+
status: 200,
|
|
349
|
+
json: async () => ({ results: {} })
|
|
350
|
+
});
|
|
351
|
+
await expect(runSemanticSearchAndFormat({
|
|
352
|
+
toolName: 'SDK',
|
|
353
|
+
toolParams: {
|
|
354
|
+
searchTerm: 'query'
|
|
355
|
+
}
|
|
356
|
+
})).rejects.toThrow('No result from search');
|
|
357
|
+
});
|
|
358
|
+
test('respects maxResults parameter', async () => {
|
|
359
|
+
const maxResults = 5;
|
|
360
|
+
await runSemanticSearchAndFormat({
|
|
361
|
+
toolName: 'SDK',
|
|
362
|
+
toolParams: {
|
|
363
|
+
searchTerm: 'query'
|
|
364
|
+
},
|
|
365
|
+
maxResults
|
|
366
|
+
});
|
|
367
|
+
const [url] = fetchMock.mock.calls[0];
|
|
368
|
+
expect(url).toContain('maxResults=5');
|
|
369
|
+
});
|
|
370
|
+
test('respects rerank parameter', async () => {
|
|
371
|
+
await runSemanticSearchAndFormat({
|
|
372
|
+
toolName: 'SDK',
|
|
373
|
+
toolParams: {
|
|
374
|
+
searchTerm: 'query'
|
|
375
|
+
},
|
|
376
|
+
maxResults: 5,
|
|
377
|
+
rerank: true
|
|
378
|
+
});
|
|
379
|
+
const [url] = fetchMock.mock.calls[0];
|
|
380
|
+
expect(url).toContain('rerank=true');
|
|
381
|
+
});
|
|
382
|
+
describe('light mode and long content', () => {
|
|
383
|
+
test('respects no linesInEachResult parameter - default behavior', async () => {
|
|
384
|
+
const result = await runSemanticSearchAndFormat({
|
|
385
|
+
toolName: 'SDK',
|
|
386
|
+
toolParams: {
|
|
387
|
+
searchTerm: 'query'
|
|
388
|
+
},
|
|
389
|
+
maxResults: 5,
|
|
390
|
+
rerank: false
|
|
391
|
+
});
|
|
392
|
+
expect(result).toContain('line 3');
|
|
393
|
+
});
|
|
394
|
+
test('respects linesInEachResult parameter', async () => {
|
|
395
|
+
const result = await runSemanticSearchAndFormat({
|
|
396
|
+
toolName: 'SDK',
|
|
397
|
+
toolParams: {
|
|
398
|
+
searchTerm: 'query'
|
|
399
|
+
},
|
|
400
|
+
maxResults: 5,
|
|
401
|
+
rerank: false,
|
|
402
|
+
linesInEachResult: 2
|
|
403
|
+
});
|
|
404
|
+
expect(result).toContain('line 2');
|
|
405
|
+
});
|
|
406
|
+
test('respects linesInEachResult parameter', async () => {
|
|
407
|
+
const result = await runSemanticSearchAndFormat({
|
|
408
|
+
toolName: 'SDK',
|
|
409
|
+
toolParams: {
|
|
410
|
+
searchTerm: 'query'
|
|
411
|
+
},
|
|
412
|
+
maxResults: 5,
|
|
413
|
+
rerank: false,
|
|
414
|
+
linesInEachResult: 1
|
|
415
|
+
});
|
|
416
|
+
expect(result).not.toContain('line 2');
|
|
417
|
+
});
|
|
418
|
+
test('respects linesInEachResult even if content is too long', async () => {
|
|
419
|
+
const longContentLines = LONG_KB_CONTENT.split('\n');
|
|
420
|
+
const longContentLine1 = longContentLines[0];
|
|
421
|
+
const longContentLine16 = longContentLines[16];
|
|
422
|
+
const result = await runSemanticSearchAndFormat({
|
|
423
|
+
toolName: 'SDK',
|
|
424
|
+
toolParams: {
|
|
425
|
+
searchTerm: 'query'
|
|
426
|
+
},
|
|
427
|
+
maxResults: 10,
|
|
428
|
+
rerank: false,
|
|
429
|
+
linesInEachResult: 15
|
|
430
|
+
});
|
|
431
|
+
expect(result).toContain(longContentLine1);
|
|
432
|
+
expect(result).not.toContain('some-chunked-content');
|
|
433
|
+
expect(result).not.toContain(longContentLine16);
|
|
434
|
+
});
|
|
435
|
+
test('uses chunked content if content is too long and linesInEachResult is not set', async () => {
|
|
436
|
+
const result = await runSemanticSearchAndFormat({
|
|
437
|
+
toolName: 'SDK',
|
|
438
|
+
toolParams: {
|
|
439
|
+
searchTerm: 'query'
|
|
440
|
+
},
|
|
441
|
+
maxResults: 10,
|
|
442
|
+
rerank: false
|
|
443
|
+
});
|
|
444
|
+
expect(result).toContain('some-chunked-content');
|
|
445
|
+
});
|
|
446
|
+
test('uses chunked content if content is too long and linesInEachResult is set', async () => {
|
|
447
|
+
const result = await runSemanticSearchAndFormat({
|
|
448
|
+
toolName: 'SDK',
|
|
449
|
+
toolParams: {
|
|
450
|
+
searchTerm: 'query'
|
|
451
|
+
},
|
|
452
|
+
maxResults: 10,
|
|
453
|
+
rerank: false,
|
|
454
|
+
linesInEachResult: 1500
|
|
455
|
+
});
|
|
456
|
+
expect(result).toContain('some-chunked-content');
|
|
457
|
+
});
|
|
458
|
+
});
|
|
459
|
+
});
|