@wix/mcp 1.0.89 → 1.0.90
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/bin-standalone.js +175 -19
- package/build/cjs/index.cjs +177 -21
- package/build/cjs/toolkit.cjs +175 -19
- package/build/dts/config/default-config.js +81 -15
- package/build/dts/config/param-descriptions.js +2 -1
- package/build/dts/docs/deploy-website.d.ts +13 -0
- package/build/dts/docs/deploy-website.js +45 -0
- package/build/dts/docs/docs.d.ts +2 -0
- package/build/dts/docs/docs.js +21 -7
- package/build/dts/docs/fetch-article.d.ts +1 -0
- package/build/dts/docs/fetch-article.js +40 -2
- package/build/dts/import-claude-design-tool/index.js +2 -2
- package/build/dts/toolkit-entry.d.cts +2 -0
- package/build/dts/toolkit-entry.d.ts +2 -0
- package/build/esm/index.js +177 -21
- package/build/esm/toolkit.js +175 -19
- package/package.json +2 -2
|
@@ -107,7 +107,8 @@ export const paramDescriptions = {
|
|
|
107
107
|
},
|
|
108
108
|
ReadFullDocsArticle: {
|
|
109
109
|
articleUrl: 'The URL of the docs article or method article to fetch. Should be something like https://dev.wix.com/docs/.../...' +
|
|
110
|
-
' For REST docs, use the URL as-is. For SDK docs, the URL SHOULD include the query param ?apiView=SDK (e.g. https://dev.wix.com/docs/...?apiView=SDK).'
|
|
110
|
+
' For REST docs, use the URL as-is. For SDK docs, the URL SHOULD include the query param ?apiView=SDK (e.g. https://dev.wix.com/docs/...?apiView=SDK).' +
|
|
111
|
+
' Wix skills pages (https://www.wix.com/skills/..., https://dev.wix.com/docs/skills/...) are read as-is, including their referenced files.'
|
|
111
112
|
},
|
|
112
113
|
ReadFullDocsMethodSchema: {
|
|
113
114
|
articleUrl: 'The URL of the documentation to fetch. Should be something like https://dev.wix.com/docs/.../...' +
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { WixMcpServer } from '../wix-mcp-server.js';
|
|
2
|
+
export declare const DEPLOY_WEBSITE_TOOL_NAME = "DeployWebsite";
|
|
3
|
+
export declare const DEPLOY_WEBSITE_RECIPE_URL = "https://dev.wix.com/docs/api-reference/account-level/sites/skills/upload-a-website-or-html-files.md";
|
|
4
|
+
export declare const DROP_PAGE_URL = "https://www.wix.com/headless/drop?utm_campaign=mcp";
|
|
5
|
+
export declare function deployWebsiteResponse(recipe: string): string;
|
|
6
|
+
export declare const DEPLOY_WEBSITE_POINTER_RESPONSE: string;
|
|
7
|
+
export interface DeployWebsiteFetchOptions {
|
|
8
|
+
skillsPortalUrl?: string;
|
|
9
|
+
repo?: string;
|
|
10
|
+
commitHash?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function addDeployWebsiteTool(server: WixMcpServer, disableTools?: string[], toolDescriptions?: Record<string, string>, fetchOptions?: DeployWebsiteFetchOptions): void;
|
|
13
|
+
//# sourceMappingURL=deploy-website.d.ts.map
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { defaultToolDescriptions } from '../config/default-config.js';
|
|
2
|
+
import { fetchArticleContent } from './fetch-article.js';
|
|
3
|
+
export const DEPLOY_WEBSITE_TOOL_NAME = 'DeployWebsite';
|
|
4
|
+
export const DEPLOY_WEBSITE_RECIPE_URL = 'https://dev.wix.com/docs/api-reference/account-level/sites/skills/upload-a-website-or-html-files.md';
|
|
5
|
+
export const DROP_PAGE_URL = 'https://www.wix.com/headless/drop?utm_campaign=mcp';
|
|
6
|
+
const FALLBACK_LINE = `Only if you cannot run it (you can't reach the file bytes, or a step fails and you can't fix it): send the user to ${DROP_PAGE_URL} — give that URL exactly as written, keeping the utm_campaign=mcp parameter.`;
|
|
7
|
+
// The tool exists to take the agent's attention at routing time; the work itself
|
|
8
|
+
// is the recipe, so the response IS the recipe — fetched live and returned whole,
|
|
9
|
+
// so the agent never has to decide whether to go read it.
|
|
10
|
+
export function deployWebsiteResponse(recipe) {
|
|
11
|
+
return [
|
|
12
|
+
`The following is the content of ${DEPLOY_WEBSITE_RECIPE_URL}. Follow it end to end and do the publishing yourself — do not hand the user instructions.`,
|
|
13
|
+
FALLBACK_LINE,
|
|
14
|
+
'---',
|
|
15
|
+
recipe.trim()
|
|
16
|
+
].join('\n\n');
|
|
17
|
+
}
|
|
18
|
+
// When the recipe can't be fetched, the pointer still routes correctly.
|
|
19
|
+
export const DEPLOY_WEBSITE_POINTER_RESPONSE = [
|
|
20
|
+
`Read and follow this recipe end to end: ${DEPLOY_WEBSITE_RECIPE_URL}`,
|
|
21
|
+
'It covers creating the site and uploading the files (with or without a Wix login), updating a site deployed this way, and implementing a backend on it (stores, bookings, CMS, members) as a Wix Headless project. Do the publishing yourself — do not hand the user instructions.',
|
|
22
|
+
FALLBACK_LINE
|
|
23
|
+
].join('\n\n');
|
|
24
|
+
export function addDeployWebsiteTool(server, disableTools = [], toolDescriptions, fetchOptions = {}) {
|
|
25
|
+
if (disableTools.includes(DEPLOY_WEBSITE_TOOL_NAME)) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
server.tool(DEPLOY_WEBSITE_TOOL_NAME, toolDescriptions?.[DEPLOY_WEBSITE_TOOL_NAME] ??
|
|
29
|
+
defaultToolDescriptions[DEPLOY_WEBSITE_TOOL_NAME], {}, { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async (_args, { httpClient }) => {
|
|
30
|
+
let text = DEPLOY_WEBSITE_POINTER_RESPONSE;
|
|
31
|
+
try {
|
|
32
|
+
// Same path ReadFullDocsArticle takes for this page: the rawdocs article
|
|
33
|
+
// API, addressed without the .md suffix, header scaffolding stripped.
|
|
34
|
+
const recipe = await fetchArticleContent(httpClient, DEPLOY_WEBSITE_RECIPE_URL.replace(/\.md$/, ''), 'article', true, fetchOptions.skillsPortalUrl, fetchOptions.repo, fetchOptions.commitHash);
|
|
35
|
+
if (recipe && recipe.trim()) {
|
|
36
|
+
text = deployWebsiteResponse(recipe);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
console.warn(`[DeployWebsite] recipe fetch failed, returning the pointer:`, error instanceof Error ? error.message : error);
|
|
41
|
+
}
|
|
42
|
+
return { content: [{ type: 'text', text }] };
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=deploy-website.js.map
|
package/build/dts/docs/docs.d.ts
CHANGED
|
@@ -19,6 +19,8 @@ export interface ReadmeDocConfig {
|
|
|
19
19
|
export interface DocsToolsOptions {
|
|
20
20
|
getToKnowWixEnabled?: boolean;
|
|
21
21
|
createWixBusinessGuideEnabled?: boolean;
|
|
22
|
+
/** DeployWebsite (publish ready-made site files) — an account-owner flow; off for visitor servers. */
|
|
23
|
+
deployWebsiteEnabled?: boolean;
|
|
22
24
|
disableTools?: string[];
|
|
23
25
|
/** Custom descriptions for tools, keyed by tool name */
|
|
24
26
|
toolDescriptions?: Record<string, string>;
|
package/build/dts/docs/docs.js
CHANGED
|
@@ -2,12 +2,13 @@ import { z } from 'zod';
|
|
|
2
2
|
import { runSemanticSearchAndFormat } from './semanticSearch.js';
|
|
3
3
|
import { logger } from '../infra/logger.js';
|
|
4
4
|
import { captureException } from '@sentry/node';
|
|
5
|
-
import { fetchArticleContent } from './fetch-article.js';
|
|
5
|
+
import { fetchArticleContent, isSkillsRegistryUrl } from './fetch-article.js';
|
|
6
6
|
import { normalizeMenuContent, summarizeLargeMenu, fetchMenuContent, MENU_CONTENT_THRESHOLD } from './normalize-menu-content.js';
|
|
7
7
|
import { fetchPlatformizedMenu, MenuNotFoundError } from './browse-menu.js';
|
|
8
8
|
import { isQueryOrSearchEndpoint, QUERY_CAPABILITY_MARKER } from './searchFormatting.js';
|
|
9
9
|
import { addGetToKnowTools, addGetSiteContextTool } from './get-to-know.js';
|
|
10
10
|
import { addCreateWixBusinessGuideTools } from './create-site-guide.js';
|
|
11
|
+
import { addDeployWebsiteTool } from './deploy-website.js';
|
|
11
12
|
import { defaultToolDescriptions } from '../config/default-config.js';
|
|
12
13
|
import { desc } from '../config/param-descriptions.js';
|
|
13
14
|
import dedent from 'dedent';
|
|
@@ -67,7 +68,7 @@ export const addDocsTools = (server, allowedTools = [
|
|
|
67
68
|
'CLI',
|
|
68
69
|
'OVERVIEW'
|
|
69
70
|
], options = {}) => {
|
|
70
|
-
const { getToKnowWixEnabled = false, createWixBusinessGuideEnabled = true, disableTools, toolDescriptions, readmeDocs, authStrategy, skillsPortalUrl, skillsRepo, repo, skillsPr, commitHash, skillsTags, dynamicContextEnabled, cliEnabled = false, usePlatformizedSearch = true, usePlatformizedBrowse = true } = options;
|
|
71
|
+
const { getToKnowWixEnabled = false, createWixBusinessGuideEnabled = true, deployWebsiteEnabled = true, disableTools, toolDescriptions, readmeDocs, authStrategy, skillsPortalUrl, skillsRepo, repo, skillsPr, commitHash, skillsTags, dynamicContextEnabled, cliEnabled = false, usePlatformizedSearch = true, usePlatformizedBrowse = true } = options;
|
|
71
72
|
const effectiveRepo = repo ?? skillsRepo;
|
|
72
73
|
const effectiveCommitHash = commitHash ?? skillsPr;
|
|
73
74
|
// Helper to get description (custom or default)
|
|
@@ -123,6 +124,15 @@ export const addDocsTools = (server, allowedTools = [
|
|
|
123
124
|
!disableTools?.includes('CreateWixBusinessGuide')) {
|
|
124
125
|
addCreateWixBusinessGuideTools(server, disableTools || [], toolDescriptions, cliEnabled);
|
|
125
126
|
}
|
|
127
|
+
// On by default: it is a routing slot, not a docs source — the agent with
|
|
128
|
+
// ready-made site files must find it next to the site-creation tools.
|
|
129
|
+
if (deployWebsiteEnabled) {
|
|
130
|
+
addDeployWebsiteTool(server, disableTools || [], toolDescriptions, {
|
|
131
|
+
skillsPortalUrl,
|
|
132
|
+
repo: effectiveRepo,
|
|
133
|
+
commitHash: effectiveCommitHash
|
|
134
|
+
});
|
|
135
|
+
}
|
|
126
136
|
// WDS Documentation
|
|
127
137
|
if (allowedTools.includes('WDS') &&
|
|
128
138
|
!disableTools?.includes('SearchWixWDSDocumentation')) {
|
|
@@ -622,17 +632,20 @@ export const addDocsTools = (server, allowedTools = [
|
|
|
622
632
|
articleUrl: z.string().url().describe(d.articleUrl)
|
|
623
633
|
};
|
|
624
634
|
})(), { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async ({ articleUrl }, { httpClient }) => {
|
|
625
|
-
// URL validation:
|
|
635
|
+
// URL validation: known docs prefixes, or a Wix skills registry page
|
|
636
|
+
// (https://www.wix.com/skills/..., https://dev.wix.com/docs/skills/...).
|
|
626
637
|
const validPrefixes = ['https://dev.wix.com/docs/'];
|
|
627
638
|
if (skillsPortalUrl)
|
|
628
639
|
validPrefixes.push(skillsPortalUrl);
|
|
629
|
-
|
|
640
|
+
const isSkillsPage = isSkillsRegistryUrl(articleUrl);
|
|
641
|
+
if (!isSkillsPage &&
|
|
642
|
+
!validPrefixes.some((p) => articleUrl.startsWith(p))) {
|
|
630
643
|
return {
|
|
631
644
|
isError: true,
|
|
632
645
|
content: [
|
|
633
646
|
{
|
|
634
647
|
type: 'text',
|
|
635
|
-
text: `Invalid article URL: must start with https://dev.wix.com/docs
|
|
648
|
+
text: `Invalid article URL: must start with https://dev.wix.com/docs/, or be a Wix skills page (https://www.wix.com/skills/...). Got: "${articleUrl}"`
|
|
636
649
|
}
|
|
637
650
|
]
|
|
638
651
|
};
|
|
@@ -640,8 +653,9 @@ export const addDocsTools = (server, allowedTools = [
|
|
|
640
653
|
// Every docs page has a .md twin whose menu pages link children WITH
|
|
641
654
|
// the .md suffix, so agents that navigated the .md tree pass .md URLs
|
|
642
655
|
// here — which 404 in get-article-content. Read the canonical page.
|
|
643
|
-
// (dev.wix.com only: on the skills
|
|
644
|
-
if (
|
|
656
|
+
// (dev.wix.com docs only: on the skills registry .md is the real path.)
|
|
657
|
+
if (!isSkillsPage &&
|
|
658
|
+
articleUrl.startsWith('https://dev.wix.com/docs/')) {
|
|
645
659
|
articleUrl = articleUrl.replace(/\.md$/, '');
|
|
646
660
|
}
|
|
647
661
|
try {
|
|
@@ -35,5 +35,6 @@ export declare function fetchRecipesIndex(): Promise<string>;
|
|
|
35
35
|
* ```
|
|
36
36
|
*/
|
|
37
37
|
export declare function fetchArticle(articleUrl: string): Promise<string>;
|
|
38
|
+
export declare function isSkillsRegistryUrl(url: string): boolean;
|
|
38
39
|
export declare function fetchArticleContent(httpClient: HttpClient, articleUrl: string, mode: 'article' | 'methodSchema' | 'raw', stripHeader?: boolean, skillsPortalUrl?: string, repo?: string, commitHash?: string, fetchMcpWhiteList?: boolean): Promise<string>;
|
|
39
40
|
//# sourceMappingURL=fetch-article.d.ts.map
|
|
@@ -50,6 +50,38 @@ export async function fetchArticle(articleUrl) {
|
|
|
50
50
|
// Internal implementation
|
|
51
51
|
// ---------------------------------------------------------------------------
|
|
52
52
|
const DOCS_URL_PREFIX = 'https://dev.wix.com/docs/';
|
|
53
|
+
/**
|
|
54
|
+
* The Wix skills registry serves agent skills (SKILL.md and bundled files)
|
|
55
|
+
* as raw markdown straight from the `wix/skills` repo, on every host the
|
|
56
|
+
* gateway maps to it. Pages there are not docs articles: the rawdocs
|
|
57
|
+
* get-article-content API does not know them, and `.md` is a real path, so
|
|
58
|
+
* they are fetched as-is.
|
|
59
|
+
*/
|
|
60
|
+
const SKILLS_REGISTRY_URL = new RegExp('^https://(?:dev\\.wix\\.com(?:/docs)?|www\\.wix\\.com(?:/velo/reference)?)/skills(?:[/.?#]|$)');
|
|
61
|
+
export function isSkillsRegistryUrl(url) {
|
|
62
|
+
return SKILLS_REGISTRY_URL.test(url.trim());
|
|
63
|
+
}
|
|
64
|
+
async function fetchSkillsRegistryPage(httpClient, url) {
|
|
65
|
+
let data;
|
|
66
|
+
try {
|
|
67
|
+
({ data } = await httpClient.get(url, {
|
|
68
|
+
headers: { accept: 'text/markdown, text/plain;q=0.9, */*;q=0.1' }
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
const { message, status } = getHttpErrorDetails(error);
|
|
73
|
+
const statusSuffix = status ? ` (status ${status})` : '';
|
|
74
|
+
throw new Error(`${message}${statusSuffix}`);
|
|
75
|
+
}
|
|
76
|
+
if (typeof data !== 'string') {
|
|
77
|
+
// The manifest endpoint is JSON; anything else is text.
|
|
78
|
+
return JSON.stringify(data, null, 2);
|
|
79
|
+
}
|
|
80
|
+
if (!data.trim()) {
|
|
81
|
+
throw new Error('Article content is empty');
|
|
82
|
+
}
|
|
83
|
+
return data;
|
|
84
|
+
}
|
|
53
85
|
function getResponseErrorMessage(data) {
|
|
54
86
|
if (!data) {
|
|
55
87
|
return undefined;
|
|
@@ -152,10 +184,16 @@ export async function fetchArticleContent(httpClient, articleUrl, mode, stripHea
|
|
|
152
184
|
}
|
|
153
185
|
catch (error) {
|
|
154
186
|
console.warn(`[fetch] Override failed for ${effectiveUrl}, falling back to ${articleUrl}:`, error instanceof Error ? error.message : error);
|
|
155
|
-
// Fall through to normal fetch
|
|
156
|
-
|
|
187
|
+
// Fall through to the normal fetch for this URL: the registry for a
|
|
188
|
+
// skills page (rawdocs cannot serve those), rawdocs otherwise.
|
|
189
|
+
content = isSkillsRegistryUrl(articleUrl)
|
|
190
|
+
? await fetchSkillsRegistryPage(httpClient, articleUrl)
|
|
191
|
+
: await fetchArticleContentFromDigor(httpClient, articleUrl, mode, stripHeader);
|
|
157
192
|
}
|
|
158
193
|
}
|
|
194
|
+
else if (isSkillsRegistryUrl(articleUrl)) {
|
|
195
|
+
content = await fetchSkillsRegistryPage(httpClient, articleUrl);
|
|
196
|
+
}
|
|
159
197
|
else if (mode === 'raw') {
|
|
160
198
|
let parsedUrl;
|
|
161
199
|
try {
|
|
@@ -86,11 +86,11 @@ export function addImportClaudeDesignTool(server, authStrategy, options) {
|
|
|
86
86
|
designUrl = new URL(args.url);
|
|
87
87
|
}
|
|
88
88
|
catch {
|
|
89
|
-
return errorResult("Invalid design URL — this tool only accepts the claudeusercontent.com URL produced by Claude Design. For site
|
|
89
|
+
return errorResult("Invalid design URL — this tool only accepts the claudeusercontent.com URL produced by Claude Design. For a page or site that exists in any other form (the user's files, a build, a zip, another builder's export, a page you made), do not retry this tool — call DeployWebsite, which returns the recipe to publish the files yourself. If that tool isn't available: read https://dev.wix.com/docs/api-reference/account-level/sites/skills/upload-a-website-or-html-files.md and publish them yourself, or send the user to https://www.wix.com/headless/drop?utm_campaign=mcp.");
|
|
90
90
|
}
|
|
91
91
|
if (designUrl.protocol !== 'https:' ||
|
|
92
92
|
!designUrl.hostname.endsWith(CLAUDE_USER_CONTENT_HOST_SUFFIX)) {
|
|
93
|
-
return errorResult("Invalid design URL — this tool only accepts the claudeusercontent.com URL produced by Claude Design. For site
|
|
93
|
+
return errorResult("Invalid design URL — this tool only accepts the claudeusercontent.com URL produced by Claude Design. For a page or site that exists in any other form (the user's files, a build, a zip, another builder's export, a page you made), do not retry this tool — call DeployWebsite, which returns the recipe to publish the files yourself. If that tool isn't available: read https://dev.wix.com/docs/api-reference/account-level/sites/skills/upload-a-website-or-html-files.md and publish them yourself, or send the user to https://www.wix.com/headless/drop?utm_campaign=mcp.");
|
|
94
94
|
}
|
|
95
95
|
// Resolve the caller's account identity BEFORE the design fetch — the
|
|
96
96
|
// design URL is single-use, so an unauthenticated caller must fail
|
|
@@ -127,6 +127,8 @@ export interface ReadmeDocConfig {
|
|
|
127
127
|
export interface DocsToolsOptions {
|
|
128
128
|
getToKnowWixEnabled?: boolean;
|
|
129
129
|
createWixBusinessGuideEnabled?: boolean;
|
|
130
|
+
/** DeployWebsite (publish ready-made site files) — an account-owner flow; off for visitor servers. */
|
|
131
|
+
deployWebsiteEnabled?: boolean;
|
|
130
132
|
disableTools?: string[];
|
|
131
133
|
/** Custom descriptions for tools, keyed by tool name */
|
|
132
134
|
toolDescriptions?: Record<string, string>;
|
|
@@ -127,6 +127,8 @@ export interface ReadmeDocConfig {
|
|
|
127
127
|
export interface DocsToolsOptions {
|
|
128
128
|
getToKnowWixEnabled?: boolean;
|
|
129
129
|
createWixBusinessGuideEnabled?: boolean;
|
|
130
|
+
/** DeployWebsite (publish ready-made site files) — an account-owner flow; off for visitor servers. */
|
|
131
|
+
deployWebsiteEnabled?: boolean;
|
|
130
132
|
disableTools?: string[];
|
|
131
133
|
/** Custom descriptions for tools, keyed by tool name */
|
|
132
134
|
toolDescriptions?: Record<string, string>;
|