@wix/mcp 1.0.91 → 1.0.93
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 +63 -28
- package/build/cjs/index.cjs +282 -31
- package/build/cjs/toolkit.cjs +282 -31
- package/build/dts/code-mode/attachments.d.ts +37 -0
- package/build/dts/code-mode/attachments.js +218 -0
- package/build/dts/code-mode/index.js +36 -3
- package/build/dts/config/default-config.js +21 -12
- package/build/dts/config/param-descriptions.js +3 -3
- package/build/dts/docs/docs.js +14 -8
- package/build/dts/docs/semanticSearch.d.ts +2 -1
- package/build/dts/docs/semanticSearch.js +12 -5
- package/build/dts/docs/start-deploy-website.d.ts +9 -1
- package/build/dts/docs/start-deploy-website.js +36 -4
- package/build/esm/index.js +282 -31
- package/build/esm/toolkit.js +282 -31
- package/package.json +2 -2
package/build/esm/toolkit.js
CHANGED
|
@@ -10714,9 +10714,12 @@ var runSemanticSearch = async (toolName, toolParams, maxResults = 20, rerank = f
|
|
|
10714
10714
|
);
|
|
10715
10715
|
return data?.results;
|
|
10716
10716
|
};
|
|
10717
|
-
var runPlatformizedSemanticSearch = async (toolName, searchTerm, maxResults = 20, linesInEachResult) => {
|
|
10717
|
+
var runPlatformizedSemanticSearch = async (toolName, searchTerm, maxResults = 20, linesInEachResult, extraDocumentTypes) => {
|
|
10718
10718
|
const startTime = Date.now();
|
|
10719
|
-
|
|
10719
|
+
const documentTypes = extraDocumentTypes?.length ? [toolName, ...extraDocumentTypes] : void 0;
|
|
10720
|
+
logger.log(
|
|
10721
|
+
`[SemanticSearch/v2] Tool: ${documentTypes ? documentTypes.join("+") : toolName}, Query: "${searchTerm}"`
|
|
10722
|
+
);
|
|
10720
10723
|
const response = await fetch(
|
|
10721
10724
|
"https://www.wixapis.com/mcp-docs-search/v1/docs/search/markdown",
|
|
10722
10725
|
{
|
|
@@ -10727,7 +10730,7 @@ var runPlatformizedSemanticSearch = async (toolName, searchTerm, maxResults = 20
|
|
|
10727
10730
|
},
|
|
10728
10731
|
body: JSON.stringify({
|
|
10729
10732
|
search_term: searchTerm,
|
|
10730
|
-
document_type: toolName,
|
|
10733
|
+
...documentTypes ? { document_types: documentTypes } : { document_type: toolName },
|
|
10731
10734
|
maximum_results: maxResults,
|
|
10732
10735
|
lines_in_each_result: linesInEachResult
|
|
10733
10736
|
})
|
|
@@ -10756,14 +10759,16 @@ var runSemanticSearchAndFormat = async ({
|
|
|
10756
10759
|
maxResults = DEFAULT_MAX_RESULTS,
|
|
10757
10760
|
rerank,
|
|
10758
10761
|
linesInEachResult,
|
|
10759
|
-
usePlatformizedSearch = true
|
|
10762
|
+
usePlatformizedSearch = true,
|
|
10763
|
+
extraDocumentTypes
|
|
10760
10764
|
}) => {
|
|
10761
10765
|
if (usePlatformizedSearch) {
|
|
10762
10766
|
return runPlatformizedSemanticSearch(
|
|
10763
10767
|
toolName,
|
|
10764
10768
|
toolParams.searchTerm,
|
|
10765
10769
|
maxResults,
|
|
10766
|
-
linesInEachResult
|
|
10770
|
+
linesInEachResult,
|
|
10771
|
+
extraDocumentTypes
|
|
10767
10772
|
);
|
|
10768
10773
|
} else {
|
|
10769
10774
|
const results = await runSemanticSearch(
|
|
@@ -12204,9 +12209,11 @@ var SITE_CREATION_COPY = {
|
|
|
12204
12209
|
}
|
|
12205
12210
|
};
|
|
12206
12211
|
var SITE_GUIDANCE = dedent_default`
|
|
12207
|
-
|
|
12212
|
+
First decide which of two different things is being asked for:
|
|
12213
|
+
- The site is code the user or you control — hand-written HTML/CSS/JS, a static build, a zip, another AI builder's export, or a page or design you made earlier in this conversation — and it should go live on Wix. This is also the route whenever the user wants to keep working on the site here, with you: a Wix Headless site is a regular coded site, so you keep full control of the design and can change and redeploy it from this conversation at any time, and Wix business capabilities can be added to it as a backend when they are needed. Call StartDeployWebsite: it returns the recipe to host those exact files as a Wix Headless site (updates reuse the same site and URL; the drop page is only its fallback). Do not offer AI or templates for this and do not call any site-creation tool.
|
|
12214
|
+
- Wix should create the site — generated with AI from a description, or started from a template — and the user will design and edit it in Wix rather than through you. That is what the site-creation tools do; they never take files you already have.
|
|
12208
12215
|
|
|
12209
|
-
|
|
12216
|
+
For a new site there are two things to settle: what the site is for, and how to build it. The how is AI generation vs. starting from a template, so naming templates, a template id or Wix Studio (Wix Studio is also the template side) already settles it.
|
|
12210
12217
|
|
|
12211
12218
|
Settle what the site is for first: its purpose, topic, business type, audience, or main visitor action. Naming a method is not a description of the site, and neither is the business or industry on its own.
|
|
12212
12219
|
If you can't tell yet, ask the preferred question below and nothing else — one question, no creation-method question in the same reply, and no internal tool names.
|
|
@@ -12303,13 +12310,14 @@ var ACCOUNT_SITE_EXECUTE_SCOPE = dedent_default`
|
|
|
12303
12310
|
unzip(input: string | Uint8Array): Promise<Array<{ path: string; bytes: Uint8Array; text(): string }>>;
|
|
12304
12311
|
};
|
|
12305
12312
|
declare const siteId: string | undefined;
|
|
12306
|
-
// Files from the ExecuteWixAPI \`files\` param
|
|
12307
|
-
//
|
|
12308
|
-
//
|
|
12313
|
+
// Files from the ExecuteWixAPI \`files\` param, followed by the resolved
|
|
12314
|
+
// \`attachments\`. Text entries have \`content\`; an entry tagged
|
|
12315
|
+
// \`=== FILE: <path> base64 ===\` — and every attachment, path = its file name —
|
|
12316
|
+
// has encoding:'base64' and base64 \`content\`.
|
|
12309
12317
|
declare const files: Array<{ path: string; content: string; encoding?: "base64" }>;
|
|
12310
12318
|
\`\`\`
|
|
12311
12319
|
|
|
12312
|
-
FILE UPLOADS:
|
|
12320
|
+
FILE UPLOADS: files never go inline in \`code\`; two params feed the \`files\` global. \`attachments\` takes files attached in the chat or created in your file sandbox, of any type and size up to 10 MB per call (a zip of a whole site, HTML, images, PDFs): pass the files themselves, all in one call, and the platform resolves each into \`{ download_url, file_id, file_name?, mime_type? }\` — the bytes are fetched for you and arrive as base64 entries named by file name. The \`files\` param takes content you have as text here: text goes raw; a small binary (icon, logo, font) rides as a \`base64\`-tagged entry — large images/video are referenced by URL (\`<img src="https://...">\`), not bundled. \`wix.multipart()\` turns the whole set into one upload body (bytes, so binary is safe):
|
|
12313
12321
|
\`\`\`javascript
|
|
12314
12322
|
// files param:
|
|
12315
12323
|
// === FILE: index.html ===
|
|
@@ -12324,6 +12332,12 @@ var ACCOUNT_SITE_EXECUTE_SCOPE = dedent_default`
|
|
|
12324
12332
|
return res.data;
|
|
12325
12333
|
}
|
|
12326
12334
|
\`\`\`
|
|
12335
|
+
A site zip passed through \`attachments\` is one base64 entry; unzip it and upload the entries:
|
|
12336
|
+
\`\`\`javascript
|
|
12337
|
+
// attachments: [site.zip] → files = [{ path: "site.zip", content: "<base64>", encoding: "base64" }]
|
|
12338
|
+
const entries = await wix.unzip(files[0].content); // [{ path, bytes, text() }]
|
|
12339
|
+
const mp = wix.multipart(entries);
|
|
12340
|
+
\`\`\`
|
|
12327
12341
|
DOWNLOAD + EDIT + RE-UPLOAD: fetch the zip as base64, \`wix.unzip()\` it, edit text via \`entry.text()\`, keep binary as bytes, and hand the entries back to \`wix.multipart()\`:
|
|
12328
12342
|
\`\`\`javascript
|
|
12329
12343
|
const r = await wix.request({ scope: "account", method: "GET", responseType: "base64", url: zipUrl });
|
|
@@ -12528,12 +12542,12 @@ function buildToolDescriptions(includeReadme, includeImageUploadGuidance = true)
|
|
|
12528
12542
|
NEVER call this tool with a missing, empty, or guessed siteId — ask first instead.
|
|
12529
12543
|
|
|
12530
12544
|
Parameters — provide image input via image and/or imageUrls, OR imageBase64:
|
|
12531
|
-
• image (array): chat file ATTACHMENTS. Each item is an object with download_url and file_id (both required), plus optional file_name and mime_type. Pass ALL attachments in one call.
|
|
12545
|
+
• image (array): chat file ATTACHMENTS — files the user attached, or files you created in your own file sandbox. Each item is an object with download_url and file_id (both required), plus optional file_name and mime_type. Pass ALL attachments in one call.
|
|
12532
12546
|
• imageUrls (array): plain public image URLs the user pasted or other tools produced (no file_id). Pass ALL URLs in one call. Can be combined with image.
|
|
12533
12547
|
• imageBase64 (string): base64-encoded image + mimeType. One image at a time. Do NOT combine with image/imageUrls.
|
|
12534
12548
|
|
|
12535
12549
|
Delivering the bytes — this is where uploads most often fail:
|
|
12536
|
-
•
|
|
12550
|
+
• Pass a file as a file, in image: the platform resolves it into download_url and file_id before it reaches this tool — this includes files you created in your sandbox. This server does not share your filesystem, so a bare path string (e.g. /mnt/..., /home/user/..., /Users/...) is not a file. Without a file to pass, use a public http(s) URL (imageUrls) or the complete base64 (imageBase64).
|
|
12537
12551
|
• imageBase64 must be the WHOLE file, not truncated. For large images prefer imageUrls, since long base64 is easily cut off and will be rejected as unreadable.
|
|
12538
12552
|
`,
|
|
12539
12553
|
SupportAndFeedback: dedent_default`
|
|
@@ -13030,14 +13044,14 @@ function buildToolDescriptions(includeReadme, includeImageUploadGuidance = true)
|
|
|
13030
13044
|
WixSiteBuilder: dedent_default`
|
|
13031
13045
|
${SITE_GUIDANCE}
|
|
13032
13046
|
|
|
13033
|
-
Tool for generating a Wix site with AI (creating / building a site in Wix Harmony).
|
|
13047
|
+
Tool for generating a Wix site with AI (creating / building a site in Wix Harmony) from a description. It does not take pages or files you already have — those go to StartDeployWebsite.
|
|
13034
13048
|
|
|
13035
13049
|
Call this ONLY when the user's own words name AI (for example "create a site using AI" or "build it with AI") and the site intent is clear. A description of what the site should do — reservations, online ordering, a store, bookings, menus, a portfolio, and the like — is NOT a request for AI and NOT enough to call this tool; never infer AI from features or industry.
|
|
13036
13050
|
Never default to this tool: if the user hasn't explicitly named AI, don't call this tool — ${SITE_CREATION_COPY.unstatedMethod.nonWidget}.
|
|
13037
13051
|
|
|
13038
13052
|
For templates or Wix Studio, call \`SearchSiteTemplates\`; for a specific template by \`metaSiteId\` or \`templateId\`, call \`CreateSiteFromTemplate\`; for a headless or classic Wix Editor site, or manual/account-API creation, call \`CreateWixBusinessGuide\`.
|
|
13039
13053
|
|
|
13040
|
-
Do NOT suggest HTML code, prompt templates, or alternative approaches — actually build the site through this tool.
|
|
13054
|
+
Do NOT suggest HTML code, prompt templates, or alternative approaches instead of building — actually build the site through this tool. (HTML the user already has is the StartDeployWebsite case, not a reason to build.)
|
|
13041
13055
|
`,
|
|
13042
13056
|
SearchSiteTemplates: dedent_default`
|
|
13043
13057
|
${SITE_GUIDANCE}
|
|
@@ -13081,8 +13095,8 @@ function buildToolDescriptions(includeReadme, includeImageUploadGuidance = true)
|
|
|
13081
13095
|
Set \`hasMutations: true\` for any document containing a mutation root field.
|
|
13082
13096
|
`,
|
|
13083
13097
|
StartDeployWebsite: dedent_default`
|
|
13084
|
-
The user — or you, earlier in this conversation — ALREADY HAVE a finished page or site, in any form, and it should be live on Wix
|
|
13085
|
-
|
|
13098
|
+
The user — or you, earlier in this conversation — ALREADY HAVE a finished page or site, in any form, and it should be live on Wix — or an already-deployed Wix Headless site whose files should be replaced. The site can be HTML/CSS/JS files, a static build (dist/, out/), a zip, another AI builder's export, or a page/design you created in this conversation (export it to HTML first — a finished design IS a finished page). Call this when the user says deploy, host, publish, put online, make it live, get a URL, update my site, or upload my site / index.html.
|
|
13099
|
+
Updates keep the same site and URL. Also for implementing a backend on such a site as a Wix Headless project — same site, same URL. Works with or without a Wix login (anonymous deploy with a save link), through the Wix MCP alone or from a shell.
|
|
13086
13100
|
Missing real functionality — a fake checkout, a form that goes nowhere, bookings — is NOT a reason to rebuild the site with a site-creation tool: deploy the page as is, then add the backend afterwards (the recipe covers it).
|
|
13087
13101
|
Returns the full recipe; follow it and run the flow yourself. The drop page is only the fallback when you can't.
|
|
13088
13102
|
NOT for: a screenshot, mockup or reference image of a site the user WANTS (nothing exists to deploy yet — that is site creation: WixSiteBuilder / templates); a Claude Design share URL (import-claude-design-from-url); migrating a live site by URL or CSV exports; adding HTML or code into an existing Wix site; uploading images or documents to a site's media (UploadImageToWixSite).
|
|
@@ -13785,7 +13799,7 @@ var paramDescriptions = {
|
|
|
13785
13799
|
},
|
|
13786
13800
|
SearchWixRESTDocumentation: {
|
|
13787
13801
|
searchTerm: `The search term to look up in the Wix REST API Documentation \u2014 a natural-language description of the endpoint, resource, or action you need across any Wix domain (Stores, eCommerce, Bookings, CRM, Members, CMS, Events, Blog, Forms, Media, site settings, etc.), e.g. "create a catalog item with inventory", "book a service", "update data collection items". Match the wording to how many entities you will act on: a plural term ("update products") surfaces the resource's bulk methods, which a singular term ("update a product") ranks lower or leaves out. Results are ranked by relevance, so describe the goal rather than guessing an exact API name.`,
|
|
13788
|
-
maxResults: "The maximum number of results to return, default
|
|
13802
|
+
maxResults: "The maximum number of results to return (1\u201317, default 17). Results mix REST API documentation with matching recipes and skills.",
|
|
13789
13803
|
reason: "One sentence describing the original user request and the task you are trying to accomplish with this search."
|
|
13790
13804
|
},
|
|
13791
13805
|
WixBusinessFlowsDocumentation: {
|
|
@@ -13806,7 +13820,7 @@ var paramDescriptions = {
|
|
|
13806
13820
|
},
|
|
13807
13821
|
SearchWixHeadlessDocumentation: {
|
|
13808
13822
|
searchTerm: "The search term to search for in the Headless Documentation",
|
|
13809
|
-
maxResults: "The maximum number of results to return, default
|
|
13823
|
+
maxResults: "The maximum number of results to return (1\u201317, default 17). Results mix Headless documentation with matching recipes and skills."
|
|
13810
13824
|
},
|
|
13811
13825
|
SearchWixVeloDocumentation: {
|
|
13812
13826
|
searchTerm: "The search term to search for in the Velo Documentation",
|
|
@@ -13834,7 +13848,7 @@ var paramDescriptions = {
|
|
|
13834
13848
|
},
|
|
13835
13849
|
UploadImageToWixSite: {
|
|
13836
13850
|
siteId: "The ID (UUID) of the Wix site to upload to. REQUIRED. If the user has not clearly specified which site, ASK them which site to upload to (or use ListWixSites to help them pick) BEFORE calling this tool. NEVER call this tool with a missing, empty, placeholder, or guessed siteId \u2014 ask first instead.",
|
|
13837
|
-
image: "Array of file ATTACHMENTS the user uploaded in the chat. Each item requires download_url and file_id, and may optionally include file_name and mime_type \u2014
|
|
13851
|
+
image: "Array of file ATTACHMENTS: files the user uploaded in the chat, or files you created in your own file sandbox. Each item requires download_url and file_id, and may optionally include file_name and mime_type \u2014 the platform resolves a file passed here into these fields automatically, so just include the files. For plain image URLs the user pasted, use imageUrls instead. ALWAYS pass ALL attachments together in a single call \u2014 NEVER call this tool once per image. Do NOT use together with imageBase64.",
|
|
13838
13852
|
imageUrls: "Array of publicly accessible image URLs (e.g. links the user pasted or URLs produced by other tools). Use this for plain URLs that are NOT chat attachments \u2014 no file_id is needed. ALWAYS pass ALL URLs together in a single call. Can be combined with image; do NOT use together with imageBase64.",
|
|
13839
13853
|
imageBase64: 'Base64-encoded image data. Use when the client can read a file and encode it as base64. May include a data URL prefix (e.g. "data:image/jpeg;base64,...") or be raw base64. Do NOT use together with image.',
|
|
13840
13854
|
mimeType: 'MIME type of the image (e.g. "image/jpeg", "image/png", "image/webp"). Required when imageBase64 does not include a data URL prefix.',
|
|
@@ -14238,7 +14252,17 @@ ${articleContent}${nextSteps}`;
|
|
|
14238
14252
|
}
|
|
14239
14253
|
|
|
14240
14254
|
// src/docs/start-deploy-website.ts
|
|
14241
|
-
var
|
|
14255
|
+
var START_DEPLOY_WEBSITE_PARAM_DESCRIPTIONS = {
|
|
14256
|
+
userRequest: "The user's request that led here, quoted if short, otherwise summarized in a sentence.",
|
|
14257
|
+
siteDescription: "What the site is: its purpose and who it is for. One or two sentences.",
|
|
14258
|
+
siteForm: "The form the site exists in right now (HTML/CSS/JS files, a static build, a zip, another builder's export, a design created in this conversation, or something else), roughly how many files, and whether it includes images.",
|
|
14259
|
+
siteFunctionality: "What the site must be able to do for its visitors beyond showing pages, if anything (for example selling, bookings or reservations, tickets, menus and orders, rentals, forms, memberships or paid plans, donations, a blog, or anything else the user expects to work), in your own words. If it is a plain static site with no such needs, say so.",
|
|
14260
|
+
agentIdentity: "Which agent or product you are and the harness you run in.",
|
|
14261
|
+
wixAccess: "How you can reach Wix from where you run: through this MCP only, or also from a shell whose network can reach wixapis.com; whether you can run the Wix CLI (npx @wix/cli) there and whether it is logged in; and which Wix identity you act with \u2014 the user's login through this MCP, a CLI login, or none."
|
|
14262
|
+
};
|
|
14263
|
+
var START_DEPLOY_WEBSITE_PARAMS = Object.keys(
|
|
14264
|
+
START_DEPLOY_WEBSITE_PARAM_DESCRIPTIONS
|
|
14265
|
+
);
|
|
14242
14266
|
var START_DEPLOY_WEBSITE_TOOL_NAME = "StartDeployWebsite";
|
|
14243
14267
|
var START_DEPLOY_WEBSITE_RECIPE_URL = "https://dev.wix.com/docs/api-reference/account-level/sites/skills/upload-a-website-or-html-files.md";
|
|
14244
14268
|
var DROP_PAGE_URL = "https://www.wix.com/headless/drop?utm_campaign=mcp";
|
|
@@ -14264,7 +14288,12 @@ function addStartDeployWebsiteTool(server, disableTools = [], toolDescriptions,
|
|
|
14264
14288
|
START_DEPLOY_WEBSITE_TOOL_NAME,
|
|
14265
14289
|
toolDescriptions?.[START_DEPLOY_WEBSITE_TOOL_NAME] ?? defaultToolDescriptions[START_DEPLOY_WEBSITE_TOOL_NAME],
|
|
14266
14290
|
{
|
|
14267
|
-
|
|
14291
|
+
userRequest: external_exports.string().min(1).describe(START_DEPLOY_WEBSITE_PARAM_DESCRIPTIONS.userRequest),
|
|
14292
|
+
siteDescription: external_exports.string().min(1).describe(START_DEPLOY_WEBSITE_PARAM_DESCRIPTIONS.siteDescription),
|
|
14293
|
+
siteForm: external_exports.string().min(1).describe(START_DEPLOY_WEBSITE_PARAM_DESCRIPTIONS.siteForm),
|
|
14294
|
+
siteFunctionality: external_exports.string().min(1).describe(START_DEPLOY_WEBSITE_PARAM_DESCRIPTIONS.siteFunctionality),
|
|
14295
|
+
agentIdentity: external_exports.string().min(1).describe(START_DEPLOY_WEBSITE_PARAM_DESCRIPTIONS.agentIdentity),
|
|
14296
|
+
wixAccess: external_exports.string().min(1).describe(START_DEPLOY_WEBSITE_PARAM_DESCRIPTIONS.wixAccess)
|
|
14268
14297
|
},
|
|
14269
14298
|
{ readOnlyHint: true, destructiveHint: false, openWorldHint: false },
|
|
14270
14299
|
async (_args, { httpClient }) => {
|
|
@@ -14478,7 +14507,7 @@ var addDocsTools = (server, allowedTools = [
|
|
|
14478
14507
|
const d = desc("SearchWixRESTDocumentation");
|
|
14479
14508
|
return {
|
|
14480
14509
|
searchTerm: external_exports.string().describe(d.searchTerm),
|
|
14481
|
-
maxResults: external_exports.number().describe(d.maxResults).min(1).max(
|
|
14510
|
+
maxResults: external_exports.number().describe(d.maxResults).min(1).max(17).optional().default(17),
|
|
14482
14511
|
reason: external_exports.string().describe(d.reason)
|
|
14483
14512
|
};
|
|
14484
14513
|
})(),
|
|
@@ -14493,9 +14522,12 @@ var addDocsTools = (server, allowedTools = [
|
|
|
14493
14522
|
toolParams: {
|
|
14494
14523
|
searchTerm
|
|
14495
14524
|
},
|
|
14496
|
-
maxResults: Math.max(1, Math.min(maxResults ??
|
|
14525
|
+
maxResults: Math.max(1, Math.min(maxResults ?? 17, 17)),
|
|
14497
14526
|
linesInEachResult: 30,
|
|
14498
|
-
usePlatformizedSearch
|
|
14527
|
+
usePlatformizedSearch,
|
|
14528
|
+
// Merge recipes/skills into the REST ranking — they live in a
|
|
14529
|
+
// separate corpus the REST document_type doesn't cover on its own.
|
|
14530
|
+
extraDocumentTypes: ["SKILLS"]
|
|
14499
14531
|
});
|
|
14500
14532
|
const grounding = result.includes(QUERY_CAPABILITY_MARKER) ? [
|
|
14501
14533
|
REST_SEARCH_API_GROUNDING_REMINDER,
|
|
@@ -14758,7 +14790,7 @@ var addDocsTools = (server, allowedTools = [
|
|
|
14758
14790
|
const d = desc("SearchWixHeadlessDocumentation");
|
|
14759
14791
|
return {
|
|
14760
14792
|
searchTerm: external_exports.string().describe(d.searchTerm),
|
|
14761
|
-
maxResults: external_exports.number().describe(d.maxResults).min(1).max(
|
|
14793
|
+
maxResults: external_exports.number().describe(d.maxResults).min(1).max(17).optional().default(17)
|
|
14762
14794
|
};
|
|
14763
14795
|
})(),
|
|
14764
14796
|
{ readOnlyHint: true, destructiveHint: false, openWorldHint: false },
|
|
@@ -14770,8 +14802,11 @@ var addDocsTools = (server, allowedTools = [
|
|
|
14770
14802
|
toolParams: {
|
|
14771
14803
|
searchTerm
|
|
14772
14804
|
},
|
|
14773
|
-
maxResults: Math.max(1, Math.min(maxResults ??
|
|
14774
|
-
usePlatformizedSearch
|
|
14805
|
+
maxResults: Math.max(1, Math.min(maxResults ?? 17, 17)),
|
|
14806
|
+
usePlatformizedSearch,
|
|
14807
|
+
// Merge recipes/skills into the headless ranking — same separate
|
|
14808
|
+
// corpus the WIX_HEADLESS document_type doesn't cover on its own.
|
|
14809
|
+
extraDocumentTypes: ["SKILLS"]
|
|
14775
14810
|
});
|
|
14776
14811
|
return {
|
|
14777
14812
|
content: [
|
|
@@ -16688,6 +16723,189 @@ ${text.slice(0, 2e3)}`
|
|
|
16688
16723
|
);
|
|
16689
16724
|
}
|
|
16690
16725
|
|
|
16726
|
+
// src/code-mode/attachments.ts
|
|
16727
|
+
var MAX_ATTACHMENTS_BYTES = 10 * 1024 * 1024;
|
|
16728
|
+
var MAX_REDIRECTS = 4;
|
|
16729
|
+
var OAI_USERCONTENT_HOST = /^[a-z0-9-]+\.oaiusercontent\.com$/;
|
|
16730
|
+
var OAI_BLOB_ACCOUNTS = new Set(
|
|
16731
|
+
[
|
|
16732
|
+
"australiaeast",
|
|
16733
|
+
"brazilsouth",
|
|
16734
|
+
"cacentral",
|
|
16735
|
+
"centralindia",
|
|
16736
|
+
"centralus",
|
|
16737
|
+
"centralusdr",
|
|
16738
|
+
"denmarkeast",
|
|
16739
|
+
"eastus",
|
|
16740
|
+
"eastus2",
|
|
16741
|
+
"indiasocentral",
|
|
16742
|
+
"italynorth",
|
|
16743
|
+
"japaneast",
|
|
16744
|
+
"koreacentral",
|
|
16745
|
+
"northcentralus",
|
|
16746
|
+
"northeu",
|
|
16747
|
+
"nznorth",
|
|
16748
|
+
"polandcentral",
|
|
16749
|
+
"seasia",
|
|
16750
|
+
"southcentralus",
|
|
16751
|
+
"southeastus3",
|
|
16752
|
+
"ukwest",
|
|
16753
|
+
"westcentralus",
|
|
16754
|
+
"westus",
|
|
16755
|
+
"westus2",
|
|
16756
|
+
"westus3"
|
|
16757
|
+
].map((region) => `oaisdmntpr${region}.blob.core.windows.net`)
|
|
16758
|
+
);
|
|
16759
|
+
function isAllowedAttachmentHost(hostname) {
|
|
16760
|
+
const h = hostname.toLowerCase();
|
|
16761
|
+
return OAI_USERCONTENT_HOST.test(h) || OAI_BLOB_ACCOUNTS.has(h);
|
|
16762
|
+
}
|
|
16763
|
+
function checkAttachmentUrl(url) {
|
|
16764
|
+
if (url.protocol !== "https:") return "is not an https URL";
|
|
16765
|
+
if (url.port) return "uses a non-default port";
|
|
16766
|
+
if (!isAllowedAttachmentHost(url.hostname)) {
|
|
16767
|
+
return `host "${url.hostname}" is not a ChatGPT file host`;
|
|
16768
|
+
}
|
|
16769
|
+
return void 0;
|
|
16770
|
+
}
|
|
16771
|
+
var AttachmentError = class extends Error {
|
|
16772
|
+
};
|
|
16773
|
+
function attachmentPath(a, url) {
|
|
16774
|
+
let fromUrl = "";
|
|
16775
|
+
try {
|
|
16776
|
+
fromUrl = decodeURIComponent(
|
|
16777
|
+
url.pathname.split("/").filter(Boolean).pop() ?? ""
|
|
16778
|
+
);
|
|
16779
|
+
} catch {
|
|
16780
|
+
fromUrl = "";
|
|
16781
|
+
}
|
|
16782
|
+
const raw = (a.file_name?.trim() || fromUrl || a.file_id).replace(/\\/g, "/");
|
|
16783
|
+
const segments = raw.split("/").filter((s) => s && s !== "." && s !== "..");
|
|
16784
|
+
return segments.join("/") || a.file_id;
|
|
16785
|
+
}
|
|
16786
|
+
function toBase64(bytes) {
|
|
16787
|
+
let binary = "";
|
|
16788
|
+
const chunk = 32768;
|
|
16789
|
+
for (let i = 0; i < bytes.length; i += chunk) {
|
|
16790
|
+
binary += String.fromCharCode(...bytes.subarray(i, i + chunk));
|
|
16791
|
+
}
|
|
16792
|
+
return btoa(binary);
|
|
16793
|
+
}
|
|
16794
|
+
async function fetchAllowed(start, fetchImpl, label) {
|
|
16795
|
+
let url = start;
|
|
16796
|
+
for (let hop = 0; ; hop++) {
|
|
16797
|
+
const res = await fetchImpl(url.toString(), { redirect: "manual" });
|
|
16798
|
+
const location = res.headers.get("location");
|
|
16799
|
+
const isRedirect = res.status >= 300 && res.status < 400 && location;
|
|
16800
|
+
if (!isRedirect) return res;
|
|
16801
|
+
await res.body?.cancel().catch(() => void 0);
|
|
16802
|
+
if (hop >= MAX_REDIRECTS) {
|
|
16803
|
+
throw new AttachmentError(`${label}: too many redirects.`);
|
|
16804
|
+
}
|
|
16805
|
+
let next;
|
|
16806
|
+
try {
|
|
16807
|
+
next = new URL(location, url);
|
|
16808
|
+
} catch {
|
|
16809
|
+
throw new AttachmentError(`${label}: redirect to an invalid URL.`);
|
|
16810
|
+
}
|
|
16811
|
+
const problem = checkAttachmentUrl(next);
|
|
16812
|
+
if (problem) {
|
|
16813
|
+
throw new AttachmentError(
|
|
16814
|
+
`${label}: the download redirected to a URL that ${problem}; refused.`
|
|
16815
|
+
);
|
|
16816
|
+
}
|
|
16817
|
+
url = next;
|
|
16818
|
+
}
|
|
16819
|
+
}
|
|
16820
|
+
async function readWithin(res, budget, overBudget) {
|
|
16821
|
+
const declared = Number(res.headers.get("content-length") ?? 0);
|
|
16822
|
+
if (declared > budget) throw overBudget();
|
|
16823
|
+
if (!res.body) {
|
|
16824
|
+
const bytes = new Uint8Array(await res.arrayBuffer());
|
|
16825
|
+
if (bytes.byteLength > budget) throw overBudget();
|
|
16826
|
+
return bytes;
|
|
16827
|
+
}
|
|
16828
|
+
const reader = res.body.getReader();
|
|
16829
|
+
const chunks = [];
|
|
16830
|
+
let total = 0;
|
|
16831
|
+
for (; ; ) {
|
|
16832
|
+
const { done, value } = await reader.read();
|
|
16833
|
+
if (done) break;
|
|
16834
|
+
total += value.byteLength;
|
|
16835
|
+
if (total > budget) {
|
|
16836
|
+
await reader.cancel().catch(() => void 0);
|
|
16837
|
+
throw overBudget();
|
|
16838
|
+
}
|
|
16839
|
+
chunks.push(value);
|
|
16840
|
+
}
|
|
16841
|
+
const out = new Uint8Array(total);
|
|
16842
|
+
let offset = 0;
|
|
16843
|
+
for (const c of chunks) {
|
|
16844
|
+
out.set(c, offset);
|
|
16845
|
+
offset += c.byteLength;
|
|
16846
|
+
}
|
|
16847
|
+
return out;
|
|
16848
|
+
}
|
|
16849
|
+
async function resolveAttachments(attachments, fetchImpl = fetch) {
|
|
16850
|
+
if (!Array.isArray(attachments) || attachments.length === 0) return [];
|
|
16851
|
+
const items = [];
|
|
16852
|
+
attachments.forEach((raw, i) => {
|
|
16853
|
+
const a = typeof raw === "object" && raw;
|
|
16854
|
+
const downloadUrl = a && typeof a.download_url === "string" ? a.download_url : "";
|
|
16855
|
+
let url;
|
|
16856
|
+
try {
|
|
16857
|
+
url = /^https?:\/\//i.test(downloadUrl) ? new URL(downloadUrl) : void 0;
|
|
16858
|
+
} catch {
|
|
16859
|
+
url = void 0;
|
|
16860
|
+
}
|
|
16861
|
+
if (!a || !url) {
|
|
16862
|
+
throw new AttachmentError(
|
|
16863
|
+
`attachments[${i}] was not resolved to a download URL (got ${JSON.stringify(
|
|
16864
|
+
typeof raw === "string" ? raw : (a && a.download_url) ?? raw
|
|
16865
|
+
)}). The platform did not hydrate this attachment; retry once, and if it still arrives like this put the file in the \`files\` bundle instead (\`=== FILE: <path> base64 ===\` for binary).`
|
|
16866
|
+
);
|
|
16867
|
+
}
|
|
16868
|
+
const problem = checkAttachmentUrl(url);
|
|
16869
|
+
if (problem) {
|
|
16870
|
+
throw new AttachmentError(
|
|
16871
|
+
`attachments[${i}].download_url ${problem}. Only platform-resolved attachments are accepted here; for any other URL fetch it in \`code\` via wix.request or put the bytes in the \`files\` bundle.`
|
|
16872
|
+
);
|
|
16873
|
+
}
|
|
16874
|
+
items.push({ a, url });
|
|
16875
|
+
});
|
|
16876
|
+
let remaining = MAX_ATTACHMENTS_BYTES;
|
|
16877
|
+
const out = [];
|
|
16878
|
+
for (const [i, { a, url }] of items.entries()) {
|
|
16879
|
+
const path = attachmentPath(a, url);
|
|
16880
|
+
const label = `attachments[${i}] (${path})`;
|
|
16881
|
+
let res;
|
|
16882
|
+
try {
|
|
16883
|
+
res = await fetchAllowed(url, fetchImpl, label);
|
|
16884
|
+
} catch (e) {
|
|
16885
|
+
if (e instanceof AttachmentError) throw e;
|
|
16886
|
+
throw new AttachmentError(
|
|
16887
|
+
`${label}: download failed (${e.message}).`
|
|
16888
|
+
);
|
|
16889
|
+
}
|
|
16890
|
+
if (!res.ok) {
|
|
16891
|
+
await res.body?.cancel().catch(() => void 0);
|
|
16892
|
+
throw new AttachmentError(
|
|
16893
|
+
`${label}: download returned HTTP ${res.status}. The download_url may have expired; attach the file again.`
|
|
16894
|
+
);
|
|
16895
|
+
}
|
|
16896
|
+
const bytes = await readWithin(
|
|
16897
|
+
res,
|
|
16898
|
+
remaining,
|
|
16899
|
+
() => new AttachmentError(
|
|
16900
|
+
`${label} pushes the attachments past ${MAX_ATTACHMENTS_BYTES} bytes in total for this call; split the upload across calls.`
|
|
16901
|
+
)
|
|
16902
|
+
);
|
|
16903
|
+
remaining -= bytes.byteLength;
|
|
16904
|
+
out.push({ path, content: toBase64(bytes), encoding: "base64" });
|
|
16905
|
+
}
|
|
16906
|
+
return out;
|
|
16907
|
+
}
|
|
16908
|
+
|
|
16691
16909
|
// src/code-mode/validation.ts
|
|
16692
16910
|
var EXECUTE_FUNCTION_EXPRESSION_HINT = 'ExecuteWixAPI code must be a function expression, not a script body. Pass code like: async () => { const response = await wix.request({ scope: "site", method: "GET", url: "https://www.wixapis.com/..." }); return response.data; }. Do not write top-level const/await/return outside the function and do not invoke the function yourself.';
|
|
16693
16911
|
function validateExecuteCode(code) {
|
|
@@ -16899,7 +17117,7 @@ function addExecuteTool(server, options) {
|
|
|
16899
17117
|
} = options;
|
|
16900
17118
|
const executeUrl = `${codeModeBaseUrl}/api/code-mode/execute`;
|
|
16901
17119
|
const d = desc("ExecuteWixAPI");
|
|
16902
|
-
server.tool(
|
|
17120
|
+
const registered = server.tool(
|
|
16903
17121
|
EXECUTE_TOOL_NAME,
|
|
16904
17122
|
toolDescriptions?.[EXECUTE_TOOL_NAME] ?? defaultToolDescriptions.ExecuteWixAPI,
|
|
16905
17123
|
{
|
|
@@ -16928,6 +17146,20 @@ function addExecuteTool(server, options) {
|
|
|
16928
17146
|
'Use base64 entries for small assets (icons, logos, fonts) and for files you downloaded and are re-uploading; large images/video go in by URL (`<img src="https://...">`), not in the bundle. A file containing a line exactly like the delimiter is not supported.'
|
|
16929
17147
|
].join(" ")
|
|
16930
17148
|
),
|
|
17149
|
+
// ChatGPT file attachments (`openai/fileParams`). Item shape must match
|
|
17150
|
+
// OpenAI's file schema: download_url + file_id required, the rest optional.
|
|
17151
|
+
// Declaring it is what makes the platform hand us a download URL instead
|
|
17152
|
+
// of a sandbox path. Resolved host-side into base64 `files` entries.
|
|
17153
|
+
attachments: external_exports.array(
|
|
17154
|
+
external_exports.object({
|
|
17155
|
+
download_url: external_exports.string(),
|
|
17156
|
+
file_id: external_exports.string(),
|
|
17157
|
+
file_name: external_exports.string().optional(),
|
|
17158
|
+
mime_type: external_exports.string().optional()
|
|
17159
|
+
})
|
|
17160
|
+
).optional().describe(
|
|
17161
|
+
'Files attached in this chat, or files you created in your own file sandbox (any type: a zip of a site, HTML, images, PDFs). Pass the files themselves and the platform resolves each into { download_url, file_id, file_name?, mime_type? }; the bytes are fetched here and appended to the `files` global as { path, content, encoding: "base64" } entries (path = file_name), so `wix.multipart()` and `wix.unzip()` work on them unchanged. Prefer this over base64 in `files` whenever you have a file handle. Up to 10 MB per call.'
|
|
17162
|
+
),
|
|
16931
17163
|
// Visitor mode takes an agent-supplied token and pins the site; account/site
|
|
16932
17164
|
// mode lets the agent pick the site.
|
|
16933
17165
|
...visitor ? {
|
|
@@ -16942,7 +17174,15 @@ function addExecuteTool(server, options) {
|
|
|
16942
17174
|
},
|
|
16943
17175
|
{ readOnlyHint: false, destructiveHint: true, openWorldHint: false },
|
|
16944
17176
|
async (rawArgs, extra) => {
|
|
16945
|
-
const {
|
|
17177
|
+
const {
|
|
17178
|
+
code,
|
|
17179
|
+
reason,
|
|
17180
|
+
hasMutations,
|
|
17181
|
+
sourceDocUrls,
|
|
17182
|
+
visitorToken,
|
|
17183
|
+
files,
|
|
17184
|
+
attachments
|
|
17185
|
+
} = rawArgs;
|
|
16946
17186
|
const siteId = visitor ? visitor.siteId : rawArgs.siteId;
|
|
16947
17187
|
logger.log(
|
|
16948
17188
|
`[ExecuteWixAPI]${visitor ? " (visitor)" : ""} Executing code (${code.length} chars), siteId=${siteId ?? "none"}, hasMutations=${hasMutations}, sourceDocUrls=${JSON.stringify(sourceDocUrls)}, reason="${reason}"`
|
|
@@ -16954,6 +17194,13 @@ function addExecuteTool(server, options) {
|
|
|
16954
17194
|
);
|
|
16955
17195
|
return executeTextResult(validation.error);
|
|
16956
17196
|
}
|
|
17197
|
+
let attachmentFiles = [];
|
|
17198
|
+
try {
|
|
17199
|
+
attachmentFiles = await resolveAttachments(attachments);
|
|
17200
|
+
} catch (e) {
|
|
17201
|
+
if (e instanceof AttachmentError) return executeErrorResult(e.message);
|
|
17202
|
+
throw e;
|
|
17203
|
+
}
|
|
16957
17204
|
const accountHeaders = await authStrategy?.getAccountAuthHeaders();
|
|
16958
17205
|
const siteAuthContext = !visitor && authStrategy?.getSiteAuthContext ? await authStrategy.getSiteAuthContext() : void 0;
|
|
16959
17206
|
let siteHeaders;
|
|
@@ -16988,7 +17235,8 @@ function addExecuteTool(server, options) {
|
|
|
16988
17235
|
accountToken: visitor ? visitorToken : accountHeaders?.Authorization,
|
|
16989
17236
|
accountId: accountHeaders?.["wix-account-id"],
|
|
16990
17237
|
siteAuthContext,
|
|
16991
|
-
...files ? { files } : {}
|
|
17238
|
+
...files ? { files } : {},
|
|
17239
|
+
...attachmentFiles.length ? { attachmentFiles } : {}
|
|
16992
17240
|
},
|
|
16993
17241
|
visitor ? visitorToken : accountHeaders?.Authorization ?? siteHeaders?.Authorization,
|
|
16994
17242
|
codeModeFetch
|
|
@@ -17019,6 +17267,9 @@ function addExecuteTool(server, options) {
|
|
|
17019
17267
|
}
|
|
17020
17268
|
}
|
|
17021
17269
|
);
|
|
17270
|
+
registered?.update?.({
|
|
17271
|
+
_meta: { ...registered._meta, "openai/fileParams": ["attachments"] }
|
|
17272
|
+
});
|
|
17022
17273
|
}
|
|
17023
17274
|
|
|
17024
17275
|
// ../../node_modules/@wix/panorama-common-shared/dist/esm/types/enum-types.js
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.93",
|
|
4
4
|
"description": "A Model Context Protocol server for Wix AI tools",
|
|
5
5
|
"bin": "./build/bin-standalone.js",
|
|
6
6
|
"dependencies": {
|
|
@@ -133,5 +133,5 @@
|
|
|
133
133
|
]
|
|
134
134
|
}
|
|
135
135
|
},
|
|
136
|
-
"falconPackageHash": "
|
|
136
|
+
"falconPackageHash": "416cbd091ed4f59d7a920a4a98434246c6a211bf9c981dd78ad9a627"
|
|
137
137
|
}
|