@wix/mcp 1.0.94 → 1.0.96
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 +2 -2
- package/build/bin-standalone.js +1457 -332
- package/build/cjs/index.cjs +3379 -1333
- package/build/cjs/toolkit.cjs +2158 -373
- package/build/dts/api-call/headless-release.d.ts +56 -0
- package/build/dts/api-call/headless-release.js +135 -0
- package/build/dts/api-call/index.d.ts +9 -1
- package/build/dts/api-call/index.js +36 -8
- package/build/dts/api-call/site-files.d.ts +14 -0
- package/build/dts/api-call/site-files.js +106 -10
- package/build/dts/api-call/upload-headless-website-files.d.ts +117 -5
- package/build/dts/api-call/upload-headless-website-files.js +565 -20
- package/build/dts/api-call/upload-image-tool.d.ts +2 -0
- package/build/dts/api-call/upload-image-tool.js +8 -4
- package/build/dts/bin.d.ts +1 -1
- package/build/dts/bin.js +3 -1
- package/build/dts/code-mode/attachments.d.ts +9 -6
- package/build/dts/code-mode/attachments.js +23 -16
- package/build/dts/code-mode/index.d.ts +6 -1
- package/build/dts/code-mode/index.js +32 -12
- package/build/dts/code-mode/truncate-response.js +5 -1
- package/build/dts/config/default-config.d.ts +35 -5
- package/build/dts/config/default-config.js +339 -182
- package/build/dts/config/file-params.d.ts +22 -0
- package/build/dts/config/file-params.js +24 -0
- package/build/dts/config/param-descriptions.d.ts +14 -2
- package/build/dts/config/param-descriptions.js +33 -14
- package/build/dts/constants.d.ts +1 -0
- package/build/dts/constants.js +1 -0
- package/build/dts/docs/docs.d.ts +12 -1
- package/build/dts/docs/docs.js +274 -43
- package/build/dts/docs/fetch-article.d.ts +21 -0
- package/build/dts/docs/fetch-article.js +66 -4
- package/build/dts/docs/get-to-know.d.ts +7 -2
- package/build/dts/docs/get-to-know.js +36 -14
- package/build/dts/docs/guessed-url.d.ts +41 -0
- package/build/dts/docs/guessed-url.js +185 -0
- package/build/dts/docs/mintlify-docs.d.ts +121 -0
- package/build/dts/docs/mintlify-docs.js +391 -0
- package/build/dts/docs/semanticSearch.d.ts +2 -1
- package/build/dts/docs/semanticSearch.js +14 -7
- package/build/dts/docs/start-deploy-website.d.ts +7 -6
- package/build/dts/docs/start-deploy-website.js +13 -8
- package/build/dts/docs/start-headless-build.d.ts +8 -10
- package/build/dts/docs/start-headless-build.js +14 -28
- package/build/dts/index.d.ts +2 -2
- package/build/dts/index.js +2 -2
- package/build/dts/infra/redact-personal-data.d.ts +4 -0
- package/build/dts/infra/redact-personal-data.js +148 -0
- package/build/dts/site-widget-tools/constants.d.ts +50 -2
- package/build/dts/site-widget-tools/constants.js +65 -8
- package/build/dts/site-widget-tools/index.d.ts +1 -0
- package/build/dts/site-widget-tools/index.js +1 -0
- package/build/dts/site-widget-tools/pick-images-tool/index.d.ts +14 -0
- package/build/dts/site-widget-tools/pick-images-tool/index.js +138 -0
- package/build/dts/site-widget-tools/pull-site-creation-job-tool/index.js +1 -1
- package/build/dts/site-widget-tools/search-site-templates-tool/index.js +25 -2
- package/build/dts/site-widget-tools/site-builder-tool/index.js +35 -3
- package/build/dts/site-widget-tools/site-creation-tool/index.d.ts +7 -1
- package/build/dts/site-widget-tools/site-creation-tool/index.js +22 -51
- package/build/dts/site-widget-tools/suggested-domain-tool/index.js +26 -12
- package/build/dts/support/index.d.ts +4 -0
- package/build/dts/support/index.js +13 -7
- package/build/dts/tool-utils.d.ts +8 -1
- package/build/dts/tool-utils.js +26 -2
- package/build/dts/toolkit-entry.d.cts +15 -10
- package/build/dts/toolkit-entry.d.ts +15 -10
- package/build/dts/toolkit.d.ts +2 -2
- package/build/dts/toolkit.js +21 -8
- package/build/dts/wix-mcp-server.d.ts +10 -1
- package/build/dts/wix-mcp-server.js +25 -7
- package/build/dts/wixel/constants.d.ts +8 -1
- package/build/dts/wixel/constants.js +8 -1
- package/build/dts/wixel/index.d.ts +1 -1
- package/build/dts/wixel/index.js +2 -2
- package/build/dts/wixel/wixel-a2a-client.d.ts +83 -0
- package/build/dts/wixel/wixel-a2a-client.js +166 -0
- package/build/dts/wixel/wixel-bi.d.ts +2 -1
- package/build/dts/wixel/wixel-bi.js +2 -1
- package/build/dts/wixel/{external-agent-api.d.ts → wixel-session-entries.d.ts} +11 -33
- package/build/dts/wixel/{external-agent-api.js → wixel-session-entries.js} +33 -54
- package/build/dts/wixel/wixel-session-tools.d.ts +21 -26
- package/build/dts/wixel/wixel-session-tools.js +494 -599
- package/build/esm/index.js +3422 -1388
- package/build/esm/toolkit.js +2158 -373
- package/package.json +4 -4
package/build/dts/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export { handleWixAPIResponse } from './tool-utils.js';
|
|
|
6
6
|
export { addDocsResources } from './resources/docs.js';
|
|
7
7
|
export { addSupportTool } from './support/index.js';
|
|
8
8
|
export { addGetProfileTool } from './account-tools/get-profile-tool.js';
|
|
9
|
-
export { addCreateSiteWidgetTool, addEditSiteWidgetTool, addPullSiteJobTool, addClaimSiteTool, addSuggestedDomainTool, addSiteCreationWidgetTools, addWixSiteCreationTool, addSearchSiteTemplatesTool, addCreateSiteFromTemplateTool, type SiteWidgetToolOptions } from './site-widget-tools/index.js';
|
|
9
|
+
export { addCreateSiteWidgetTool, addEditSiteWidgetTool, addPullSiteJobTool, addClaimSiteTool, addSuggestedDomainTool, addSiteCreationWidgetTools, addWixSiteCreationTool, addSearchSiteTemplatesTool, addCreateSiteFromTemplateTool, addPickImagesTools, type SiteWidgetToolOptions } from './site-widget-tools/index.js';
|
|
10
10
|
export * from './wixel/index.js';
|
|
11
11
|
export { addImportClaudeDesignTool, type ImportClaudeDesignToolOptions } from './import-claude-design-tool/index.js';
|
|
12
12
|
export { IMPORT_CLAUDE_DESIGN_TOOL_NAME } from './import-claude-design-tool/constants.js';
|
|
@@ -25,6 +25,6 @@ export { addCodeModeTools, addExecuteCodeModeTool, addSearchCodeModeTool, type C
|
|
|
25
25
|
export { addUploadHeadlessWebsiteFilesTool, UPLOAD_HEADLESS_WEBSITE_FILES_TOOL_NAME } from './api-call/upload-headless-website-files.js';
|
|
26
26
|
export { validateExecuteCode, EXECUTE_FUNCTION_EXPRESSION_HINT, type CodeValidationResult } from './code-mode/validation.js';
|
|
27
27
|
export { addGraphqlTools, resetGraphqlSchemaCache, GRAPHQL_TOOL_NAMES, SEARCH_GRAPHQL_TOOL_NAME, INSPECT_GRAPHQL_TOOL_NAME, EXECUTE_GRAPHQL_TOOL_NAME, WIX_GRAPHQL_ENDPOINT, type GraphqlToolsOptions, type GraphqlToolName } from './graphql/index.js';
|
|
28
|
-
export { defaultConfig, defaultToolDescriptions, defaultReadmeDocs, widgetSiteCreationConfig, SITE_CREATION_COPY, toWidget, executeCodeModeToolDescriptions, SYSTEM_REMINDER_GUIDELINES, SYSTEM_REMINDER, mergeConfig, type ModeDefaultConfig } from './config/default-config.js';
|
|
28
|
+
export { defaultConfig, defaultToolDescriptions, defaultReadmeDocs, widgetSiteCreationConfig, SITE_CREATION_COPY, toWidget, withUsageGuideOnEveryTool, buildReadmeDocs, executeCodeModeToolDescriptions, SYSTEM_REMINDER_GUIDELINES, SYSTEM_REMINDER, SERVER_INSTRUCTIONS, SERVER_INSTRUCTIONS_TOOLS, mergeConfig, type ModeDefaultConfig } from './config/default-config.js';
|
|
29
29
|
export * from './site-widget-tools/constants.js';
|
|
30
30
|
//# sourceMappingURL=index.d.ts.map
|
package/build/dts/index.js
CHANGED
|
@@ -6,7 +6,7 @@ export { handleWixAPIResponse } from './tool-utils.js';
|
|
|
6
6
|
export { addDocsResources } from './resources/docs.js';
|
|
7
7
|
export { addSupportTool } from './support/index.js';
|
|
8
8
|
export { addGetProfileTool } from './account-tools/get-profile-tool.js';
|
|
9
|
-
export { addCreateSiteWidgetTool, addEditSiteWidgetTool, addPullSiteJobTool, addClaimSiteTool, addSuggestedDomainTool, addSiteCreationWidgetTools, addWixSiteCreationTool, addSearchSiteTemplatesTool, addCreateSiteFromTemplateTool } from './site-widget-tools/index.js';
|
|
9
|
+
export { addCreateSiteWidgetTool, addEditSiteWidgetTool, addPullSiteJobTool, addClaimSiteTool, addSuggestedDomainTool, addSiteCreationWidgetTools, addWixSiteCreationTool, addSearchSiteTemplatesTool, addCreateSiteFromTemplateTool, addPickImagesTools } from './site-widget-tools/index.js';
|
|
10
10
|
export * from './wixel/index.js';
|
|
11
11
|
export { addImportClaudeDesignTool } from './import-claude-design-tool/index.js';
|
|
12
12
|
export { IMPORT_CLAUDE_DESIGN_TOOL_NAME } from './import-claude-design-tool/constants.js';
|
|
@@ -31,6 +31,6 @@ export { validateExecuteCode, EXECUTE_FUNCTION_EXPRESSION_HINT } from './code-mo
|
|
|
31
31
|
// GraphQL tools (search operations + inspect schema + execute)
|
|
32
32
|
export { addGraphqlTools, resetGraphqlSchemaCache, GRAPHQL_TOOL_NAMES, SEARCH_GRAPHQL_TOOL_NAME, INSPECT_GRAPHQL_TOOL_NAME, EXECUTE_GRAPHQL_TOOL_NAME, WIX_GRAPHQL_ENDPOINT } from './graphql/index.js';
|
|
33
33
|
// Config exports
|
|
34
|
-
export { defaultConfig, defaultToolDescriptions, defaultReadmeDocs, widgetSiteCreationConfig, SITE_CREATION_COPY, toWidget, executeCodeModeToolDescriptions, SYSTEM_REMINDER_GUIDELINES, SYSTEM_REMINDER, mergeConfig } from './config/default-config.js';
|
|
34
|
+
export { defaultConfig, defaultToolDescriptions, defaultReadmeDocs, widgetSiteCreationConfig, SITE_CREATION_COPY, toWidget, withUsageGuideOnEveryTool, buildReadmeDocs, executeCodeModeToolDescriptions, SYSTEM_REMINDER_GUIDELINES, SYSTEM_REMINDER, SERVER_INSTRUCTIONS, SERVER_INSTRUCTIONS_TOOLS, mergeConfig } from './config/default-config.js';
|
|
35
35
|
export * from './site-widget-tools/constants.js';
|
|
36
36
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const FREE_TEXT_INFO_PARAMS: readonly ["userRequest", "siteDescription", "siteForm", "siteFunctionality", "agentIdentity", "wixAccess", "reason", "whyNotExecuteWixAPI", "editorRequest", "templateRequest"];
|
|
2
|
+
export declare function redactPersonalData(text: string): string;
|
|
3
|
+
export declare function serializeToolParamsForBi(args: unknown): string;
|
|
4
|
+
//# sourceMappingURL=redact-personal-data.d.ts.map
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { parseFileBundle } from '../api-call/site-files.js';
|
|
2
|
+
// Free-text arguments that agents fill in for BI. Their descriptions ask for no
|
|
3
|
+
// personal data; this is the backstop for what comes through anyway, applied to
|
|
4
|
+
// these fields only before tool arguments are recorded. Other arguments (API
|
|
5
|
+
// bodies, code) carry the data the call needs and are recorded as sent.
|
|
6
|
+
export const FREE_TEXT_INFO_PARAMS = [
|
|
7
|
+
'userRequest',
|
|
8
|
+
'siteDescription',
|
|
9
|
+
'siteForm',
|
|
10
|
+
'siteFunctionality',
|
|
11
|
+
'agentIdentity',
|
|
12
|
+
'wixAccess',
|
|
13
|
+
'reason',
|
|
14
|
+
'whyNotExecuteWixAPI',
|
|
15
|
+
'editorRequest',
|
|
16
|
+
'templateRequest'
|
|
17
|
+
];
|
|
18
|
+
const EMAIL = /[A-Z0-9._%+-]+@[A-Z0-9-]+(?:\.[A-Z0-9-]+)*\.[A-Z]{2,}/gi;
|
|
19
|
+
// A secret's value after its name: "password: x", "token=x", "the password is x",
|
|
20
|
+
// "set the password to x". "password-protected" has no value and is kept. An
|
|
21
|
+
// unquoted value runs to the end of its clause, since it may contain spaces.
|
|
22
|
+
const NAMED_SECRET = /\b(passwords?|passwd|pwd|passcodes?|secrets?|tokens?|api[ _-]?keys?|access[ _-]?keys?|credentials?)(\s*[:=]\s*|\s+(?:is|was|to)\s+)(?:"[^"]*"|'[^']*'|`[^`]*`|[^\s"'`,;][^,;\n]*?(?=[.!?]\s|[,;\n]|$))/gi;
|
|
23
|
+
const BEARER = /\bBearer\s+[A-Za-z0-9._~+/=-]+/gi;
|
|
24
|
+
const JWT = /\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g;
|
|
25
|
+
const KEY_PREFIXES = /\b(?:sk-[A-Za-z0-9_-]{16,}|gh[pousr]_[A-Za-z0-9]{20,}|github_pat_\w{20,}|xox[abprs]-[A-Za-z0-9-]{10,}|AKIA[0-9A-Z]{16}|AIza[0-9A-Za-z_-]{35})\b/g;
|
|
26
|
+
// Local paths, not inside a URL ("https://example.com/work/" is kept). A
|
|
27
|
+
// folder name may contain spaces ("/Users/Jane Doe/site"); the last segment
|
|
28
|
+
// ends at the first space unless the path is quoted.
|
|
29
|
+
const BACKTICK = '`';
|
|
30
|
+
const UNIX_ROOT = String.raw `(?<![\w.:/~-])(?:~|/(?:Users|home|root|mnt|tmp|private|var|Volumes|workspace|work))`;
|
|
31
|
+
const WINDOWS_ROOT = String.raw `(?<!\w)[A-Za-z]:(?=\\\w)`;
|
|
32
|
+
const PATH_ROOT = `(?:${UNIX_ROOT}|${WINDOWS_ROOT})`;
|
|
33
|
+
const QUOTED_PATH = new RegExp(String.raw `(?<![\w])(["'${BACKTICK}])${PATH_ROOT}[^"'${BACKTICK}\n]*\1`, 'g');
|
|
34
|
+
const FOLDER = String.raw `[^\s/\\"'${BACKTICK},;()<>]+(?: [^\s/\\"'${BACKTICK},;()<>]+)*`;
|
|
35
|
+
const LOCAL_PATH = new RegExp(String.raw `${PATH_ROOT}(?:[/\\]${FOLDER}(?=[/\\]))*[/\\][^\s"'${BACKTICK},;()<>]*`, 'g');
|
|
36
|
+
// 9 to 15 digits with phone separators, standing alone. Dates, times, UUIDs
|
|
37
|
+
// and shorter counts stay; a bare 9-15 digit number reads as a phone and is
|
|
38
|
+
// redacted, since free text can't tell the two apart.
|
|
39
|
+
const PHONE_CANDIDATE = /(?<![\w-])\+?\(?\d[\d\s().-]{7,}\d(?![\w-])/g;
|
|
40
|
+
const DATE_START = /^\d{4}-\d{2}-\d{2}/;
|
|
41
|
+
function redactPhone(match, offset, text) {
|
|
42
|
+
if (DATE_START.test(match) ||
|
|
43
|
+
/^:\d{2}\b/.test(text.slice(offset + match.length))) {
|
|
44
|
+
return match;
|
|
45
|
+
}
|
|
46
|
+
const digits = match.replace(/\D/g, '').length;
|
|
47
|
+
return digits >= 9 && digits <= 15 ? '[phone]' : match;
|
|
48
|
+
}
|
|
49
|
+
export function redactPersonalData(text) {
|
|
50
|
+
return text
|
|
51
|
+
.replace(EMAIL, '[email]')
|
|
52
|
+
.replace(BEARER, 'Bearer [secret]')
|
|
53
|
+
.replace(JWT, '[secret]')
|
|
54
|
+
.replace(KEY_PREFIXES, '[secret]')
|
|
55
|
+
.replace(NAMED_SECRET, '$1$2[secret]')
|
|
56
|
+
.replace(QUOTED_PATH, '$1[path]$1')
|
|
57
|
+
.replace(LOCAL_PATH, '[path]')
|
|
58
|
+
.replace(PHONE_CANDIDATE, redactPhone);
|
|
59
|
+
}
|
|
60
|
+
function redactInfoParams(value) {
|
|
61
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
62
|
+
return value;
|
|
63
|
+
}
|
|
64
|
+
const record = value;
|
|
65
|
+
if (!FREE_TEXT_INFO_PARAMS.some((key) => typeof record[key] === 'string')) {
|
|
66
|
+
return value;
|
|
67
|
+
}
|
|
68
|
+
const redacted = { ...record };
|
|
69
|
+
for (const key of FREE_TEXT_INFO_PARAMS) {
|
|
70
|
+
if (typeof redacted[key] === 'string') {
|
|
71
|
+
redacted[key] = redactPersonalData(redacted[key]);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return redacted;
|
|
75
|
+
}
|
|
76
|
+
// A `files` argument carries a site's text whole: the upload tool's text bundle
|
|
77
|
+
// (`=== FILE: <path> ===` sections, `base64` for binaries) or a list of
|
|
78
|
+
// `{ path, content }` entries. The BI event goes out as a GET with the
|
|
79
|
+
// arguments in the query string, and a bundle past about 12 KB fails that
|
|
80
|
+
// request and loses the row (2026-10-28: every upload above that size was
|
|
81
|
+
// missing from BI). Recorded instead: the paths and their sizes, as the upload
|
|
82
|
+
// parses them (a base64 file's decoded size), with the path list cut at
|
|
83
|
+
// MAX_LISTED_PATHS_CHARS so a 2,000-file upload stays far below that limit too.
|
|
84
|
+
const MAX_LISTED_PATHS_CHARS = 2_000;
|
|
85
|
+
function summarizeFileBundle(bundle) {
|
|
86
|
+
let sections;
|
|
87
|
+
try {
|
|
88
|
+
sections = parseFileBundle(bundle).map((file) => ({
|
|
89
|
+
path: file.path,
|
|
90
|
+
bytes: file.bytes.length
|
|
91
|
+
}));
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
sections = [];
|
|
95
|
+
}
|
|
96
|
+
if (sections.length === 0) {
|
|
97
|
+
return `${new TextEncoder().encode(bundle).length} bytes, no file sections`;
|
|
98
|
+
}
|
|
99
|
+
return formatFileSummary(sections);
|
|
100
|
+
}
|
|
101
|
+
function formatFileSummary(files) {
|
|
102
|
+
const total = files.reduce((sum, file) => sum + file.bytes, 0);
|
|
103
|
+
let listed = '';
|
|
104
|
+
let shown = 0;
|
|
105
|
+
for (const file of files) {
|
|
106
|
+
const entry = `${shown ? ', ' : ''}${file.path} (${file.bytes})`;
|
|
107
|
+
if (listed.length + entry.length > MAX_LISTED_PATHS_CHARS)
|
|
108
|
+
break;
|
|
109
|
+
listed += entry;
|
|
110
|
+
shown++;
|
|
111
|
+
}
|
|
112
|
+
const more = files.length - shown;
|
|
113
|
+
return `${files.length} file(s), ${total} bytes: ${listed}${more ? `${shown ? ', ' : ''}and ${more} more` : ''}`;
|
|
114
|
+
}
|
|
115
|
+
function compactFileParams(value) {
|
|
116
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
117
|
+
return value;
|
|
118
|
+
}
|
|
119
|
+
const record = value;
|
|
120
|
+
const files = record.files;
|
|
121
|
+
if (typeof files === 'string') {
|
|
122
|
+
return { ...record, files: summarizeFileBundle(files) };
|
|
123
|
+
}
|
|
124
|
+
if (Array.isArray(files) &&
|
|
125
|
+
files.length > 0 &&
|
|
126
|
+
files.every((entry) => entry &&
|
|
127
|
+
typeof entry === 'object' &&
|
|
128
|
+
typeof entry.content === 'string')) {
|
|
129
|
+
return {
|
|
130
|
+
...record,
|
|
131
|
+
files: formatFileSummary(files.map((entry) => ({
|
|
132
|
+
path: entry.path ?? '?',
|
|
133
|
+
bytes: new TextEncoder().encode(entry.content).length
|
|
134
|
+
})))
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
return value;
|
|
138
|
+
}
|
|
139
|
+
function prepareForBi(value) {
|
|
140
|
+
return compactFileParams(redactInfoParams(value));
|
|
141
|
+
}
|
|
142
|
+
// Tool arguments as recorded in BI and error reports: the arguments object, or
|
|
143
|
+
// the MCP SDK's positional argument list, with the free-text info fields
|
|
144
|
+
// redacted and a `files` argument reduced to its paths and sizes.
|
|
145
|
+
export function serializeToolParamsForBi(args) {
|
|
146
|
+
return JSON.stringify(Array.isArray(args) ? args.map(prepareForBi) : prepareForBi(args));
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=redact-personal-data.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const SITE_BUILDER_TOOL_NAME = "
|
|
1
|
+
export declare const SITE_BUILDER_TOOL_NAME = "WixHarmonyEditorBuild";
|
|
2
2
|
export declare const EDIT_SITE_TOOL_NAME = "EditSite";
|
|
3
3
|
export declare const PULL_SITE_JOB_TOOL_NAME = "pullSiteCreationJob";
|
|
4
4
|
export declare const CLAIM_SITE_TOOL_NAME = "ClaimAnonymousSite";
|
|
@@ -6,6 +6,21 @@ export declare const GET_SUGGESTED_DOMAINS_TOOL_NAME = "GetSuggestedDomains";
|
|
|
6
6
|
export declare const WIX_SITE_CREATION_TOOL_NAME = "WixSiteCreation";
|
|
7
7
|
export declare const SEARCH_SITE_TEMPLATES_TOOL_NAME = "SearchSiteTemplates";
|
|
8
8
|
export declare const CREATE_SITE_FROM_TEMPLATE_TOOL_NAME = "CreateSiteFromTemplate";
|
|
9
|
+
export declare const PICK_IMAGES_TOOL_NAME = "PickImagesForWixMedia";
|
|
10
|
+
export declare const MEDIA_UPLOAD_URL_TOOL_NAME = "CreateWixMediaUploadUrl";
|
|
11
|
+
/** The Wix business features that send a site to StartHeadlessBuild: what wix-headless-kit ships. */
|
|
12
|
+
export declare const WIX_BUSINESS_FEATURES = "a store, bookings or appointments, rentals, events and tickets, a restaurant menu with online orders or reservations, a blog, a portfolio, pricing plans and memberships, donations, Wix Forms, members and login, a CMS, payments";
|
|
13
|
+
/** WixHarmonyEditorBuild's and SearchSiteTemplates' answer when the agent says the user did not ask for them. */
|
|
14
|
+
/**
|
|
15
|
+
* The widget payload of a refused editor call: the gallery and builder widgets render nothing
|
|
16
|
+
* for it, since the host mounts them for every call of their tool.
|
|
17
|
+
*/
|
|
18
|
+
export declare const NOT_REQUESTED_WIDGET_PAYLOAD: {
|
|
19
|
+
readonly notRequested: true;
|
|
20
|
+
};
|
|
21
|
+
export declare const EDITOR_NOT_REQUESTED_MESSAGE = "Nothing was created: the user did not ask for this. A new site is written in code and uploaded: call StartDeployWebsite, or StartHeadlessBuild when it needs Wix business features. Don't offer Wix's editor or a template instead.";
|
|
22
|
+
/** WixSiteCreation's answer: it no longer opens a chooser, it sends the agent to the code path. */
|
|
23
|
+
export declare const SITE_CREATION_ROUTE_MESSAGE = "A new site is written in code and uploaded. Call StartDeployWebsite now for the upload guide, or StartHeadlessBuild when the site needs Wix business features. Use WixHarmonyEditorBuild or SearchSiteTemplates only when the user asked for the Wix Harmony Editor, a template, Wix Studio or the Classic Editor.";
|
|
9
24
|
/** Fallback actions when the industry is generic or unclear. */
|
|
10
25
|
export declare const SITE_CREATION_DEFAULT_ACTIONS = "add products, set up bookings, and adjust your content";
|
|
11
26
|
/**
|
|
@@ -13,6 +28,38 @@ export declare const SITE_CREATION_DEFAULT_ACTIONS = "add products, set up booki
|
|
|
13
28
|
* that fill the "Next up:" line, generalizing to any industry (the patterns are a reference).
|
|
14
29
|
*/
|
|
15
30
|
export declare const SITE_CREATION_CUSTOM_ACTIONS_GUIDANCE = "2\u20133 specific, high-value setup actions for the site's industry, written as a comma-separated phrase (it slots into \"\u2026ask me to ___ right here in the chat\"). Use the following domain patterns as guidance:\n* E-commerce / Retail: \"add products, set up payment methods, and organize collections\"\n* Restaurants / Food / Bakeries: \"add menu items, set up online ordering, and collect table reservations\"\n* Services / Fitness / Salons / Consultants: \"set up booking slots, add service pricing, and manage appointments\"\n* Creative / Portfolios / Photographers: \"upload project galleries, feature client reviews, and customize contact forms\"\n* Events / Weddings / Real Estate: \"add event schedules, display listings, and manage RSVP forms\"\n* General / Unspecified: \"add products, set up bookings, and adjust your content\"\nIf none of these patterns fit the site, infer 2\u20133 actions that suit what that kind of business would manage on its site.";
|
|
31
|
+
/**
|
|
32
|
+
* Who builds a new site, as the user is asked it. Named by who builds it and where it gets
|
|
33
|
+
* edited, never "AI": the user is already talking to an AI, so "Build with AI" does not say
|
|
34
|
+
* which one. Shared by the tool descriptions, the chooser widget and its reply.
|
|
35
|
+
*/
|
|
36
|
+
export declare const SITE_BUILDER_CHOICE: {
|
|
37
|
+
readonly here: {
|
|
38
|
+
readonly label: "Build it here with me";
|
|
39
|
+
readonly pitch: "I build it in code right here, and you change anything by asking me";
|
|
40
|
+
};
|
|
41
|
+
readonly editor: {
|
|
42
|
+
readonly label: "Design it in Wix's editor";
|
|
43
|
+
readonly pitch: "Wix designs a first version or you start from a template, then you edit it in Wix";
|
|
44
|
+
};
|
|
45
|
+
/** The editor's second step, in the widget and its reply. */
|
|
46
|
+
readonly editorStart: {
|
|
47
|
+
readonly wix: {
|
|
48
|
+
readonly label: "Let Wix design it";
|
|
49
|
+
readonly pitch: "Wix designs a first version from your description for you to edit";
|
|
50
|
+
};
|
|
51
|
+
readonly template: {
|
|
52
|
+
readonly label: "Browse templates";
|
|
53
|
+
readonly pitch: "start from a ready-made design and edit it in Wix";
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
/** Asked in chat when no widget is shown: who builds it. */
|
|
57
|
+
readonly whoQuestion: "Do you want me to build it here, so you can change anything just by asking me, or do you want to design it yourself in Wix's editor?";
|
|
58
|
+
/** Asked next, only when the user chose Wix's editor. */
|
|
59
|
+
readonly editorQuestion: "Should Wix design a first version for you to edit, or do you want to start from a template?";
|
|
60
|
+
/** What the widget sends as the user's message when they pick "Build it here with me". */
|
|
61
|
+
readonly hereFollowUp: "Build it here with me, in code, so I can keep changing it by asking you.";
|
|
62
|
+
};
|
|
16
63
|
/**
|
|
17
64
|
* Builds the WixSiteCreation chooser reply. The message is fully composed here and wrapped in a
|
|
18
65
|
* preamble that tells the host model to display the body verbatim (keeping the bullets and line
|
|
@@ -24,8 +71,9 @@ export declare const SITE_CREATION_CUSTOM_ACTIONS_GUIDANCE = "2\u20133 specific,
|
|
|
24
71
|
* injection and blocks the whole reply ("Sorry, it looks like I can't chat about this"); there the
|
|
25
72
|
* verbatim-reply instruction lives only in the tool description.
|
|
26
73
|
*/
|
|
27
|
-
export declare function buildSiteCreationSelectorMessage(siteType?: string, customActions?: string, { plain }?: {
|
|
74
|
+
export declare function buildSiteCreationSelectorMessage(siteType?: string, customActions?: string, { plain, editorChosen }?: {
|
|
28
75
|
plain?: boolean;
|
|
76
|
+
editorChosen?: boolean;
|
|
29
77
|
}): string;
|
|
30
78
|
/** OpenAI/ChatGPT widget MIME type for Skybridge rendering */
|
|
31
79
|
export declare const OPENAI_WIDGET_MIME_TYPE = "text/html+skybridge";
|
|
@@ -1,13 +1,29 @@
|
|
|
1
1
|
// Tool name constants - separated to avoid circular dependencies during widget builds
|
|
2
2
|
// These constants can be imported by both the widgets and the tool implementations
|
|
3
|
-
|
|
3
|
+
// Named in SERVER_INSTRUCTIONS (config/default-config.ts): when this tool's name or what it is for changes, update them to match.
|
|
4
|
+
export const SITE_BUILDER_TOOL_NAME = 'WixHarmonyEditorBuild';
|
|
4
5
|
export const EDIT_SITE_TOOL_NAME = 'EditSite';
|
|
5
6
|
export const PULL_SITE_JOB_TOOL_NAME = 'pullSiteCreationJob';
|
|
6
7
|
export const CLAIM_SITE_TOOL_NAME = 'ClaimAnonymousSite';
|
|
7
8
|
export const GET_SUGGESTED_DOMAINS_TOOL_NAME = 'GetSuggestedDomains';
|
|
8
9
|
export const WIX_SITE_CREATION_TOOL_NAME = 'WixSiteCreation';
|
|
10
|
+
// Named in SERVER_INSTRUCTIONS (config/default-config.ts): when this tool's name or what it is for changes, update them to match.
|
|
9
11
|
export const SEARCH_SITE_TEMPLATES_TOOL_NAME = 'SearchSiteTemplates';
|
|
10
12
|
export const CREATE_SITE_FROM_TEMPLATE_TOOL_NAME = 'CreateSiteFromTemplate';
|
|
13
|
+
// Claude clients only: the image picker, and the app-only tool its widget uploads through.
|
|
14
|
+
export const PICK_IMAGES_TOOL_NAME = 'PickImagesForWixMedia';
|
|
15
|
+
export const MEDIA_UPLOAD_URL_TOOL_NAME = 'CreateWixMediaUploadUrl';
|
|
16
|
+
/** The Wix business features that send a site to StartHeadlessBuild: what wix-headless-kit ships. */
|
|
17
|
+
export const WIX_BUSINESS_FEATURES = 'a store, bookings or appointments, rentals, events and tickets, a restaurant menu with online orders or reservations, a blog, a portfolio, pricing plans and memberships, donations, Wix Forms, members and login, a CMS, payments';
|
|
18
|
+
/** WixHarmonyEditorBuild's and SearchSiteTemplates' answer when the agent says the user did not ask for them. */
|
|
19
|
+
/**
|
|
20
|
+
* The widget payload of a refused editor call: the gallery and builder widgets render nothing
|
|
21
|
+
* for it, since the host mounts them for every call of their tool.
|
|
22
|
+
*/
|
|
23
|
+
export const NOT_REQUESTED_WIDGET_PAYLOAD = { notRequested: true };
|
|
24
|
+
export const EDITOR_NOT_REQUESTED_MESSAGE = `Nothing was created: the user did not ask for this. A new site is written in code and uploaded: call StartDeployWebsite, or StartHeadlessBuild when it needs Wix business features. Don't offer Wix's editor or a template instead.`;
|
|
25
|
+
/** WixSiteCreation's answer: it no longer opens a chooser, it sends the agent to the code path. */
|
|
26
|
+
export const SITE_CREATION_ROUTE_MESSAGE = `A new site is written in code and uploaded. Call StartDeployWebsite now for the upload guide, or StartHeadlessBuild when the site needs Wix business features. Use WixHarmonyEditorBuild or SearchSiteTemplates only when the user asked for the Wix Harmony Editor, a template, Wix Studio or the Classic Editor.`;
|
|
11
27
|
/** Fallback actions when the industry is generic or unclear. */
|
|
12
28
|
export const SITE_CREATION_DEFAULT_ACTIONS = 'add products, set up bookings, and adjust your content';
|
|
13
29
|
/**
|
|
@@ -22,6 +38,38 @@ export const SITE_CREATION_CUSTOM_ACTIONS_GUIDANCE = `2–3 specific, high-value
|
|
|
22
38
|
* Events / Weddings / Real Estate: "add event schedules, display listings, and manage RSVP forms"
|
|
23
39
|
* General / Unspecified: "${SITE_CREATION_DEFAULT_ACTIONS}"
|
|
24
40
|
If none of these patterns fit the site, infer 2–3 actions that suit what that kind of business would manage on its site.`;
|
|
41
|
+
/**
|
|
42
|
+
* Who builds a new site, as the user is asked it. Named by who builds it and where it gets
|
|
43
|
+
* edited, never "AI": the user is already talking to an AI, so "Build with AI" does not say
|
|
44
|
+
* which one. Shared by the tool descriptions, the chooser widget and its reply.
|
|
45
|
+
*/
|
|
46
|
+
export const SITE_BUILDER_CHOICE = {
|
|
47
|
+
here: {
|
|
48
|
+
label: 'Build it here with me',
|
|
49
|
+
pitch: 'I build it in code right here, and you change anything by asking me'
|
|
50
|
+
},
|
|
51
|
+
editor: {
|
|
52
|
+
label: "Design it in Wix's editor",
|
|
53
|
+
pitch: 'Wix designs a first version or you start from a template, then you edit it in Wix'
|
|
54
|
+
},
|
|
55
|
+
/** The editor's second step, in the widget and its reply. */
|
|
56
|
+
editorStart: {
|
|
57
|
+
wix: {
|
|
58
|
+
label: 'Let Wix design it',
|
|
59
|
+
pitch: 'Wix designs a first version from your description for you to edit'
|
|
60
|
+
},
|
|
61
|
+
template: {
|
|
62
|
+
label: 'Browse templates',
|
|
63
|
+
pitch: 'start from a ready-made design and edit it in Wix'
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
/** Asked in chat when no widget is shown: who builds it. */
|
|
67
|
+
whoQuestion: "Do you want me to build it here, so you can change anything just by asking me, or do you want to design it yourself in Wix's editor?",
|
|
68
|
+
/** Asked next, only when the user chose Wix's editor. */
|
|
69
|
+
editorQuestion: 'Should Wix design a first version for you to edit, or do you want to start from a template?',
|
|
70
|
+
/** What the widget sends as the user's message when they pick "Build it here with me". */
|
|
71
|
+
hereFollowUp: 'Build it here with me, in code, so I can keep changing it by asking you.'
|
|
72
|
+
};
|
|
25
73
|
/**
|
|
26
74
|
* Builds the WixSiteCreation chooser reply. The message is fully composed here and wrapped in a
|
|
27
75
|
* preamble that tells the host model to display the body verbatim (keeping the bullets and line
|
|
@@ -33,23 +81,32 @@ If none of these patterns fit the site, infer 2–3 actions that suit what that
|
|
|
33
81
|
* injection and blocks the whole reply ("Sorry, it looks like I can't chat about this"); there the
|
|
34
82
|
* verbatim-reply instruction lives only in the tool description.
|
|
35
83
|
*/
|
|
36
|
-
export function buildSiteCreationSelectorMessage(siteType, customActions, { plain = false } = {}) {
|
|
84
|
+
export function buildSiteCreationSelectorMessage(siteType, customActions, { plain = false, editorChosen = false } = {}) {
|
|
37
85
|
const type = (siteType ?? '').trim() || 'new';
|
|
38
86
|
const actions = (customActions ?? '').trim() || SITE_CREATION_DEFAULT_ACTIONS;
|
|
87
|
+
// With the editor already chosen, the widget opens at "how to start", so the two
|
|
88
|
+
// bullets are that step's options instead of who builds it.
|
|
89
|
+
const here = editorChosen
|
|
90
|
+
? `* **${SITE_BUILDER_CHOICE.editorStart.wix.label}**: ${SITE_BUILDER_CHOICE.editorStart.wix.pitch}`
|
|
91
|
+
: `* **${SITE_BUILDER_CHOICE.here.label}**: ${SITE_BUILDER_CHOICE.here.pitch}`;
|
|
92
|
+
const editor = editorChosen
|
|
93
|
+
? `* **${SITE_BUILDER_CHOICE.editorStart.template.label}**: ${SITE_BUILDER_CHOICE.editorStart.template.pitch}`
|
|
94
|
+
: `* **${SITE_BUILDER_CHOICE.editor.label}**: ${SITE_BUILDER_CHOICE.editor.pitch}`;
|
|
95
|
+
const nextUp = `**Next up:** Either way, you can ask me to ${actions}—right here in the chat!`;
|
|
39
96
|
const body = `Ready to set up your ${type} site? Choose your path in the widget above:
|
|
40
97
|
|
|
41
|
-
|
|
42
|
-
|
|
98
|
+
${here}
|
|
99
|
+
${editor}
|
|
43
100
|
|
|
44
|
-
|
|
101
|
+
${nextUp}`;
|
|
45
102
|
if (plain) {
|
|
46
103
|
return body;
|
|
47
104
|
}
|
|
48
105
|
return `You are the assistant replying to the user — say this message out loud in chat (do NOT stay silent, and do NOT just point at the widget). Your reply is only complete if it includes ALL of the following, word for word, each on its own line and in this order:
|
|
49
106
|
1. "Ready to set up your ${type} site? Choose your path in the widget above:" — keep the "Choose your path in the widget above:" part.
|
|
50
|
-
2. "
|
|
51
|
-
3. "
|
|
52
|
-
4. "
|
|
107
|
+
2. "${here}"
|
|
108
|
+
3. "${editor}"
|
|
109
|
+
4. "${nextUp}"
|
|
53
110
|
|
|
54
111
|
Copy those four lines as written; do not summarize, shorten, reorder, or reword any of them. Here is the full message to send:
|
|
55
112
|
|
|
@@ -9,5 +9,6 @@ export { addSuggestedDomainTool } from './suggested-domain-tool/index.js';
|
|
|
9
9
|
export { addWixSiteCreationTool } from './site-creation-tool/index.js';
|
|
10
10
|
export { addSearchSiteTemplatesTool } from './search-site-templates-tool/index.js';
|
|
11
11
|
export { addCreateSiteFromTemplateTool } from './create-site-from-template-tool/index.js';
|
|
12
|
+
export { addPickImagesTools } from './pick-images-tool/index.js';
|
|
12
13
|
export declare function addSiteCreationWidgetTools(server: WixMcpServer, authStrategy: McpAuthenticationStrategy, options?: SiteWidgetToolOptions): void;
|
|
13
14
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -10,6 +10,7 @@ export { addSuggestedDomainTool } from './suggested-domain-tool/index.js';
|
|
|
10
10
|
export { addWixSiteCreationTool } from './site-creation-tool/index.js';
|
|
11
11
|
export { addSearchSiteTemplatesTool } from './search-site-templates-tool/index.js';
|
|
12
12
|
export { addCreateSiteFromTemplateTool } from './create-site-from-template-tool/index.js';
|
|
13
|
+
export { addPickImagesTools } from './pick-images-tool/index.js';
|
|
13
14
|
// Combine all the required site widget tools
|
|
14
15
|
export function addSiteCreationWidgetTools(server, authStrategy, options) {
|
|
15
16
|
addCreateSiteWidgetTool(server, authStrategy, options);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { McpAuthenticationStrategy } from '../../auth/index.js';
|
|
2
|
+
import { WixMcpServer } from '../../wix-mcp-server.js';
|
|
3
|
+
/**
|
|
4
|
+
* Exists only because Claude can't hand a file to a tool: recheck when it can (see
|
|
5
|
+
* config/file-params.ts), and drop or narrow this then.
|
|
6
|
+
*
|
|
7
|
+
* The image picker for clients that can't hand a file to a tool (Claude): the user
|
|
8
|
+
* picks images in a widget, which uploads them from the browser to the site's Media
|
|
9
|
+
* Manager through upload URLs from the app-only CreateWixMediaUploadUrl tool.
|
|
10
|
+
*/
|
|
11
|
+
export declare function addPickImagesTools(server: WixMcpServer, strategy: McpAuthenticationStrategy, options?: {
|
|
12
|
+
toolDescriptions?: Record<string, string>;
|
|
13
|
+
}): void;
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { RESOURCE_MIME_TYPE } from '@modelcontextprotocol/ext-apps/server';
|
|
3
|
+
import { rethrowIfUnauthorized } from '../../auth/index.js';
|
|
4
|
+
import { getWidgetHtml } from '../../widget-manifest.js';
|
|
5
|
+
import { withJsonContent } from '../../tool-utils.js';
|
|
6
|
+
import { WixFetchError } from '../../wix-fetch-error.js';
|
|
7
|
+
import { defaultToolDescriptions } from '../../config/default-config.js';
|
|
8
|
+
import { MEDIA_UPLOAD_URL_TOOL_NAME, PICK_IMAGES_TOOL_NAME } from '../constants.js';
|
|
9
|
+
const PICK_IMAGES_WIDGET_URI = 'ui://widget/pick-images.html';
|
|
10
|
+
// The widget uploads each picked file from the user's browser straight to the
|
|
11
|
+
// Media Manager upload URL, so upload.wixmp.com must be reachable from it.
|
|
12
|
+
const PICK_IMAGES_CSP = {
|
|
13
|
+
connectDomains: [
|
|
14
|
+
'https://upload.wixmp.com',
|
|
15
|
+
'https://static.parastorage.com'
|
|
16
|
+
],
|
|
17
|
+
resourceDomains: [
|
|
18
|
+
'https://static.wixstatic.com',
|
|
19
|
+
'https://static.parastorage.com',
|
|
20
|
+
'data:',
|
|
21
|
+
'blob:'
|
|
22
|
+
]
|
|
23
|
+
};
|
|
24
|
+
const PICKER_OPEN_TEXT = "An image picker is open in the chat. The user selects images there; they upload to the site's Media Manager, and a message with each image's media ID and URL follows. Reply with one short sentence and wait for that message. If your client shows no picker, send the images with UploadImageToWixSite as imageBase64, or ask the user for public URLs.";
|
|
25
|
+
const siteIdSchema = z
|
|
26
|
+
.string()
|
|
27
|
+
.uuid('siteId must be a valid Wix site ID (UUID)');
|
|
28
|
+
/**
|
|
29
|
+
* Exists only because Claude can't hand a file to a tool: recheck when it can (see
|
|
30
|
+
* config/file-params.ts), and drop or narrow this then.
|
|
31
|
+
*
|
|
32
|
+
* The image picker for clients that can't hand a file to a tool (Claude): the user
|
|
33
|
+
* picks images in a widget, which uploads them from the browser to the site's Media
|
|
34
|
+
* Manager through upload URLs from the app-only CreateWixMediaUploadUrl tool.
|
|
35
|
+
*/
|
|
36
|
+
export function addPickImagesTools(server, strategy, options) {
|
|
37
|
+
server.registerResource(`${PICK_IMAGES_TOOL_NAME}_RESOURCE`, PICK_IMAGES_WIDGET_URI, {}, async (uri) => ({
|
|
38
|
+
contents: [
|
|
39
|
+
{
|
|
40
|
+
uri: uri.href,
|
|
41
|
+
_meta: { ui: { csp: PICK_IMAGES_CSP } },
|
|
42
|
+
mimeType: RESOURCE_MIME_TYPE,
|
|
43
|
+
text: getWidgetHtml({
|
|
44
|
+
widgetId: 'pickImages',
|
|
45
|
+
props: { renderMcpApps: true }
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
}));
|
|
50
|
+
server.registerTool(PICK_IMAGES_TOOL_NAME, {
|
|
51
|
+
title: 'Pick Images to Upload to Wix',
|
|
52
|
+
description: options?.toolDescriptions?.[PICK_IMAGES_TOOL_NAME] ??
|
|
53
|
+
defaultToolDescriptions[PICK_IMAGES_TOOL_NAME],
|
|
54
|
+
inputSchema: {
|
|
55
|
+
siteId: siteIdSchema.describe('The site whose Media Manager receives the images.')
|
|
56
|
+
},
|
|
57
|
+
_meta: {
|
|
58
|
+
ui: {
|
|
59
|
+
resourceUri: PICK_IMAGES_WIDGET_URI,
|
|
60
|
+
visibility: ['app', 'model']
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
annotations: {
|
|
64
|
+
readOnlyHint: false,
|
|
65
|
+
destructiveHint: false,
|
|
66
|
+
openWorldHint: true
|
|
67
|
+
}
|
|
68
|
+
}, async ({ siteId }, { setToolBiParams }) => {
|
|
69
|
+
setToolBiParams({ siteId });
|
|
70
|
+
return withJsonContent({
|
|
71
|
+
content: [{ type: 'text', text: PICKER_OPEN_TEXT }],
|
|
72
|
+
structuredContent: { siteId },
|
|
73
|
+
_meta: { widgetPayload: { siteId } }
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
server.registerTool(MEDIA_UPLOAD_URL_TOOL_NAME, {
|
|
77
|
+
title: 'Create Wix Media Upload URL',
|
|
78
|
+
description: `Used by the ${PICK_IMAGES_TOOL_NAME} widget: returns a one-time URL the widget uploads one picked image to. Not for direct use.`,
|
|
79
|
+
inputSchema: {
|
|
80
|
+
siteId: siteIdSchema,
|
|
81
|
+
fileName: z.string().min(1).max(200),
|
|
82
|
+
mimeType: z
|
|
83
|
+
.string()
|
|
84
|
+
.regex(/^image\//, 'Only images can be uploaded here'),
|
|
85
|
+
sizeInBytes: z.number().int().positive().optional()
|
|
86
|
+
},
|
|
87
|
+
_meta: { ui: { visibility: ['app'] } },
|
|
88
|
+
annotations: {
|
|
89
|
+
readOnlyHint: false,
|
|
90
|
+
destructiveHint: false,
|
|
91
|
+
openWorldHint: true
|
|
92
|
+
}
|
|
93
|
+
}, async ({ siteId, fileName, mimeType, sizeInBytes }, { setToolBiParams }) => {
|
|
94
|
+
setToolBiParams({ siteId });
|
|
95
|
+
try {
|
|
96
|
+
const authHeaders = await strategy.getSiteAuthHeaders(siteId);
|
|
97
|
+
const res = await fetch('https://www.wixapis.com/site-media/v1/files/generate-upload-url', {
|
|
98
|
+
method: 'POST',
|
|
99
|
+
headers: { ...authHeaders, 'Content-Type': 'application/json' },
|
|
100
|
+
body: JSON.stringify({
|
|
101
|
+
mimeType,
|
|
102
|
+
fileName,
|
|
103
|
+
...(sizeInBytes ? { sizeInBytes: String(sizeInBytes) } : {})
|
|
104
|
+
})
|
|
105
|
+
});
|
|
106
|
+
if (!res.ok) {
|
|
107
|
+
throw new WixFetchError(res.status, res.statusText, await res.text());
|
|
108
|
+
}
|
|
109
|
+
const { uploadUrl } = (await res.json());
|
|
110
|
+
if (!uploadUrl) {
|
|
111
|
+
throw new Error('Wix returned no upload URL');
|
|
112
|
+
}
|
|
113
|
+
// The URL is a one-time upload grant: never in the text content, which BI
|
|
114
|
+
// records as the result preview. _meta carries it for hosts that drop
|
|
115
|
+
// structuredContent.
|
|
116
|
+
return {
|
|
117
|
+
content: [{ type: 'text', text: 'Upload URL created.' }],
|
|
118
|
+
structuredContent: { uploadUrl },
|
|
119
|
+
_meta: { uploadUrl }
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
rethrowIfUnauthorized(error);
|
|
124
|
+
await strategy.enforceValidWixToken?.(error);
|
|
125
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
126
|
+
return {
|
|
127
|
+
isError: true,
|
|
128
|
+
content: [
|
|
129
|
+
{
|
|
130
|
+
type: 'text',
|
|
131
|
+
text: `Failed to create an upload URL: ${message}`
|
|
132
|
+
}
|
|
133
|
+
]
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -13,7 +13,7 @@ export function addPullSiteJobTool(server, authStrategy, options) {
|
|
|
13
13
|
title: 'Pull Site Job',
|
|
14
14
|
description: isWidgetClient
|
|
15
15
|
? 'Poll the status of a site creation or editing job. Do not call this tool unless the user explicitly asks for status polling.'
|
|
16
|
-
: 'Poll the status of a site creation or editing job. Call this tool with the jobId returned by
|
|
16
|
+
: 'Poll the status of a site creation or editing job. Call this tool with the jobId returned by WixHarmonyEditorBuild or EditSite to check if the site build is complete. When the job status is COMPLETED, the response includes the previewUrl and editorUrl.',
|
|
17
17
|
inputSchema: {
|
|
18
18
|
jobId: z.string().describe('The job ID to pull')
|
|
19
19
|
},
|
|
@@ -6,8 +6,9 @@ import { Type, TemplateBuilder } from '@wix/ambassador-funnel-templates-gallery-
|
|
|
6
6
|
import { getWidgetHtml } from '../../widget-manifest.js';
|
|
7
7
|
import { RESOURCE_MIME_TYPE } from '@modelcontextprotocol/ext-apps/server';
|
|
8
8
|
import { defaultToolDescriptions } from '../../config/default-config.js';
|
|
9
|
-
import { SEARCH_SITE_TEMPLATES_TOOL_NAME, CREATE_SITE_FROM_TEMPLATE_TOOL_NAME, SITE_WIDGET_MCP_CSP, OPEN_AI_SITE_WIDGET_CSP } from '../constants.js';
|
|
9
|
+
import { EDITOR_NOT_REQUESTED_MESSAGE, NOT_REQUESTED_WIDGET_PAYLOAD, SEARCH_SITE_TEMPLATES_TOOL_NAME, CREATE_SITE_FROM_TEMPLATE_TOOL_NAME, SITE_WIDGET_MCP_CSP, OPEN_AI_SITE_WIDGET_CSP } from '../constants.js';
|
|
10
10
|
import { withJsonContent } from '../../tool-utils.js';
|
|
11
|
+
import { NO_PERSONAL_DATA, START_DEPLOY_WEBSITE_PARAM_DESCRIPTIONS } from '../../docs/start-deploy-website.js';
|
|
11
12
|
// baseURL pins the host so the ambassador resolves to the public template-search
|
|
12
13
|
// endpoint: https://www.wix.com/_api/template-cms-view-service/view/v2/templates/search
|
|
13
14
|
const httpClient = createHttpClient({ baseURL: 'https://www.wix.com' });
|
|
@@ -69,7 +70,19 @@ export function addSearchSiteTemplatesTool(server, _authStrategy, options) {
|
|
|
69
70
|
.min(1)
|
|
70
71
|
.max(MAX_TEMPLATE_RESULTS)
|
|
71
72
|
.optional()
|
|
72
|
-
.describe(`Maximum number of templates to return (capped at ${MAX_TEMPLATE_RESULTS}).`)
|
|
73
|
+
.describe(`Maximum number of templates to return (capped at ${MAX_TEMPLATE_RESULTS}).`),
|
|
74
|
+
templatesExplicitlyRequested: z
|
|
75
|
+
.boolean()
|
|
76
|
+
.optional()
|
|
77
|
+
.describe("Did the user, in their own words or their answer to your question, ask for a template, Wix Studio, or the Classic Editor by name? Wanting Wix's editor, or to design the site themselves, is not that: ask them how to start first. Nor are a site's business, features or look."),
|
|
78
|
+
templateRequest: z
|
|
79
|
+
.string()
|
|
80
|
+
.optional()
|
|
81
|
+
.describe(`The user's own words that asked for a template, Wix Studio or the Classic Editor, quoted from their message or their answer to your question. Empty when they asked for none of them; then templatesExplicitlyRequested is false. Recorded, not checked. ${NO_PERSONAL_DATA}`),
|
|
82
|
+
agentIdentity: z
|
|
83
|
+
.string()
|
|
84
|
+
.optional()
|
|
85
|
+
.describe(START_DEPLOY_WEBSITE_PARAM_DESCRIPTIONS.agentIdentity)
|
|
73
86
|
},
|
|
74
87
|
_meta: {
|
|
75
88
|
ui: {
|
|
@@ -86,6 +99,16 @@ export function addSearchSiteTemplatesTool(server, _authStrategy, options) {
|
|
|
86
99
|
idempotentHint: true
|
|
87
100
|
}
|
|
88
101
|
}, async (args, { panorama }) => {
|
|
102
|
+
// Only an explicit false is refused: clients that hold the previous definition never send the flag.
|
|
103
|
+
if (args.templatesExplicitlyRequested === false) {
|
|
104
|
+
return withJsonContent({
|
|
105
|
+
content: [
|
|
106
|
+
{ type: 'text', text: EDITOR_NOT_REQUESTED_MESSAGE }
|
|
107
|
+
],
|
|
108
|
+
structuredContent: { success: false, status: 'not_requested' },
|
|
109
|
+
_meta: { widgetPayload: NOT_REQUESTED_WIDGET_PAYLOAD }
|
|
110
|
+
});
|
|
111
|
+
}
|
|
89
112
|
const limit = args.limit ?? MAX_TEMPLATE_RESULTS;
|
|
90
113
|
console.log(`[${SEARCH_SITE_TEMPLATES_TOOL_NAME}] 🚀 tool invoked`, {
|
|
91
114
|
builder: args.builder,
|