@wix/mcp 1.0.86 → 1.0.87

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.
@@ -71552,6 +71552,7 @@ function rethrowIfUnauthorized(error2) {
71552
71552
 
71553
71553
  // src/config/api-request-rules.ts
71554
71554
  var ARRAY_QUERY_PARAMS_RULE = "Repeat array query params once per value: `?fieldsets=URL&fieldsets=RICH_CONTENT`. Do NOT comma-join values (`fieldsets=URL,RICH_CONTENT`), do NOT leave a trailing comma, and do NOT use a value the method schema does not list, even if a sibling method accepts it (draft posts have no `SEO` fieldset).";
71555
+ var WQL_FILTER_RULE = "Query and search filters are written in WQL: each field takes a single operator, so combine conditions with the logical operators \u2014 `$and` and `$or` take an array of expressions, `$not` takes one, and they can nest.";
71555
71556
 
71556
71557
  // src/config/default-config.ts
71557
71558
  var AGENT_GOAL = dedent_default`
@@ -71652,7 +71653,7 @@ var SITE_CREATION_COPY = {
71652
71653
  var SITE_GUIDANCE = dedent_default`
71653
71654
  A new-site request has 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.
71654
71655
 
71655
- One case skips all of this: the user ALREADY HAS the finished site as files — hand-written HTML/CSS/JS, a zip, or the export of an AI builder. There is nothing to build, so don't offer AI or templates and don't call any site-creation tool. Send them to https://www.wix.com/headless/drop?utm_campaign=mcp — they drag the files in and get a live Wix-hosted site. Give that URL exactly as written, keeping the utm_campaign=mcp parameter.
71656
+ One case skips all of this: the user ALREADY HAS the finished site as files — hand-written HTML/CSS/JS, a zip, or the export of an AI builder. There is nothing to build, so don't offer AI or templates and don't call any site-creation tool. For a full agentic flow, read the recipe first and publish the files yourself: https://dev.wix.com/docs/api-reference/account-level/sites/skills/upload-a-website-or-html-files.md — it walks you through creating the site and uploading the files end to end. If you can't follow it, or it doesn't apply (you can't reach the file bytes, or something fails), fall back to sending the user to https://www.wix.com/headless/drop?utm_campaign=mcp — they drag the files in and get a live Wix-hosted site. Give that URL exactly as written, keeping the utm_campaign=mcp parameter.
71656
71657
 
71657
71658
  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.
71658
71659
  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.
@@ -71711,12 +71712,25 @@ var ACCOUNT_SITE_EXECUTE_SCOPE = dedent_default`
71711
71712
  siteId?: string;
71712
71713
  method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
71713
71714
  url: string;
71715
+ // Plain object → JSON. A string is sent verbatim (set your own Content-Type,
71716
+ // e.g. multipart/form-data). A Uint8Array/ArrayBuffer is sent as raw bytes
71717
+ // for binary uploads (set your own Content-Type).
71714
71718
  body?: unknown;
71715
71719
  headers?: Record<string, string>;
71720
+ // "base64" returns the response body as a base64 string (data), with
71721
+ // encoding: "base64" on the result — use it for binary downloads (zip,
71722
+ // image, pdf); decoding those as text corrupts them. Binary content types
71723
+ // are returned as base64 automatically even without this. Decode, edit and
71724
+ // re-upload binary WITHIN this script and return only a small summary. If you
71725
+ // must return the bytes, return the wix.request response object itself (so
71726
+ // encoding: "base64" is preserved and it isn't truncated); a bare base64
71727
+ // string you return is treated as plain text and may be truncated.
71728
+ responseType?: "base64";
71716
71729
  }
71717
71730
  interface WixResponse<T = unknown> {
71718
71731
  status: number;
71719
71732
  data: T;
71733
+ encoding?: "base64";
71720
71734
  json(): Promise<T>;
71721
71735
  }
71722
71736
  declare const wix: {
@@ -71855,6 +71869,7 @@ function buildToolDescriptions(includeReadme, includeImageUploadGuidance = true)
71855
71869
  ReadFullDocsArticle: dedent_default`
71856
71870
  Fetches the full Wix docs article or method article with code examples for using the method.
71857
71871
  Docs articles looks like this: https://dev.wix.com/docs/... and they can either be general docs articles or method articles.
71872
+ Take the URL from the user's message or an earlier tool result. To reach an article you have no URL for, search or browse the docs first.
71858
71873
  For REST docs, use the URL as-is. For SDK docs, the URL SHOULD include ?apiView=SDK.
71859
71874
  ${reminder}
71860
71875
  `,
@@ -71987,7 +72002,7 @@ function buildToolDescriptions(includeReadme, includeImageUploadGuidance = true)
71987
72002
  `,
71988
72003
  "import-claude-design-from-url": dedent_default`
71989
72004
  Import a design created in Claude's design tool into Wix. Takes the signed claudeusercontent.com URL Claude Design produces for its self-contained HTML bundle (all images, fonts, and styles inlined); any other host is rejected. Creates a live Wix-hosted site and returns its URL.
71990
- NOT for site files the user provides themselves (their own HTML/CSS/JS, a zip, another builder's export) — for those, don't call this tool: send the user to https://www.wix.com/headless/drop?utm_campaign=mcp, where they upload the files and get a live hosted site. Give that URL exactly as written, keeping the utm_campaign=mcp parameter.
72005
+ NOT for site files the user provides themselves (their own HTML/CSS/JS, a zip, another builder's export) — for those, don't call this tool. For a full agentic flow, read the recipe and publish the files yourself: https://dev.wix.com/docs/api-reference/account-level/sites/skills/upload-a-website-or-html-files.md — it covers creating the site and uploading the files end to end. If you can't follow it, or it doesn't apply, fall back to sending the user to https://www.wix.com/headless/drop?utm_campaign=mcp, where they upload the files and get a live hosted site. Give that URL exactly as written, keeping the utm_campaign=mcp parameter.
71991
72006
  `,
71992
72007
  RunWixCliCommand: dedent_default`
71993
72008
  Executes Wix CLI commands for Wix app development and management.
@@ -72414,7 +72429,7 @@ function buildToolDescriptions(includeReadme, includeImageUploadGuidance = true)
72414
72429
  CreateWixBusinessGuide: dedent_default`
72415
72430
  Provides comprehensive documentation for creating a new Wix business (site, app, etc.).
72416
72431
  Call this ONLY when the user explicitly asks for a headless site, a Wix Classic Editor site, or manual/advanced account/API-based site creation — these don't need the site's purpose first. For normal site-creation ${SITE_CREATION_COPY.normalCreationRoute.nonWidget}; for a specific template id, call \`CreateSiteFromTemplate\`.
72417
- Exception, even when the user says "headless": if they ALREADY HAVE the finished site as files (their own HTML/CSS/JS, a zip, an AI-builder export) and want those files hosted, don't call this tool — send them to https://www.wix.com/headless/drop?utm_campaign=mcp to upload the files and get a live hosted site (give that URL exactly, keeping the utm_campaign=mcp parameter). This guide's CLI flow is for BUILDING a headless frontend, not for hosting ready-made files.
72432
+ Exception, even when the user says "headless": if they ALREADY HAVE the finished site as files (their own HTML/CSS/JS, a zip, an AI-builder export) and want those files hosted, don't call this tool. For a full agentic flow, read the recipe and publish the files yourself: https://dev.wix.com/docs/api-reference/account-level/sites/skills/upload-a-website-or-html-files.md — it covers creating the site and uploading the files end to end. If you can't follow it, or it doesn't apply, fall back to sending the user to https://www.wix.com/headless/drop?utm_campaign=mcp to upload the files and get a live hosted site (give that URL exactly, keeping the utm_campaign=mcp parameter). This guide's CLI flow is for BUILDING a headless frontend, not for hosting ready-made files.
72418
72433
 
72419
72434
  ## What This Tool Contains
72420
72435
 
@@ -73013,7 +73028,10 @@ var paramDescriptions = {
73013
73028
  ARRAY_QUERY_PARAMS_RULE
73014
73029
  ].join("\n"),
73015
73030
  method: "The HTTP method to use for the API call (e.g. GET, POST, PUT, DELETE)",
73016
- body: 'The request body as a JSON object or array with all the required fields and values, including nested objects. Pass the actual value (object or array), NOT a JSON string. YOU MUST NEVER MAKE UP A BODY - the body should be based on the conversation context, i.e from the user prompt OR got into the conversation context by the "ReadFullDocsArticle" tool OR by the "SearchWixAPISpec" tool OR by the "ReadFullDocsMethodSchema" tool - i.e based on the API docs, a relevant recipe you read (preferably), a code example you found in the docs, a schema you read etc.. YOU MUST NEVER ASSUME YOU KNOW WHAT THE BODY SCHEMA IS WITHOUT CONCRETE EXAMPLES OR SCHEMA DEFINITIONS FROM THE CONVERSATION CONTEXT. Prefer reading relevant recipes if you have them in context for understand the body schema for API calls.',
73031
+ body: [
73032
+ 'The request body as a JSON object or array with all the required fields and values, including nested objects. Pass the actual value (object or array), NOT a JSON string. YOU MUST NEVER MAKE UP A BODY - the body should be based on the conversation context, i.e from the user prompt OR got into the conversation context by the "ReadFullDocsArticle" tool OR by the "SearchWixAPISpec" tool OR by the "ReadFullDocsMethodSchema" tool - i.e based on the API docs, a relevant recipe you read (preferably), a code example you found in the docs, a schema you read etc.. YOU MUST NEVER ASSUME YOU KNOW WHAT THE BODY SCHEMA IS WITHOUT CONCRETE EXAMPLES OR SCHEMA DEFINITIONS FROM THE CONVERSATION CONTEXT. Prefer reading relevant recipes if you have them in context for understand the body schema for API calls.',
73033
+ WQL_FILTER_RULE
73034
+ ].join("\n"),
73017
73035
  reason: "One sentence explaining the original user request and why you are calling this API to complete it.",
73018
73036
  sourceDocUrl: [
73019
73037
  "The URL of the documentation or recipe where you found this API endpoint.",
@@ -73337,15 +73355,17 @@ Failed to fetch content: ${errorMsg}`
73337
73355
  const baseContentsPromise = Promise.all(
73338
73356
  baseDocsWithoutRecipes.map(fetchDoc)
73339
73357
  );
73340
- const skillsContentPromise = getSkillsByPortal(httpClient, {
73358
+ const skillsContentPromise = skillsTags?.length ? getSkillsByPortal(httpClient, {
73341
73359
  portalId: REST_PORTAL_ID,
73342
73360
  ...repo && { repo },
73343
73361
  ...commitHash && { commitHash },
73344
- ...skillsTags && skillsTags.length > 0 && { tags: skillsTags }
73362
+ tags: skillsTags
73345
73363
  }).catch((err) => {
73346
73364
  console.error("[WixREADME] Failed to fetch skills by portal:", err);
73347
73365
  return null;
73348
- });
73366
+ }) : fetchDoc({ action: "include", url: RECIPES_INDEX_URL }).then(
73367
+ (doc) => doc?.text ?? null
73368
+ );
73349
73369
  const filter = {};
73350
73370
  if (siteId) filter.siteId = siteId;
73351
73371
  else if (siteName) filter.siteName = siteName;
@@ -85253,6 +85273,14 @@ var EMPTY_COMPLETION_RESULT = {
85253
85273
 
85254
85274
  // src/tool-utils.ts
85255
85275
  var REST_METHOD_CONTRACT_RETRY_HINT = "Before retrying, make sure you have everything needed for a correct call: the right endpoint URL, HTTP method, request body shape, and response shape. Use the SearchWixRESTDocumentation tool or BrowseWixRESTDocsMenu tool to find the correct method or relevant related articles, the ReadFullDocsArticle tool to read the method description and all code examples, and the SearchWixAPISpec tool for precise field names and schema details.";
85276
+ var SINGLE_OPERATOR_PER_FIELD_HINT = 'WQL takes one operator per field object. Split the conditions into separate expressions under the matching logical operator \u2014 `{"$and": [{"field": {"$gte": ...}}, {"field": {"$lte": ...}}]}` \u2014 and retry without re-searching the docs.';
85277
+ var FIELD_CAPABILITIES_HINT = "This endpoint declares its filterable and sortable fields with their operators. Read the map with SearchWixAPISpec (`queryMethodData.queryFieldsCapabilitiesMap`, or `searchMethodData.searchFieldsCapabilitiesMap` on search methods) and use only what it lists; otherwise fetch a bounded page and filter or sort the results yourself.";
85278
+ var getRetryHint = (errorDetails) => {
85279
+ if (!/Filter contains unsupported operator/i.test(errorDetails)) {
85280
+ return REST_METHOD_CONTRACT_RETRY_HINT;
85281
+ }
85282
+ return /"operator":"\{/.test(errorDetails) ? SINGLE_OPERATOR_PER_FIELD_HINT : FIELD_CAPABILITIES_HINT;
85283
+ };
85256
85284
  var DEFAULT_OPENAI_SECURITY_SCHEMES = [
85257
85285
  { type: "oauth2", scopes: ["offline_access"] }
85258
85286
  ];
@@ -85279,7 +85307,7 @@ var buildErrorMessage = ({
85279
85307
  ].filter((str) => !!str).join("\n");
85280
85308
  return `${baseMessage}
85281
85309
 
85282
- ${REST_METHOD_CONTRACT_RETRY_HINT}`;
85310
+ ${getRetryHint(String(errorDetails))}`;
85283
85311
  };
85284
85312
  var handleWixAPIResponse = async (response) => {
85285
85313
  const requestId = response.headers?.["x-wix-request-id"];
@@ -35867,6 +35867,14 @@ var EMPTY_COMPLETION_RESULT = {
35867
35867
 
35868
35868
  // src/tool-utils.ts
35869
35869
  var REST_METHOD_CONTRACT_RETRY_HINT = "Before retrying, make sure you have everything needed for a correct call: the right endpoint URL, HTTP method, request body shape, and response shape. Use the SearchWixRESTDocumentation tool or BrowseWixRESTDocsMenu tool to find the correct method or relevant related articles, the ReadFullDocsArticle tool to read the method description and all code examples, and the SearchWixAPISpec tool for precise field names and schema details.";
35870
+ var SINGLE_OPERATOR_PER_FIELD_HINT = 'WQL takes one operator per field object. Split the conditions into separate expressions under the matching logical operator \u2014 `{"$and": [{"field": {"$gte": ...}}, {"field": {"$lte": ...}}]}` \u2014 and retry without re-searching the docs.';
35871
+ var FIELD_CAPABILITIES_HINT = "This endpoint declares its filterable and sortable fields with their operators. Read the map with SearchWixAPISpec (`queryMethodData.queryFieldsCapabilitiesMap`, or `searchMethodData.searchFieldsCapabilitiesMap` on search methods) and use only what it lists; otherwise fetch a bounded page and filter or sort the results yourself.";
35872
+ var getRetryHint = (errorDetails) => {
35873
+ if (!/Filter contains unsupported operator/i.test(errorDetails)) {
35874
+ return REST_METHOD_CONTRACT_RETRY_HINT;
35875
+ }
35876
+ return /"operator":"\{/.test(errorDetails) ? SINGLE_OPERATOR_PER_FIELD_HINT : FIELD_CAPABILITIES_HINT;
35877
+ };
35870
35878
  var DEFAULT_OPENAI_SECURITY_SCHEMES = [
35871
35879
  { type: "oauth2", scopes: ["offline_access"] }
35872
35880
  ];
@@ -35893,7 +35901,7 @@ var buildErrorMessage = ({
35893
35901
  ].filter((str) => !!str).join("\n");
35894
35902
  return `${baseMessage}
35895
35903
 
35896
- ${REST_METHOD_CONTRACT_RETRY_HINT}`;
35904
+ ${getRetryHint(String(errorDetails))}`;
35897
35905
  };
35898
35906
  var handleWixAPIResponse = async (response) => {
35899
35907
  const requestId = response.headers?.["x-wix-request-id"];
@@ -37160,6 +37168,7 @@ function rethrowIfUnauthorized(error2) {
37160
37168
 
37161
37169
  // src/config/api-request-rules.ts
37162
37170
  var ARRAY_QUERY_PARAMS_RULE = "Repeat array query params once per value: `?fieldsets=URL&fieldsets=RICH_CONTENT`. Do NOT comma-join values (`fieldsets=URL,RICH_CONTENT`), do NOT leave a trailing comma, and do NOT use a value the method schema does not list, even if a sibling method accepts it (draft posts have no `SEO` fieldset).";
37171
+ var WQL_FILTER_RULE = "Query and search filters are written in WQL: each field takes a single operator, so combine conditions with the logical operators \u2014 `$and` and `$or` take an array of expressions, `$not` takes one, and they can nest.";
37163
37172
 
37164
37173
  // src/config/default-config.ts
37165
37174
  var AGENT_GOAL = dedent_default`
@@ -37260,7 +37269,7 @@ var SITE_CREATION_COPY = {
37260
37269
  var SITE_GUIDANCE = dedent_default`
37261
37270
  A new-site request has 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.
37262
37271
 
37263
- One case skips all of this: the user ALREADY HAS the finished site as files — hand-written HTML/CSS/JS, a zip, or the export of an AI builder. There is nothing to build, so don't offer AI or templates and don't call any site-creation tool. Send them to https://www.wix.com/headless/drop?utm_campaign=mcp — they drag the files in and get a live Wix-hosted site. Give that URL exactly as written, keeping the utm_campaign=mcp parameter.
37272
+ One case skips all of this: the user ALREADY HAS the finished site as files — hand-written HTML/CSS/JS, a zip, or the export of an AI builder. There is nothing to build, so don't offer AI or templates and don't call any site-creation tool. For a full agentic flow, read the recipe first and publish the files yourself: https://dev.wix.com/docs/api-reference/account-level/sites/skills/upload-a-website-or-html-files.md — it walks you through creating the site and uploading the files end to end. If you can't follow it, or it doesn't apply (you can't reach the file bytes, or something fails), fall back to sending the user to https://www.wix.com/headless/drop?utm_campaign=mcp — they drag the files in and get a live Wix-hosted site. Give that URL exactly as written, keeping the utm_campaign=mcp parameter.
37264
37273
 
37265
37274
  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.
37266
37275
  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.
@@ -37319,12 +37328,25 @@ var ACCOUNT_SITE_EXECUTE_SCOPE = dedent_default`
37319
37328
  siteId?: string;
37320
37329
  method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
37321
37330
  url: string;
37331
+ // Plain object → JSON. A string is sent verbatim (set your own Content-Type,
37332
+ // e.g. multipart/form-data). A Uint8Array/ArrayBuffer is sent as raw bytes
37333
+ // for binary uploads (set your own Content-Type).
37322
37334
  body?: unknown;
37323
37335
  headers?: Record<string, string>;
37336
+ // "base64" returns the response body as a base64 string (data), with
37337
+ // encoding: "base64" on the result — use it for binary downloads (zip,
37338
+ // image, pdf); decoding those as text corrupts them. Binary content types
37339
+ // are returned as base64 automatically even without this. Decode, edit and
37340
+ // re-upload binary WITHIN this script and return only a small summary. If you
37341
+ // must return the bytes, return the wix.request response object itself (so
37342
+ // encoding: "base64" is preserved and it isn't truncated); a bare base64
37343
+ // string you return is treated as plain text and may be truncated.
37344
+ responseType?: "base64";
37324
37345
  }
37325
37346
  interface WixResponse<T = unknown> {
37326
37347
  status: number;
37327
37348
  data: T;
37349
+ encoding?: "base64";
37328
37350
  json(): Promise<T>;
37329
37351
  }
37330
37352
  declare const wix: {
@@ -37463,6 +37485,7 @@ function buildToolDescriptions(includeReadme, includeImageUploadGuidance = true)
37463
37485
  ReadFullDocsArticle: dedent_default`
37464
37486
  Fetches the full Wix docs article or method article with code examples for using the method.
37465
37487
  Docs articles looks like this: https://dev.wix.com/docs/... and they can either be general docs articles or method articles.
37488
+ Take the URL from the user's message or an earlier tool result. To reach an article you have no URL for, search or browse the docs first.
37466
37489
  For REST docs, use the URL as-is. For SDK docs, the URL SHOULD include ?apiView=SDK.
37467
37490
  ${reminder}
37468
37491
  `,
@@ -37595,7 +37618,7 @@ function buildToolDescriptions(includeReadme, includeImageUploadGuidance = true)
37595
37618
  `,
37596
37619
  "import-claude-design-from-url": dedent_default`
37597
37620
  Import a design created in Claude's design tool into Wix. Takes the signed claudeusercontent.com URL Claude Design produces for its self-contained HTML bundle (all images, fonts, and styles inlined); any other host is rejected. Creates a live Wix-hosted site and returns its URL.
37598
- NOT for site files the user provides themselves (their own HTML/CSS/JS, a zip, another builder's export) — for those, don't call this tool: send the user to https://www.wix.com/headless/drop?utm_campaign=mcp, where they upload the files and get a live hosted site. Give that URL exactly as written, keeping the utm_campaign=mcp parameter.
37621
+ NOT for site files the user provides themselves (their own HTML/CSS/JS, a zip, another builder's export) — for those, don't call this tool. For a full agentic flow, read the recipe and publish the files yourself: https://dev.wix.com/docs/api-reference/account-level/sites/skills/upload-a-website-or-html-files.md — it covers creating the site and uploading the files end to end. If you can't follow it, or it doesn't apply, fall back to sending the user to https://www.wix.com/headless/drop?utm_campaign=mcp, where they upload the files and get a live hosted site. Give that URL exactly as written, keeping the utm_campaign=mcp parameter.
37599
37622
  `,
37600
37623
  RunWixCliCommand: dedent_default`
37601
37624
  Executes Wix CLI commands for Wix app development and management.
@@ -38022,7 +38045,7 @@ function buildToolDescriptions(includeReadme, includeImageUploadGuidance = true)
38022
38045
  CreateWixBusinessGuide: dedent_default`
38023
38046
  Provides comprehensive documentation for creating a new Wix business (site, app, etc.).
38024
38047
  Call this ONLY when the user explicitly asks for a headless site, a Wix Classic Editor site, or manual/advanced account/API-based site creation — these don't need the site's purpose first. For normal site-creation ${SITE_CREATION_COPY.normalCreationRoute.nonWidget}; for a specific template id, call \`CreateSiteFromTemplate\`.
38025
- Exception, even when the user says "headless": if they ALREADY HAVE the finished site as files (their own HTML/CSS/JS, a zip, an AI-builder export) and want those files hosted, don't call this tool — send them to https://www.wix.com/headless/drop?utm_campaign=mcp to upload the files and get a live hosted site (give that URL exactly, keeping the utm_campaign=mcp parameter). This guide's CLI flow is for BUILDING a headless frontend, not for hosting ready-made files.
38048
+ Exception, even when the user says "headless": if they ALREADY HAVE the finished site as files (their own HTML/CSS/JS, a zip, an AI-builder export) and want those files hosted, don't call this tool. For a full agentic flow, read the recipe and publish the files yourself: https://dev.wix.com/docs/api-reference/account-level/sites/skills/upload-a-website-or-html-files.md — it covers creating the site and uploading the files end to end. If you can't follow it, or it doesn't apply, fall back to sending the user to https://www.wix.com/headless/drop?utm_campaign=mcp to upload the files and get a live hosted site (give that URL exactly, keeping the utm_campaign=mcp parameter). This guide's CLI flow is for BUILDING a headless frontend, not for hosting ready-made files.
38026
38049
 
38027
38050
  ## What This Tool Contains
38028
38051
 
@@ -38659,7 +38682,10 @@ var paramDescriptions = {
38659
38682
  ARRAY_QUERY_PARAMS_RULE
38660
38683
  ].join("\n"),
38661
38684
  method: "The HTTP method to use for the API call (e.g. GET, POST, PUT, DELETE)",
38662
- body: 'The request body as a JSON object or array with all the required fields and values, including nested objects. Pass the actual value (object or array), NOT a JSON string. YOU MUST NEVER MAKE UP A BODY - the body should be based on the conversation context, i.e from the user prompt OR got into the conversation context by the "ReadFullDocsArticle" tool OR by the "SearchWixAPISpec" tool OR by the "ReadFullDocsMethodSchema" tool - i.e based on the API docs, a relevant recipe you read (preferably), a code example you found in the docs, a schema you read etc.. YOU MUST NEVER ASSUME YOU KNOW WHAT THE BODY SCHEMA IS WITHOUT CONCRETE EXAMPLES OR SCHEMA DEFINITIONS FROM THE CONVERSATION CONTEXT. Prefer reading relevant recipes if you have them in context for understand the body schema for API calls.',
38685
+ body: [
38686
+ 'The request body as a JSON object or array with all the required fields and values, including nested objects. Pass the actual value (object or array), NOT a JSON string. YOU MUST NEVER MAKE UP A BODY - the body should be based on the conversation context, i.e from the user prompt OR got into the conversation context by the "ReadFullDocsArticle" tool OR by the "SearchWixAPISpec" tool OR by the "ReadFullDocsMethodSchema" tool - i.e based on the API docs, a relevant recipe you read (preferably), a code example you found in the docs, a schema you read etc.. YOU MUST NEVER ASSUME YOU KNOW WHAT THE BODY SCHEMA IS WITHOUT CONCRETE EXAMPLES OR SCHEMA DEFINITIONS FROM THE CONVERSATION CONTEXT. Prefer reading relevant recipes if you have them in context for understand the body schema for API calls.',
38687
+ WQL_FILTER_RULE
38688
+ ].join("\n"),
38663
38689
  reason: "One sentence explaining the original user request and why you are calling this API to complete it.",
38664
38690
  sourceDocUrl: [
38665
38691
  "The URL of the documentation or recipe where you found this API endpoint.",
@@ -38983,15 +39009,17 @@ Failed to fetch content: ${errorMsg}`
38983
39009
  const baseContentsPromise = Promise.all(
38984
39010
  baseDocsWithoutRecipes.map(fetchDoc)
38985
39011
  );
38986
- const skillsContentPromise = getSkillsByPortal(httpClient6, {
39012
+ const skillsContentPromise = skillsTags?.length ? getSkillsByPortal(httpClient6, {
38987
39013
  portalId: REST_PORTAL_ID,
38988
39014
  ...repo && { repo },
38989
39015
  ...commitHash && { commitHash },
38990
- ...skillsTags && skillsTags.length > 0 && { tags: skillsTags }
39016
+ tags: skillsTags
38991
39017
  }).catch((err) => {
38992
39018
  console.error("[WixREADME] Failed to fetch skills by portal:", err);
38993
39019
  return null;
38994
- });
39020
+ }) : fetchDoc({ action: "include", url: RECIPES_INDEX_URL }).then(
39021
+ (doc) => doc?.text ?? null
39022
+ );
38995
39023
  const filter = {};
38996
39024
  if (siteId) filter.siteId = siteId;
38997
39025
  else if (siteName) filter.siteName = siteName;
@@ -52009,12 +52037,12 @@ function addImportClaudeDesignTool(server, authStrategy, options) {
52009
52037
  designUrl = new URL(args.url);
52010
52038
  } catch {
52011
52039
  return errorResult(
52012
- "Invalid design URL \u2014 this tool only accepts the claudeusercontent.com URL produced by Claude Design. For site files the user provided themselves, do not retry: send the user to https://www.wix.com/headless/drop?utm_campaign=mcp to upload them and get a live hosted site."
52040
+ "Invalid design URL \u2014 this tool only accepts the claudeusercontent.com URL produced by Claude Design. For site files the user provided themselves, do not retry this tool. For a full agentic flow, read the recipe and publish the files yourself: https://dev.wix.com/docs/api-reference/account-level/sites/skills/upload-a-website-or-html-files.md \u2014 it covers creating the site and uploading the files end to end. If you can't follow it, or it doesn't apply, send the user to https://www.wix.com/headless/drop?utm_campaign=mcp to upload them and get a live hosted site."
52013
52041
  );
52014
52042
  }
52015
52043
  if (designUrl.protocol !== "https:" || !designUrl.hostname.endsWith(CLAUDE_USER_CONTENT_HOST_SUFFIX)) {
52016
52044
  return errorResult(
52017
- "Invalid design URL \u2014 this tool only accepts the claudeusercontent.com URL produced by Claude Design. For site files the user provided themselves, do not retry: send the user to https://www.wix.com/headless/drop?utm_campaign=mcp to upload them and get a live hosted site."
52045
+ "Invalid design URL \u2014 this tool only accepts the claudeusercontent.com URL produced by Claude Design. For site files the user provided themselves, do not retry this tool. For a full agentic flow, read the recipe and publish the files yourself: https://dev.wix.com/docs/api-reference/account-level/sites/skills/upload-a-website-or-html-files.md \u2014 it covers creating the site and uploading the files end to end. If you can't follow it, or it doesn't apply, send the user to https://www.wix.com/headless/drop?utm_campaign=mcp to upload them and get a live hosted site."
52018
52046
  );
52019
52047
  }
52020
52048
  const accountHeaders = await authStrategy.getAccountAuthHeaders();
@@ -53072,12 +53100,31 @@ function formatExecuteResult(data, maxResponseSize, reportBi) {
53072
53100
  reportBi?.({
53073
53101
  originalLength: typeof data.result === "string" ? data.result.length : JSON.stringify(data.result)?.length
53074
53102
  });
53103
+ const base64Text = base64PayloadText(data.result);
53104
+ if (base64Text !== null) {
53105
+ if (base64Text.length <= MAX_ALLOWED_RESPONSE_CHARS) {
53106
+ return { content: [{ type: "text", text: base64Text }] };
53107
+ }
53108
+ const approxKb = Math.ceil(base64Text.length / 1024).toLocaleString();
53109
+ const limitKb = Math.floor(
53110
+ MAX_ALLOWED_RESPONSE_CHARS / 1024
53111
+ ).toLocaleString();
53112
+ return executeErrorResult(
53113
+ `Binary (base64) result is ~${approxKb} KB, too large to return intact (limit ~${limitKb} KB); truncating it would corrupt the base64. Process the bytes inside your ExecuteWixAPI script \u2014 decode, edit, and re-upload in the same call \u2014 and return only a small summary.`
53114
+ );
53115
+ }
53075
53116
  return {
53076
53117
  content: [
53077
53118
  { type: "text", text: truncateResponse(data.result, maxResponseSize) }
53078
53119
  ]
53079
53120
  };
53080
53121
  }
53122
+ function base64PayloadText(result) {
53123
+ if (result !== null && typeof result === "object" && result.encoding === "base64" && typeof result.data === "string") {
53124
+ return JSON.stringify(result);
53125
+ }
53126
+ return null;
53127
+ }
53081
53128
  function addExecuteTool(server, options) {
53082
53129
  const {
53083
53130
  codeModeBaseUrl,
@@ -17655,6 +17655,7 @@ function rethrowIfUnauthorized(error) {
17655
17655
 
17656
17656
  // src/config/api-request-rules.ts
17657
17657
  var ARRAY_QUERY_PARAMS_RULE = "Repeat array query params once per value: `?fieldsets=URL&fieldsets=RICH_CONTENT`. Do NOT comma-join values (`fieldsets=URL,RICH_CONTENT`), do NOT leave a trailing comma, and do NOT use a value the method schema does not list, even if a sibling method accepts it (draft posts have no `SEO` fieldset).";
17658
+ var WQL_FILTER_RULE = "Query and search filters are written in WQL: each field takes a single operator, so combine conditions with the logical operators \u2014 `$and` and `$or` take an array of expressions, `$not` takes one, and they can nest.";
17658
17659
 
17659
17660
  // src/config/default-config.ts
17660
17661
  var AGENT_GOAL = dedent_default`
@@ -17755,7 +17756,7 @@ var SITE_CREATION_COPY = {
17755
17756
  var SITE_GUIDANCE = dedent_default`
17756
17757
  A new-site request has 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.
17757
17758
 
17758
- One case skips all of this: the user ALREADY HAS the finished site as files — hand-written HTML/CSS/JS, a zip, or the export of an AI builder. There is nothing to build, so don't offer AI or templates and don't call any site-creation tool. Send them to https://www.wix.com/headless/drop?utm_campaign=mcp — they drag the files in and get a live Wix-hosted site. Give that URL exactly as written, keeping the utm_campaign=mcp parameter.
17759
+ One case skips all of this: the user ALREADY HAS the finished site as files — hand-written HTML/CSS/JS, a zip, or the export of an AI builder. There is nothing to build, so don't offer AI or templates and don't call any site-creation tool. For a full agentic flow, read the recipe first and publish the files yourself: https://dev.wix.com/docs/api-reference/account-level/sites/skills/upload-a-website-or-html-files.md — it walks you through creating the site and uploading the files end to end. If you can't follow it, or it doesn't apply (you can't reach the file bytes, or something fails), fall back to sending the user to https://www.wix.com/headless/drop?utm_campaign=mcp — they drag the files in and get a live Wix-hosted site. Give that URL exactly as written, keeping the utm_campaign=mcp parameter.
17759
17760
 
17760
17761
  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.
17761
17762
  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.
@@ -17814,12 +17815,25 @@ var ACCOUNT_SITE_EXECUTE_SCOPE = dedent_default`
17814
17815
  siteId?: string;
17815
17816
  method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
17816
17817
  url: string;
17818
+ // Plain object → JSON. A string is sent verbatim (set your own Content-Type,
17819
+ // e.g. multipart/form-data). A Uint8Array/ArrayBuffer is sent as raw bytes
17820
+ // for binary uploads (set your own Content-Type).
17817
17821
  body?: unknown;
17818
17822
  headers?: Record<string, string>;
17823
+ // "base64" returns the response body as a base64 string (data), with
17824
+ // encoding: "base64" on the result — use it for binary downloads (zip,
17825
+ // image, pdf); decoding those as text corrupts them. Binary content types
17826
+ // are returned as base64 automatically even without this. Decode, edit and
17827
+ // re-upload binary WITHIN this script and return only a small summary. If you
17828
+ // must return the bytes, return the wix.request response object itself (so
17829
+ // encoding: "base64" is preserved and it isn't truncated); a bare base64
17830
+ // string you return is treated as plain text and may be truncated.
17831
+ responseType?: "base64";
17819
17832
  }
17820
17833
  interface WixResponse<T = unknown> {
17821
17834
  status: number;
17822
17835
  data: T;
17836
+ encoding?: "base64";
17823
17837
  json(): Promise<T>;
17824
17838
  }
17825
17839
  declare const wix: {
@@ -17958,6 +17972,7 @@ function buildToolDescriptions(includeReadme, includeImageUploadGuidance = true)
17958
17972
  ReadFullDocsArticle: dedent_default`
17959
17973
  Fetches the full Wix docs article or method article with code examples for using the method.
17960
17974
  Docs articles looks like this: https://dev.wix.com/docs/... and they can either be general docs articles or method articles.
17975
+ Take the URL from the user's message or an earlier tool result. To reach an article you have no URL for, search or browse the docs first.
17961
17976
  For REST docs, use the URL as-is. For SDK docs, the URL SHOULD include ?apiView=SDK.
17962
17977
  ${reminder}
17963
17978
  `,
@@ -18090,7 +18105,7 @@ function buildToolDescriptions(includeReadme, includeImageUploadGuidance = true)
18090
18105
  `,
18091
18106
  "import-claude-design-from-url": dedent_default`
18092
18107
  Import a design created in Claude's design tool into Wix. Takes the signed claudeusercontent.com URL Claude Design produces for its self-contained HTML bundle (all images, fonts, and styles inlined); any other host is rejected. Creates a live Wix-hosted site and returns its URL.
18093
- NOT for site files the user provides themselves (their own HTML/CSS/JS, a zip, another builder's export) — for those, don't call this tool: send the user to https://www.wix.com/headless/drop?utm_campaign=mcp, where they upload the files and get a live hosted site. Give that URL exactly as written, keeping the utm_campaign=mcp parameter.
18108
+ NOT for site files the user provides themselves (their own HTML/CSS/JS, a zip, another builder's export) — for those, don't call this tool. For a full agentic flow, read the recipe and publish the files yourself: https://dev.wix.com/docs/api-reference/account-level/sites/skills/upload-a-website-or-html-files.md — it covers creating the site and uploading the files end to end. If you can't follow it, or it doesn't apply, fall back to sending the user to https://www.wix.com/headless/drop?utm_campaign=mcp, where they upload the files and get a live hosted site. Give that URL exactly as written, keeping the utm_campaign=mcp parameter.
18094
18109
  `,
18095
18110
  RunWixCliCommand: dedent_default`
18096
18111
  Executes Wix CLI commands for Wix app development and management.
@@ -18517,7 +18532,7 @@ function buildToolDescriptions(includeReadme, includeImageUploadGuidance = true)
18517
18532
  CreateWixBusinessGuide: dedent_default`
18518
18533
  Provides comprehensive documentation for creating a new Wix business (site, app, etc.).
18519
18534
  Call this ONLY when the user explicitly asks for a headless site, a Wix Classic Editor site, or manual/advanced account/API-based site creation — these don't need the site's purpose first. For normal site-creation ${SITE_CREATION_COPY.normalCreationRoute.nonWidget}; for a specific template id, call \`CreateSiteFromTemplate\`.
18520
- Exception, even when the user says "headless": if they ALREADY HAVE the finished site as files (their own HTML/CSS/JS, a zip, an AI-builder export) and want those files hosted, don't call this tool — send them to https://www.wix.com/headless/drop?utm_campaign=mcp to upload the files and get a live hosted site (give that URL exactly, keeping the utm_campaign=mcp parameter). This guide's CLI flow is for BUILDING a headless frontend, not for hosting ready-made files.
18535
+ Exception, even when the user says "headless": if they ALREADY HAVE the finished site as files (their own HTML/CSS/JS, a zip, an AI-builder export) and want those files hosted, don't call this tool. For a full agentic flow, read the recipe and publish the files yourself: https://dev.wix.com/docs/api-reference/account-level/sites/skills/upload-a-website-or-html-files.md — it covers creating the site and uploading the files end to end. If you can't follow it, or it doesn't apply, fall back to sending the user to https://www.wix.com/headless/drop?utm_campaign=mcp to upload the files and get a live hosted site (give that URL exactly, keeping the utm_campaign=mcp parameter). This guide's CLI flow is for BUILDING a headless frontend, not for hosting ready-made files.
18521
18536
 
18522
18537
  ## What This Tool Contains
18523
18538
 
@@ -19154,7 +19169,10 @@ var paramDescriptions = {
19154
19169
  ARRAY_QUERY_PARAMS_RULE
19155
19170
  ].join("\n"),
19156
19171
  method: "The HTTP method to use for the API call (e.g. GET, POST, PUT, DELETE)",
19157
- body: 'The request body as a JSON object or array with all the required fields and values, including nested objects. Pass the actual value (object or array), NOT a JSON string. YOU MUST NEVER MAKE UP A BODY - the body should be based on the conversation context, i.e from the user prompt OR got into the conversation context by the "ReadFullDocsArticle" tool OR by the "SearchWixAPISpec" tool OR by the "ReadFullDocsMethodSchema" tool - i.e based on the API docs, a relevant recipe you read (preferably), a code example you found in the docs, a schema you read etc.. YOU MUST NEVER ASSUME YOU KNOW WHAT THE BODY SCHEMA IS WITHOUT CONCRETE EXAMPLES OR SCHEMA DEFINITIONS FROM THE CONVERSATION CONTEXT. Prefer reading relevant recipes if you have them in context for understand the body schema for API calls.',
19172
+ body: [
19173
+ 'The request body as a JSON object or array with all the required fields and values, including nested objects. Pass the actual value (object or array), NOT a JSON string. YOU MUST NEVER MAKE UP A BODY - the body should be based on the conversation context, i.e from the user prompt OR got into the conversation context by the "ReadFullDocsArticle" tool OR by the "SearchWixAPISpec" tool OR by the "ReadFullDocsMethodSchema" tool - i.e based on the API docs, a relevant recipe you read (preferably), a code example you found in the docs, a schema you read etc.. YOU MUST NEVER ASSUME YOU KNOW WHAT THE BODY SCHEMA IS WITHOUT CONCRETE EXAMPLES OR SCHEMA DEFINITIONS FROM THE CONVERSATION CONTEXT. Prefer reading relevant recipes if you have them in context for understand the body schema for API calls.',
19174
+ WQL_FILTER_RULE
19175
+ ].join("\n"),
19158
19176
  reason: "One sentence explaining the original user request and why you are calling this API to complete it.",
19159
19177
  sourceDocUrl: [
19160
19178
  "The URL of the documentation or recipe where you found this API endpoint.",
@@ -19478,15 +19496,17 @@ Failed to fetch content: ${errorMsg}`
19478
19496
  const baseContentsPromise = Promise.all(
19479
19497
  baseDocsWithoutRecipes.map(fetchDoc)
19480
19498
  );
19481
- const skillsContentPromise = getSkillsByPortal(httpClient, {
19499
+ const skillsContentPromise = skillsTags?.length ? getSkillsByPortal(httpClient, {
19482
19500
  portalId: REST_PORTAL_ID,
19483
19501
  ...repo && { repo },
19484
19502
  ...commitHash && { commitHash },
19485
- ...skillsTags && skillsTags.length > 0 && { tags: skillsTags }
19503
+ tags: skillsTags
19486
19504
  }).catch((err) => {
19487
19505
  console.error("[WixREADME] Failed to fetch skills by portal:", err);
19488
19506
  return null;
19489
- });
19507
+ }) : fetchDoc({ action: "include", url: RECIPES_INDEX_URL }).then(
19508
+ (doc) => doc?.text ?? null
19509
+ );
19490
19510
  const filter = {};
19491
19511
  if (siteId) filter.siteId = siteId;
19492
19512
  else if (siteName) filter.siteName = siteName;
@@ -20525,6 +20545,14 @@ var import_http_client2 = __toESM(require_index_node(), 1);
20525
20545
 
20526
20546
  // src/tool-utils.ts
20527
20547
  var REST_METHOD_CONTRACT_RETRY_HINT = "Before retrying, make sure you have everything needed for a correct call: the right endpoint URL, HTTP method, request body shape, and response shape. Use the SearchWixRESTDocumentation tool or BrowseWixRESTDocsMenu tool to find the correct method or relevant related articles, the ReadFullDocsArticle tool to read the method description and all code examples, and the SearchWixAPISpec tool for precise field names and schema details.";
20548
+ var SINGLE_OPERATOR_PER_FIELD_HINT = 'WQL takes one operator per field object. Split the conditions into separate expressions under the matching logical operator \u2014 `{"$and": [{"field": {"$gte": ...}}, {"field": {"$lte": ...}}]}` \u2014 and retry without re-searching the docs.';
20549
+ var FIELD_CAPABILITIES_HINT = "This endpoint declares its filterable and sortable fields with their operators. Read the map with SearchWixAPISpec (`queryMethodData.queryFieldsCapabilitiesMap`, or `searchMethodData.searchFieldsCapabilitiesMap` on search methods) and use only what it lists; otherwise fetch a bounded page and filter or sort the results yourself.";
20550
+ var getRetryHint = (errorDetails) => {
20551
+ if (!/Filter contains unsupported operator/i.test(errorDetails)) {
20552
+ return REST_METHOD_CONTRACT_RETRY_HINT;
20553
+ }
20554
+ return /"operator":"\{/.test(errorDetails) ? SINGLE_OPERATOR_PER_FIELD_HINT : FIELD_CAPABILITIES_HINT;
20555
+ };
20528
20556
  var safeParseJSON = (text) => {
20529
20557
  try {
20530
20558
  return JSON.parse(text);
@@ -20548,7 +20576,7 @@ var buildErrorMessage = ({
20548
20576
  ].filter((str) => !!str).join("\n");
20549
20577
  return `${baseMessage}
20550
20578
 
20551
- ${REST_METHOD_CONTRACT_RETRY_HINT}`;
20579
+ ${getRetryHint(String(errorDetails))}`;
20552
20580
  };
20553
20581
  var handleWixAPIResponse = async (response) => {
20554
20582
  const requestId = response.headers?.["x-wix-request-id"];
@@ -22215,12 +22243,31 @@ function formatExecuteResult(data, maxResponseSize, reportBi) {
22215
22243
  reportBi?.({
22216
22244
  originalLength: typeof data.result === "string" ? data.result.length : JSON.stringify(data.result)?.length
22217
22245
  });
22246
+ const base64Text = base64PayloadText(data.result);
22247
+ if (base64Text !== null) {
22248
+ if (base64Text.length <= MAX_ALLOWED_RESPONSE_CHARS) {
22249
+ return { content: [{ type: "text", text: base64Text }] };
22250
+ }
22251
+ const approxKb = Math.ceil(base64Text.length / 1024).toLocaleString();
22252
+ const limitKb = Math.floor(
22253
+ MAX_ALLOWED_RESPONSE_CHARS / 1024
22254
+ ).toLocaleString();
22255
+ return executeErrorResult(
22256
+ `Binary (base64) result is ~${approxKb} KB, too large to return intact (limit ~${limitKb} KB); truncating it would corrupt the base64. Process the bytes inside your ExecuteWixAPI script \u2014 decode, edit, and re-upload in the same call \u2014 and return only a small summary.`
22257
+ );
22258
+ }
22218
22259
  return {
22219
22260
  content: [
22220
22261
  { type: "text", text: truncateResponse(data.result, maxResponseSize) }
22221
22262
  ]
22222
22263
  };
22223
22264
  }
22265
+ function base64PayloadText(result) {
22266
+ if (result !== null && typeof result === "object" && result.encoding === "base64" && typeof result.data === "string") {
22267
+ return JSON.stringify(result);
22268
+ }
22269
+ return null;
22270
+ }
22224
22271
  function addExecuteTool(server, options) {
22225
22272
  const {
22226
22273
  codeModeBaseUrl,
@@ -2,6 +2,7 @@ import { z } from 'zod';
2
2
  import { logger } from '../infra/logger.js';
3
3
  import { defaultToolDescriptions } from '../config/default-config.js';
4
4
  import { truncateResponse } from './truncate-response.js';
5
+ import { MAX_ALLOWED_RESPONSE_CHARS } from '../infra/response-size-limits.js';
5
6
  import { validateExecuteCode } from './validation.js';
6
7
  import { desc } from '../config/param-descriptions.js';
7
8
  import { rethrowIfUnauthorized } from '../auth/index.js';
@@ -176,12 +177,39 @@ function formatExecuteResult(data, maxResponseSize, reportBi) {
176
177
  ? data.result.length
177
178
  : JSON.stringify(data.result)?.length
178
179
  });
180
+ // A base64/binary payload (a downloaded zip, image, …) must never be sliced:
181
+ // a cut base64 string decodes to garbage, so the usual char-limit truncation
182
+ // would silently corrupt it. Return it whole up to the hard ceiling; past
183
+ // that, fail cleanly rather than hand back a broken blob.
184
+ const base64Text = base64PayloadText(data.result);
185
+ if (base64Text !== null) {
186
+ if (base64Text.length <= MAX_ALLOWED_RESPONSE_CHARS) {
187
+ return { content: [{ type: 'text', text: base64Text }] };
188
+ }
189
+ const approxKb = Math.ceil(base64Text.length / 1024).toLocaleString();
190
+ const limitKb = Math.floor(MAX_ALLOWED_RESPONSE_CHARS / 1024).toLocaleString();
191
+ return executeErrorResult(`Binary (base64) result is ~${approxKb} KB, too large to return intact (limit ~${limitKb} KB); truncating it would corrupt the base64. Process the bytes inside your ExecuteWixAPI script — decode, edit, and re-upload in the same call — and return only a small summary.`);
192
+ }
179
193
  return {
180
194
  content: [
181
195
  { type: 'text', text: truncateResponse(data.result, maxResponseSize) }
182
196
  ]
183
197
  };
184
198
  }
199
+ // A base64 payload the caller returned as a WixResponse carrying
200
+ // `encoding: "base64"` — the shape `wix.request` produces for a binary body.
201
+ // We key off that explicit marker, never a content heuristic: a long string in
202
+ // the base64 alphabet can be ordinary text (e.g. "x".repeat(30000)) and must
203
+ // still truncate normally. Returns the text to keep intact, or null otherwise.
204
+ function base64PayloadText(result) {
205
+ if (result !== null &&
206
+ typeof result === 'object' &&
207
+ result.encoding === 'base64' &&
208
+ typeof result.data === 'string') {
209
+ return JSON.stringify(result);
210
+ }
211
+ return null;
212
+ }
185
213
  function addExecuteTool(server, options) {
186
214
  const { codeModeBaseUrl, codeModeFetch, authStrategy, visitor, toolDescriptions, maxResponseSize } = options;
187
215
  const executeUrl = `${codeModeBaseUrl}/api/code-mode/execute`;
@@ -8,4 +8,5 @@
8
8
  * single unknown enum member and rejected with HTTP 400.
9
9
  */
10
10
  export declare const ARRAY_QUERY_PARAMS_RULE = "Repeat array query params once per value: `?fieldsets=URL&fieldsets=RICH_CONTENT`. Do NOT comma-join values (`fieldsets=URL,RICH_CONTENT`), do NOT leave a trailing comma, and do NOT use a value the method schema does not list, even if a sibling method accepts it (draft posts have no `SEO` fieldset).";
11
+ export declare const WQL_FILTER_RULE = "Query and search filters are written in WQL: each field takes a single operator, so combine conditions with the logical operators \u2014 `$and` and `$or` take an array of expressions, `$not` takes one, and they can nest.";
11
12
  //# sourceMappingURL=api-request-rules.d.ts.map
@@ -8,4 +8,5 @@
8
8
  * single unknown enum member and rejected with HTTP 400.
9
9
  */
10
10
  export const ARRAY_QUERY_PARAMS_RULE = 'Repeat array query params once per value: `?fieldsets=URL&fieldsets=RICH_CONTENT`. Do NOT comma-join values (`fieldsets=URL,RICH_CONTENT`), do NOT leave a trailing comma, and do NOT use a value the method schema does not list, even if a sibling method accepts it (draft posts have no `SEO` fieldset).';
11
+ export const WQL_FILTER_RULE = 'Query and search filters are written in WQL: each field takes a single operator, so combine conditions with the logical operators — `$and` and `$or` take an array of expressions, `$not` takes one, and they can nest.';
11
12
  //# sourceMappingURL=api-request-rules.js.map
@@ -80,7 +80,7 @@ export const SITE_CREATION_COPY = {
80
80
  const SITE_GUIDANCE = dedent `
81
81
  A new-site request has 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.
82
82
 
83
- One case skips all of this: the user ALREADY HAS the finished site as files — hand-written HTML/CSS/JS, a zip, or the export of an AI builder. There is nothing to build, so don't offer AI or templates and don't call any site-creation tool. Send them to https://www.wix.com/headless/drop?utm_campaign=mcp — they drag the files in and get a live Wix-hosted site. Give that URL exactly as written, keeping the utm_campaign=mcp parameter.
83
+ One case skips all of this: the user ALREADY HAS the finished site as files — hand-written HTML/CSS/JS, a zip, or the export of an AI builder. There is nothing to build, so don't offer AI or templates and don't call any site-creation tool. For a full agentic flow, read the recipe first and publish the files yourself: https://dev.wix.com/docs/api-reference/account-level/sites/skills/upload-a-website-or-html-files.md — it walks you through creating the site and uploading the files end to end. If you can't follow it, or it doesn't apply (you can't reach the file bytes, or something fails), fall back to sending the user to https://www.wix.com/headless/drop?utm_campaign=mcp — they drag the files in and get a live Wix-hosted site. Give that URL exactly as written, keeping the utm_campaign=mcp parameter.
84
84
 
85
85
  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.
86
86
  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.
@@ -142,12 +142,25 @@ const ACCOUNT_SITE_EXECUTE_SCOPE = dedent `
142
142
  siteId?: string;
143
143
  method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
144
144
  url: string;
145
+ // Plain object → JSON. A string is sent verbatim (set your own Content-Type,
146
+ // e.g. multipart/form-data). A Uint8Array/ArrayBuffer is sent as raw bytes
147
+ // for binary uploads (set your own Content-Type).
145
148
  body?: unknown;
146
149
  headers?: Record<string, string>;
150
+ // "base64" returns the response body as a base64 string (data), with
151
+ // encoding: "base64" on the result — use it for binary downloads (zip,
152
+ // image, pdf); decoding those as text corrupts them. Binary content types
153
+ // are returned as base64 automatically even without this. Decode, edit and
154
+ // re-upload binary WITHIN this script and return only a small summary. If you
155
+ // must return the bytes, return the wix.request response object itself (so
156
+ // encoding: "base64" is preserved and it isn't truncated); a bare base64
157
+ // string you return is treated as plain text and may be truncated.
158
+ responseType?: "base64";
147
159
  }
148
160
  interface WixResponse<T = unknown> {
149
161
  status: number;
150
162
  data: T;
163
+ encoding?: "base64";
151
164
  json(): Promise<T>;
152
165
  }
153
166
  declare const wix: {
@@ -283,6 +296,7 @@ export function buildToolDescriptions(includeReadme, includeImageUploadGuidance
283
296
  ReadFullDocsArticle: dedent `
284
297
  Fetches the full Wix docs article or method article with code examples for using the method.
285
298
  Docs articles looks like this: https://dev.wix.com/docs/... and they can either be general docs articles or method articles.
299
+ Take the URL from the user's message or an earlier tool result. To reach an article you have no URL for, search or browse the docs first.
286
300
  For REST docs, use the URL as-is. For SDK docs, the URL SHOULD include ?apiView=SDK.
287
301
  ${reminder}
288
302
  `,
@@ -415,7 +429,7 @@ export function buildToolDescriptions(includeReadme, includeImageUploadGuidance
415
429
  `,
416
430
  'import-claude-design-from-url': dedent `
417
431
  Import a design created in Claude's design tool into Wix. Takes the signed claudeusercontent.com URL Claude Design produces for its self-contained HTML bundle (all images, fonts, and styles inlined); any other host is rejected. Creates a live Wix-hosted site and returns its URL.
418
- NOT for site files the user provides themselves (their own HTML/CSS/JS, a zip, another builder's export) — for those, don't call this tool: send the user to https://www.wix.com/headless/drop?utm_campaign=mcp, where they upload the files and get a live hosted site. Give that URL exactly as written, keeping the utm_campaign=mcp parameter.
432
+ NOT for site files the user provides themselves (their own HTML/CSS/JS, a zip, another builder's export) — for those, don't call this tool. For a full agentic flow, read the recipe and publish the files yourself: https://dev.wix.com/docs/api-reference/account-level/sites/skills/upload-a-website-or-html-files.md — it covers creating the site and uploading the files end to end. If you can't follow it, or it doesn't apply, fall back to sending the user to https://www.wix.com/headless/drop?utm_campaign=mcp, where they upload the files and get a live hosted site. Give that URL exactly as written, keeping the utm_campaign=mcp parameter.
419
433
  `,
420
434
  RunWixCliCommand: dedent `
421
435
  Executes Wix CLI commands for Wix app development and management.
@@ -842,7 +856,7 @@ export function buildToolDescriptions(includeReadme, includeImageUploadGuidance
842
856
  CreateWixBusinessGuide: dedent `
843
857
  Provides comprehensive documentation for creating a new Wix business (site, app, etc.).
844
858
  Call this ONLY when the user explicitly asks for a headless site, a Wix Classic Editor site, or manual/advanced account/API-based site creation — these don't need the site's purpose first. For normal site-creation ${SITE_CREATION_COPY.normalCreationRoute.nonWidget}; for a specific template id, call \`CreateSiteFromTemplate\`.
845
- Exception, even when the user says "headless": if they ALREADY HAVE the finished site as files (their own HTML/CSS/JS, a zip, an AI-builder export) and want those files hosted, don't call this tool — send them to https://www.wix.com/headless/drop?utm_campaign=mcp to upload the files and get a live hosted site (give that URL exactly, keeping the utm_campaign=mcp parameter). This guide's CLI flow is for BUILDING a headless frontend, not for hosting ready-made files.
859
+ Exception, even when the user says "headless": if they ALREADY HAVE the finished site as files (their own HTML/CSS/JS, a zip, an AI-builder export) and want those files hosted, don't call this tool. For a full agentic flow, read the recipe and publish the files yourself: https://dev.wix.com/docs/api-reference/account-level/sites/skills/upload-a-website-or-html-files.md — it covers creating the site and uploading the files end to end. If you can't follow it, or it doesn't apply, fall back to sending the user to https://www.wix.com/headless/drop?utm_campaign=mcp to upload the files and get a live hosted site (give that URL exactly, keeping the utm_campaign=mcp parameter). This guide's CLI flow is for BUILDING a headless frontend, not for hosting ready-made files.
846
860
 
847
861
  ## What This Tool Contains
848
862
 
@@ -1,5 +1,5 @@
1
1
  import { ALLOWED_HOSTNAMES } from '../api-call/validation.js';
2
- import { ARRAY_QUERY_PARAMS_RULE } from './api-request-rules.js';
2
+ import { ARRAY_QUERY_PARAMS_RULE, WQL_FILTER_RULE } from './api-request-rules.js';
3
3
  /**
4
4
  * Centralized parameter descriptions organized by tool.
5
5
  * Each tool has all its parameter descriptions in one place.
@@ -15,7 +15,10 @@ export const paramDescriptions = {
15
15
  ARRAY_QUERY_PARAMS_RULE
16
16
  ].join('\n'),
17
17
  method: 'The HTTP method to use for the API call (e.g. GET, POST, PUT, DELETE)',
18
- body: 'The request body as a JSON object or array with all the required fields and values, including nested objects. Pass the actual value (object or array), NOT a JSON string. YOU MUST NEVER MAKE UP A BODY - the body should be based on the conversation context, i.e from the user prompt OR got into the conversation context by the "ReadFullDocsArticle" tool OR by the "SearchWixAPISpec" tool OR by the "ReadFullDocsMethodSchema" tool - i.e based on the API docs, a relevant recipe you read (preferably), a code example you found in the docs, a schema you read etc.. YOU MUST NEVER ASSUME YOU KNOW WHAT THE BODY SCHEMA IS WITHOUT CONCRETE EXAMPLES OR SCHEMA DEFINITIONS FROM THE CONVERSATION CONTEXT. Prefer reading relevant recipes if you have them in context for understand the body schema for API calls.',
18
+ body: [
19
+ 'The request body as a JSON object or array with all the required fields and values, including nested objects. Pass the actual value (object or array), NOT a JSON string. YOU MUST NEVER MAKE UP A BODY - the body should be based on the conversation context, i.e from the user prompt OR got into the conversation context by the "ReadFullDocsArticle" tool OR by the "SearchWixAPISpec" tool OR by the "ReadFullDocsMethodSchema" tool - i.e based on the API docs, a relevant recipe you read (preferably), a code example you found in the docs, a schema you read etc.. YOU MUST NEVER ASSUME YOU KNOW WHAT THE BODY SCHEMA IS WITHOUT CONCRETE EXAMPLES OR SCHEMA DEFINITIONS FROM THE CONVERSATION CONTEXT. Prefer reading relevant recipes if you have them in context for understand the body schema for API calls.',
20
+ WQL_FILTER_RULE
21
+ ].join('\n'),
19
22
  reason: 'One sentence explaining the original user request and why you are calling this API to complete it.',
20
23
  sourceDocUrl: [
21
24
  'The URL of the documentation or recipe where you found this API endpoint.',
@@ -169,17 +169,20 @@ export async function addGetToKnowTools({ server, disableTools = [], toolDescrip
169
169
  // return '';
170
170
  // });
171
171
  const baseContentsPromise = Promise.all(baseDocsWithoutRecipes.map(fetchDoc));
172
- // Fetch the skills index from the portal. In PR mode, pass repo+commitHash
173
- // to get the PR-aware index (includes recipes added via YAML in the PR).
174
- const skillsContentPromise = getSkillsByPortal(httpClient, {
175
- portalId: REST_PORTAL_ID,
176
- ...(repo && { repo }),
177
- ...(commitHash && { commitHash }),
178
- ...(skillsTags && skillsTags.length > 0 && { tags: skillsTags })
179
- }).catch((err) => {
180
- console.error('[WixREADME] Failed to fetch skills by portal:', err);
181
- return null;
182
- });
172
+ // Filtered lists still come from the portal. The full management index is
173
+ // authored alongside the recipes and is fetched like any other article,
174
+ // using its commit version when a PR override is configured.
175
+ const skillsContentPromise = skillsTags?.length
176
+ ? getSkillsByPortal(httpClient, {
177
+ portalId: REST_PORTAL_ID,
178
+ ...(repo && { repo }),
179
+ ...(commitHash && { commitHash }),
180
+ tags: skillsTags
181
+ }).catch((err) => {
182
+ console.error('[WixREADME] Failed to fetch skills by portal:', err);
183
+ return null;
184
+ })
185
+ : fetchDoc({ action: 'include', url: RECIPES_INDEX_URL }).then((doc) => doc?.text ?? null);
183
186
  // Auto-inject site context. With no site targeted this is the account-wide
184
187
  // view: single-site accounts "just work", and accounts with more than the
185
188
  // cap show the first N sites plus a note to use GetSiteContext for the rest.
@@ -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 files the user provided themselves, do not retry: send the user to https://www.wix.com/headless/drop?utm_campaign=mcp to upload them and get a live hosted site.');
89
+ return errorResult("Invalid design URL — this tool only accepts the claudeusercontent.com URL produced by Claude Design. For site files the user provided themselves, do not retry this tool. For a full agentic flow, read the recipe and publish the files yourself: https://dev.wix.com/docs/api-reference/account-level/sites/skills/upload-a-website-or-html-files.md — it covers creating the site and uploading the files end to end. If you can't follow it, or it doesn't apply, send the user to https://www.wix.com/headless/drop?utm_campaign=mcp to upload them and get a live hosted site.");
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 files the user provided themselves, do not retry: send the user to https://www.wix.com/headless/drop?utm_campaign=mcp to upload them and get a live hosted site.');
93
+ return errorResult("Invalid design URL — this tool only accepts the claudeusercontent.com URL produced by Claude Design. For site files the user provided themselves, do not retry this tool. For a full agentic flow, read the recipe and publish the files yourself: https://dev.wix.com/docs/api-reference/account-level/sites/skills/upload-a-website-or-html-files.md — it covers creating the site and uploading the files end to end. If you can't follow it, or it doesn't apply, send the user to https://www.wix.com/headless/drop?utm_campaign=mcp to upload them and get a live hosted site.");
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
@@ -1,5 +1,16 @@
1
1
  const REST_METHOD_CONTRACT_RETRY_HINT = 'Before retrying, make sure you have everything needed for a correct call: the right endpoint URL, HTTP method, request body shape, and response shape. ' +
2
2
  'Use the SearchWixRESTDocumentation tool or BrowseWixRESTDocsMenu tool to find the correct method or relevant related articles, the ReadFullDocsArticle tool to read the method description and all code examples, and the SearchWixAPISpec tool for precise field names and schema details.';
3
+ const SINGLE_OPERATOR_PER_FIELD_HINT = 'WQL takes one operator per field object. Split the conditions into separate expressions under the matching logical operator — `{"$and": [{"field": {"$gte": ...}}, {"field": {"$lte": ...}}]}` — and retry without re-searching the docs.';
4
+ const FIELD_CAPABILITIES_HINT = 'This endpoint declares its filterable and sortable fields with their operators. Read the map with SearchWixAPISpec (`queryMethodData.queryFieldsCapabilitiesMap`, or `searchMethodData.searchFieldsCapabilitiesMap` on search methods) and use only what it lists; otherwise fetch a bounded page and filter or sort the results yourself.';
5
+ const getRetryHint = (errorDetails) => {
6
+ if (!/Filter contains unsupported operator/i.test(errorDetails)) {
7
+ return REST_METHOD_CONTRACT_RETRY_HINT;
8
+ }
9
+ // The API reports a field object with several operators as one unknown operator whose name is that object.
10
+ return /"operator":"\{/.test(errorDetails)
11
+ ? SINGLE_OPERATOR_PER_FIELD_HINT
12
+ : FIELD_CAPABILITIES_HINT;
13
+ };
3
14
  export const DEFAULT_OPENAI_SECURITY_SCHEMES = [
4
15
  { type: 'oauth2', scopes: ['offline_access'] }
5
16
  ];
@@ -28,7 +39,7 @@ export const buildErrorMessage = ({ status, statusText, requestId, responseData
28
39
  ]
29
40
  .filter((str) => !!str)
30
41
  .join('\n');
31
- return `${baseMessage}\n\n${REST_METHOD_CONTRACT_RETRY_HINT}`;
42
+ return `${baseMessage}\n\n${getRetryHint(String(errorDetails))}`;
32
43
  };
33
44
  export const handleWixAPIResponse = async (response) => {
34
45
  const requestId = response.headers?.['x-wix-request-id'];
@@ -27117,6 +27117,14 @@ var EMPTY_COMPLETION_RESULT = {
27117
27117
 
27118
27118
  // src/tool-utils.ts
27119
27119
  var REST_METHOD_CONTRACT_RETRY_HINT = "Before retrying, make sure you have everything needed for a correct call: the right endpoint URL, HTTP method, request body shape, and response shape. Use the SearchWixRESTDocumentation tool or BrowseWixRESTDocsMenu tool to find the correct method or relevant related articles, the ReadFullDocsArticle tool to read the method description and all code examples, and the SearchWixAPISpec tool for precise field names and schema details.";
27120
+ var SINGLE_OPERATOR_PER_FIELD_HINT = 'WQL takes one operator per field object. Split the conditions into separate expressions under the matching logical operator \u2014 `{"$and": [{"field": {"$gte": ...}}, {"field": {"$lte": ...}}]}` \u2014 and retry without re-searching the docs.';
27121
+ var FIELD_CAPABILITIES_HINT = "This endpoint declares its filterable and sortable fields with their operators. Read the map with SearchWixAPISpec (`queryMethodData.queryFieldsCapabilitiesMap`, or `searchMethodData.searchFieldsCapabilitiesMap` on search methods) and use only what it lists; otherwise fetch a bounded page and filter or sort the results yourself.";
27122
+ var getRetryHint = (errorDetails) => {
27123
+ if (!/Filter contains unsupported operator/i.test(errorDetails)) {
27124
+ return REST_METHOD_CONTRACT_RETRY_HINT;
27125
+ }
27126
+ return /"operator":"\{/.test(errorDetails) ? SINGLE_OPERATOR_PER_FIELD_HINT : FIELD_CAPABILITIES_HINT;
27127
+ };
27120
27128
  var DEFAULT_OPENAI_SECURITY_SCHEMES = [
27121
27129
  { type: "oauth2", scopes: ["offline_access"] }
27122
27130
  ];
@@ -27143,7 +27151,7 @@ var buildErrorMessage = ({
27143
27151
  ].filter((str) => !!str).join("\n");
27144
27152
  return `${baseMessage}
27145
27153
 
27146
- ${REST_METHOD_CONTRACT_RETRY_HINT}`;
27154
+ ${getRetryHint(String(errorDetails))}`;
27147
27155
  };
27148
27156
  var handleWixAPIResponse = async (response) => {
27149
27157
  const requestId = response.headers?.["x-wix-request-id"];
@@ -30873,6 +30881,7 @@ function rethrowIfUnauthorized(error2) {
30873
30881
 
30874
30882
  // src/config/api-request-rules.ts
30875
30883
  var ARRAY_QUERY_PARAMS_RULE = "Repeat array query params once per value: `?fieldsets=URL&fieldsets=RICH_CONTENT`. Do NOT comma-join values (`fieldsets=URL,RICH_CONTENT`), do NOT leave a trailing comma, and do NOT use a value the method schema does not list, even if a sibling method accepts it (draft posts have no `SEO` fieldset).";
30884
+ var WQL_FILTER_RULE = "Query and search filters are written in WQL: each field takes a single operator, so combine conditions with the logical operators \u2014 `$and` and `$or` take an array of expressions, `$not` takes one, and they can nest.";
30876
30885
 
30877
30886
  // src/config/default-config.ts
30878
30887
  var AGENT_GOAL = dedent_default`
@@ -30973,7 +30982,7 @@ var SITE_CREATION_COPY = {
30973
30982
  var SITE_GUIDANCE = dedent_default`
30974
30983
  A new-site request has 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.
30975
30984
 
30976
- One case skips all of this: the user ALREADY HAS the finished site as files — hand-written HTML/CSS/JS, a zip, or the export of an AI builder. There is nothing to build, so don't offer AI or templates and don't call any site-creation tool. Send them to https://www.wix.com/headless/drop?utm_campaign=mcp — they drag the files in and get a live Wix-hosted site. Give that URL exactly as written, keeping the utm_campaign=mcp parameter.
30985
+ One case skips all of this: the user ALREADY HAS the finished site as files — hand-written HTML/CSS/JS, a zip, or the export of an AI builder. There is nothing to build, so don't offer AI or templates and don't call any site-creation tool. For a full agentic flow, read the recipe first and publish the files yourself: https://dev.wix.com/docs/api-reference/account-level/sites/skills/upload-a-website-or-html-files.md — it walks you through creating the site and uploading the files end to end. If you can't follow it, or it doesn't apply (you can't reach the file bytes, or something fails), fall back to sending the user to https://www.wix.com/headless/drop?utm_campaign=mcp — they drag the files in and get a live Wix-hosted site. Give that URL exactly as written, keeping the utm_campaign=mcp parameter.
30977
30986
 
30978
30987
  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.
30979
30988
  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.
@@ -31032,12 +31041,25 @@ var ACCOUNT_SITE_EXECUTE_SCOPE = dedent_default`
31032
31041
  siteId?: string;
31033
31042
  method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
31034
31043
  url: string;
31044
+ // Plain object → JSON. A string is sent verbatim (set your own Content-Type,
31045
+ // e.g. multipart/form-data). A Uint8Array/ArrayBuffer is sent as raw bytes
31046
+ // for binary uploads (set your own Content-Type).
31035
31047
  body?: unknown;
31036
31048
  headers?: Record<string, string>;
31049
+ // "base64" returns the response body as a base64 string (data), with
31050
+ // encoding: "base64" on the result — use it for binary downloads (zip,
31051
+ // image, pdf); decoding those as text corrupts them. Binary content types
31052
+ // are returned as base64 automatically even without this. Decode, edit and
31053
+ // re-upload binary WITHIN this script and return only a small summary. If you
31054
+ // must return the bytes, return the wix.request response object itself (so
31055
+ // encoding: "base64" is preserved and it isn't truncated); a bare base64
31056
+ // string you return is treated as plain text and may be truncated.
31057
+ responseType?: "base64";
31037
31058
  }
31038
31059
  interface WixResponse<T = unknown> {
31039
31060
  status: number;
31040
31061
  data: T;
31062
+ encoding?: "base64";
31041
31063
  json(): Promise<T>;
31042
31064
  }
31043
31065
  declare const wix: {
@@ -31176,6 +31198,7 @@ function buildToolDescriptions(includeReadme, includeImageUploadGuidance = true)
31176
31198
  ReadFullDocsArticle: dedent_default`
31177
31199
  Fetches the full Wix docs article or method article with code examples for using the method.
31178
31200
  Docs articles looks like this: https://dev.wix.com/docs/... and they can either be general docs articles or method articles.
31201
+ Take the URL from the user's message or an earlier tool result. To reach an article you have no URL for, search or browse the docs first.
31179
31202
  For REST docs, use the URL as-is. For SDK docs, the URL SHOULD include ?apiView=SDK.
31180
31203
  ${reminder}
31181
31204
  `,
@@ -31308,7 +31331,7 @@ function buildToolDescriptions(includeReadme, includeImageUploadGuidance = true)
31308
31331
  `,
31309
31332
  "import-claude-design-from-url": dedent_default`
31310
31333
  Import a design created in Claude's design tool into Wix. Takes the signed claudeusercontent.com URL Claude Design produces for its self-contained HTML bundle (all images, fonts, and styles inlined); any other host is rejected. Creates a live Wix-hosted site and returns its URL.
31311
- NOT for site files the user provides themselves (their own HTML/CSS/JS, a zip, another builder's export) — for those, don't call this tool: send the user to https://www.wix.com/headless/drop?utm_campaign=mcp, where they upload the files and get a live hosted site. Give that URL exactly as written, keeping the utm_campaign=mcp parameter.
31334
+ NOT for site files the user provides themselves (their own HTML/CSS/JS, a zip, another builder's export) — for those, don't call this tool. For a full agentic flow, read the recipe and publish the files yourself: https://dev.wix.com/docs/api-reference/account-level/sites/skills/upload-a-website-or-html-files.md — it covers creating the site and uploading the files end to end. If you can't follow it, or it doesn't apply, fall back to sending the user to https://www.wix.com/headless/drop?utm_campaign=mcp, where they upload the files and get a live hosted site. Give that URL exactly as written, keeping the utm_campaign=mcp parameter.
31312
31335
  `,
31313
31336
  RunWixCliCommand: dedent_default`
31314
31337
  Executes Wix CLI commands for Wix app development and management.
@@ -31735,7 +31758,7 @@ function buildToolDescriptions(includeReadme, includeImageUploadGuidance = true)
31735
31758
  CreateWixBusinessGuide: dedent_default`
31736
31759
  Provides comprehensive documentation for creating a new Wix business (site, app, etc.).
31737
31760
  Call this ONLY when the user explicitly asks for a headless site, a Wix Classic Editor site, or manual/advanced account/API-based site creation — these don't need the site's purpose first. For normal site-creation ${SITE_CREATION_COPY.normalCreationRoute.nonWidget}; for a specific template id, call \`CreateSiteFromTemplate\`.
31738
- Exception, even when the user says "headless": if they ALREADY HAVE the finished site as files (their own HTML/CSS/JS, a zip, an AI-builder export) and want those files hosted, don't call this tool — send them to https://www.wix.com/headless/drop?utm_campaign=mcp to upload the files and get a live hosted site (give that URL exactly, keeping the utm_campaign=mcp parameter). This guide's CLI flow is for BUILDING a headless frontend, not for hosting ready-made files.
31761
+ Exception, even when the user says "headless": if they ALREADY HAVE the finished site as files (their own HTML/CSS/JS, a zip, an AI-builder export) and want those files hosted, don't call this tool. For a full agentic flow, read the recipe and publish the files yourself: https://dev.wix.com/docs/api-reference/account-level/sites/skills/upload-a-website-or-html-files.md — it covers creating the site and uploading the files end to end. If you can't follow it, or it doesn't apply, fall back to sending the user to https://www.wix.com/headless/drop?utm_campaign=mcp to upload the files and get a live hosted site (give that URL exactly, keeping the utm_campaign=mcp parameter). This guide's CLI flow is for BUILDING a headless frontend, not for hosting ready-made files.
31739
31762
 
31740
31763
  ## What This Tool Contains
31741
31764
 
@@ -32372,7 +32395,10 @@ var paramDescriptions = {
32372
32395
  ARRAY_QUERY_PARAMS_RULE
32373
32396
  ].join("\n"),
32374
32397
  method: "The HTTP method to use for the API call (e.g. GET, POST, PUT, DELETE)",
32375
- body: 'The request body as a JSON object or array with all the required fields and values, including nested objects. Pass the actual value (object or array), NOT a JSON string. YOU MUST NEVER MAKE UP A BODY - the body should be based on the conversation context, i.e from the user prompt OR got into the conversation context by the "ReadFullDocsArticle" tool OR by the "SearchWixAPISpec" tool OR by the "ReadFullDocsMethodSchema" tool - i.e based on the API docs, a relevant recipe you read (preferably), a code example you found in the docs, a schema you read etc.. YOU MUST NEVER ASSUME YOU KNOW WHAT THE BODY SCHEMA IS WITHOUT CONCRETE EXAMPLES OR SCHEMA DEFINITIONS FROM THE CONVERSATION CONTEXT. Prefer reading relevant recipes if you have them in context for understand the body schema for API calls.',
32398
+ body: [
32399
+ 'The request body as a JSON object or array with all the required fields and values, including nested objects. Pass the actual value (object or array), NOT a JSON string. YOU MUST NEVER MAKE UP A BODY - the body should be based on the conversation context, i.e from the user prompt OR got into the conversation context by the "ReadFullDocsArticle" tool OR by the "SearchWixAPISpec" tool OR by the "ReadFullDocsMethodSchema" tool - i.e based on the API docs, a relevant recipe you read (preferably), a code example you found in the docs, a schema you read etc.. YOU MUST NEVER ASSUME YOU KNOW WHAT THE BODY SCHEMA IS WITHOUT CONCRETE EXAMPLES OR SCHEMA DEFINITIONS FROM THE CONVERSATION CONTEXT. Prefer reading relevant recipes if you have them in context for understand the body schema for API calls.',
32400
+ WQL_FILTER_RULE
32401
+ ].join("\n"),
32376
32402
  reason: "One sentence explaining the original user request and why you are calling this API to complete it.",
32377
32403
  sourceDocUrl: [
32378
32404
  "The URL of the documentation or recipe where you found this API endpoint.",
@@ -32696,15 +32722,17 @@ Failed to fetch content: ${errorMsg}`
32696
32722
  const baseContentsPromise = Promise.all(
32697
32723
  baseDocsWithoutRecipes.map(fetchDoc)
32698
32724
  );
32699
- const skillsContentPromise = getSkillsByPortal(httpClient6, {
32725
+ const skillsContentPromise = skillsTags?.length ? getSkillsByPortal(httpClient6, {
32700
32726
  portalId: REST_PORTAL_ID,
32701
32727
  ...repo && { repo },
32702
32728
  ...commitHash && { commitHash },
32703
- ...skillsTags && skillsTags.length > 0 && { tags: skillsTags }
32729
+ tags: skillsTags
32704
32730
  }).catch((err) => {
32705
32731
  console.error("[WixREADME] Failed to fetch skills by portal:", err);
32706
32732
  return null;
32707
- });
32733
+ }) : fetchDoc({ action: "include", url: RECIPES_INDEX_URL }).then(
32734
+ (doc) => doc?.text ?? null
32735
+ );
32708
32736
  const filter = {};
32709
32737
  if (siteId) filter.siteId = siteId;
32710
32738
  else if (siteName) filter.siteName = siteName;
@@ -45776,12 +45804,12 @@ function addImportClaudeDesignTool(server, authStrategy, options) {
45776
45804
  designUrl = new URL(args.url);
45777
45805
  } catch {
45778
45806
  return errorResult(
45779
- "Invalid design URL \u2014 this tool only accepts the claudeusercontent.com URL produced by Claude Design. For site files the user provided themselves, do not retry: send the user to https://www.wix.com/headless/drop?utm_campaign=mcp to upload them and get a live hosted site."
45807
+ "Invalid design URL \u2014 this tool only accepts the claudeusercontent.com URL produced by Claude Design. For site files the user provided themselves, do not retry this tool. For a full agentic flow, read the recipe and publish the files yourself: https://dev.wix.com/docs/api-reference/account-level/sites/skills/upload-a-website-or-html-files.md \u2014 it covers creating the site and uploading the files end to end. If you can't follow it, or it doesn't apply, send the user to https://www.wix.com/headless/drop?utm_campaign=mcp to upload them and get a live hosted site."
45780
45808
  );
45781
45809
  }
45782
45810
  if (designUrl.protocol !== "https:" || !designUrl.hostname.endsWith(CLAUDE_USER_CONTENT_HOST_SUFFIX)) {
45783
45811
  return errorResult(
45784
- "Invalid design URL \u2014 this tool only accepts the claudeusercontent.com URL produced by Claude Design. For site files the user provided themselves, do not retry: send the user to https://www.wix.com/headless/drop?utm_campaign=mcp to upload them and get a live hosted site."
45812
+ "Invalid design URL \u2014 this tool only accepts the claudeusercontent.com URL produced by Claude Design. For site files the user provided themselves, do not retry this tool. For a full agentic flow, read the recipe and publish the files yourself: https://dev.wix.com/docs/api-reference/account-level/sites/skills/upload-a-website-or-html-files.md \u2014 it covers creating the site and uploading the files end to end. If you can't follow it, or it doesn't apply, send the user to https://www.wix.com/headless/drop?utm_campaign=mcp to upload them and get a live hosted site."
45785
45813
  );
45786
45814
  }
45787
45815
  const accountHeaders = await authStrategy.getAccountAuthHeaders();
@@ -46836,12 +46864,31 @@ function formatExecuteResult(data, maxResponseSize, reportBi) {
46836
46864
  reportBi?.({
46837
46865
  originalLength: typeof data.result === "string" ? data.result.length : JSON.stringify(data.result)?.length
46838
46866
  });
46867
+ const base64Text = base64PayloadText(data.result);
46868
+ if (base64Text !== null) {
46869
+ if (base64Text.length <= MAX_ALLOWED_RESPONSE_CHARS) {
46870
+ return { content: [{ type: "text", text: base64Text }] };
46871
+ }
46872
+ const approxKb = Math.ceil(base64Text.length / 1024).toLocaleString();
46873
+ const limitKb = Math.floor(
46874
+ MAX_ALLOWED_RESPONSE_CHARS / 1024
46875
+ ).toLocaleString();
46876
+ return executeErrorResult(
46877
+ `Binary (base64) result is ~${approxKb} KB, too large to return intact (limit ~${limitKb} KB); truncating it would corrupt the base64. Process the bytes inside your ExecuteWixAPI script \u2014 decode, edit, and re-upload in the same call \u2014 and return only a small summary.`
46878
+ );
46879
+ }
46839
46880
  return {
46840
46881
  content: [
46841
46882
  { type: "text", text: truncateResponse(data.result, maxResponseSize) }
46842
46883
  ]
46843
46884
  };
46844
46885
  }
46886
+ function base64PayloadText(result) {
46887
+ if (result !== null && typeof result === "object" && result.encoding === "base64" && typeof result.data === "string") {
46888
+ return JSON.stringify(result);
46889
+ }
46890
+ return null;
46891
+ }
46845
46892
  function addExecuteTool(server, options) {
46846
46893
  const {
46847
46894
  codeModeBaseUrl,
@@ -12077,6 +12077,7 @@ function rethrowIfUnauthorized(error) {
12077
12077
 
12078
12078
  // src/config/api-request-rules.ts
12079
12079
  var ARRAY_QUERY_PARAMS_RULE = "Repeat array query params once per value: `?fieldsets=URL&fieldsets=RICH_CONTENT`. Do NOT comma-join values (`fieldsets=URL,RICH_CONTENT`), do NOT leave a trailing comma, and do NOT use a value the method schema does not list, even if a sibling method accepts it (draft posts have no `SEO` fieldset).";
12080
+ var WQL_FILTER_RULE = "Query and search filters are written in WQL: each field takes a single operator, so combine conditions with the logical operators \u2014 `$and` and `$or` take an array of expressions, `$not` takes one, and they can nest.";
12080
12081
 
12081
12082
  // src/config/default-config.ts
12082
12083
  var AGENT_GOAL = dedent_default`
@@ -12177,7 +12178,7 @@ var SITE_CREATION_COPY = {
12177
12178
  var SITE_GUIDANCE = dedent_default`
12178
12179
  A new-site request has 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.
12179
12180
 
12180
- One case skips all of this: the user ALREADY HAS the finished site as files — hand-written HTML/CSS/JS, a zip, or the export of an AI builder. There is nothing to build, so don't offer AI or templates and don't call any site-creation tool. Send them to https://www.wix.com/headless/drop?utm_campaign=mcp — they drag the files in and get a live Wix-hosted site. Give that URL exactly as written, keeping the utm_campaign=mcp parameter.
12181
+ One case skips all of this: the user ALREADY HAS the finished site as files — hand-written HTML/CSS/JS, a zip, or the export of an AI builder. There is nothing to build, so don't offer AI or templates and don't call any site-creation tool. For a full agentic flow, read the recipe first and publish the files yourself: https://dev.wix.com/docs/api-reference/account-level/sites/skills/upload-a-website-or-html-files.md — it walks you through creating the site and uploading the files end to end. If you can't follow it, or it doesn't apply (you can't reach the file bytes, or something fails), fall back to sending the user to https://www.wix.com/headless/drop?utm_campaign=mcp — they drag the files in and get a live Wix-hosted site. Give that URL exactly as written, keeping the utm_campaign=mcp parameter.
12181
12182
 
12182
12183
  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.
12183
12184
  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.
@@ -12236,12 +12237,25 @@ var ACCOUNT_SITE_EXECUTE_SCOPE = dedent_default`
12236
12237
  siteId?: string;
12237
12238
  method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
12238
12239
  url: string;
12240
+ // Plain object → JSON. A string is sent verbatim (set your own Content-Type,
12241
+ // e.g. multipart/form-data). A Uint8Array/ArrayBuffer is sent as raw bytes
12242
+ // for binary uploads (set your own Content-Type).
12239
12243
  body?: unknown;
12240
12244
  headers?: Record<string, string>;
12245
+ // "base64" returns the response body as a base64 string (data), with
12246
+ // encoding: "base64" on the result — use it for binary downloads (zip,
12247
+ // image, pdf); decoding those as text corrupts them. Binary content types
12248
+ // are returned as base64 automatically even without this. Decode, edit and
12249
+ // re-upload binary WITHIN this script and return only a small summary. If you
12250
+ // must return the bytes, return the wix.request response object itself (so
12251
+ // encoding: "base64" is preserved and it isn't truncated); a bare base64
12252
+ // string you return is treated as plain text and may be truncated.
12253
+ responseType?: "base64";
12241
12254
  }
12242
12255
  interface WixResponse<T = unknown> {
12243
12256
  status: number;
12244
12257
  data: T;
12258
+ encoding?: "base64";
12245
12259
  json(): Promise<T>;
12246
12260
  }
12247
12261
  declare const wix: {
@@ -12380,6 +12394,7 @@ function buildToolDescriptions(includeReadme, includeImageUploadGuidance = true)
12380
12394
  ReadFullDocsArticle: dedent_default`
12381
12395
  Fetches the full Wix docs article or method article with code examples for using the method.
12382
12396
  Docs articles looks like this: https://dev.wix.com/docs/... and they can either be general docs articles or method articles.
12397
+ Take the URL from the user's message or an earlier tool result. To reach an article you have no URL for, search or browse the docs first.
12383
12398
  For REST docs, use the URL as-is. For SDK docs, the URL SHOULD include ?apiView=SDK.
12384
12399
  ${reminder}
12385
12400
  `,
@@ -12512,7 +12527,7 @@ function buildToolDescriptions(includeReadme, includeImageUploadGuidance = true)
12512
12527
  `,
12513
12528
  "import-claude-design-from-url": dedent_default`
12514
12529
  Import a design created in Claude's design tool into Wix. Takes the signed claudeusercontent.com URL Claude Design produces for its self-contained HTML bundle (all images, fonts, and styles inlined); any other host is rejected. Creates a live Wix-hosted site and returns its URL.
12515
- NOT for site files the user provides themselves (their own HTML/CSS/JS, a zip, another builder's export) — for those, don't call this tool: send the user to https://www.wix.com/headless/drop?utm_campaign=mcp, where they upload the files and get a live hosted site. Give that URL exactly as written, keeping the utm_campaign=mcp parameter.
12530
+ NOT for site files the user provides themselves (their own HTML/CSS/JS, a zip, another builder's export) — for those, don't call this tool. For a full agentic flow, read the recipe and publish the files yourself: https://dev.wix.com/docs/api-reference/account-level/sites/skills/upload-a-website-or-html-files.md — it covers creating the site and uploading the files end to end. If you can't follow it, or it doesn't apply, fall back to sending the user to https://www.wix.com/headless/drop?utm_campaign=mcp, where they upload the files and get a live hosted site. Give that URL exactly as written, keeping the utm_campaign=mcp parameter.
12516
12531
  `,
12517
12532
  RunWixCliCommand: dedent_default`
12518
12533
  Executes Wix CLI commands for Wix app development and management.
@@ -12939,7 +12954,7 @@ function buildToolDescriptions(includeReadme, includeImageUploadGuidance = true)
12939
12954
  CreateWixBusinessGuide: dedent_default`
12940
12955
  Provides comprehensive documentation for creating a new Wix business (site, app, etc.).
12941
12956
  Call this ONLY when the user explicitly asks for a headless site, a Wix Classic Editor site, or manual/advanced account/API-based site creation — these don't need the site's purpose first. For normal site-creation ${SITE_CREATION_COPY.normalCreationRoute.nonWidget}; for a specific template id, call \`CreateSiteFromTemplate\`.
12942
- Exception, even when the user says "headless": if they ALREADY HAVE the finished site as files (their own HTML/CSS/JS, a zip, an AI-builder export) and want those files hosted, don't call this tool — send them to https://www.wix.com/headless/drop?utm_campaign=mcp to upload the files and get a live hosted site (give that URL exactly, keeping the utm_campaign=mcp parameter). This guide's CLI flow is for BUILDING a headless frontend, not for hosting ready-made files.
12957
+ Exception, even when the user says "headless": if they ALREADY HAVE the finished site as files (their own HTML/CSS/JS, a zip, an AI-builder export) and want those files hosted, don't call this tool. For a full agentic flow, read the recipe and publish the files yourself: https://dev.wix.com/docs/api-reference/account-level/sites/skills/upload-a-website-or-html-files.md — it covers creating the site and uploading the files end to end. If you can't follow it, or it doesn't apply, fall back to sending the user to https://www.wix.com/headless/drop?utm_campaign=mcp to upload the files and get a live hosted site (give that URL exactly, keeping the utm_campaign=mcp parameter). This guide's CLI flow is for BUILDING a headless frontend, not for hosting ready-made files.
12943
12958
 
12944
12959
  ## What This Tool Contains
12945
12960
 
@@ -13576,7 +13591,10 @@ var paramDescriptions = {
13576
13591
  ARRAY_QUERY_PARAMS_RULE
13577
13592
  ].join("\n"),
13578
13593
  method: "The HTTP method to use for the API call (e.g. GET, POST, PUT, DELETE)",
13579
- body: 'The request body as a JSON object or array with all the required fields and values, including nested objects. Pass the actual value (object or array), NOT a JSON string. YOU MUST NEVER MAKE UP A BODY - the body should be based on the conversation context, i.e from the user prompt OR got into the conversation context by the "ReadFullDocsArticle" tool OR by the "SearchWixAPISpec" tool OR by the "ReadFullDocsMethodSchema" tool - i.e based on the API docs, a relevant recipe you read (preferably), a code example you found in the docs, a schema you read etc.. YOU MUST NEVER ASSUME YOU KNOW WHAT THE BODY SCHEMA IS WITHOUT CONCRETE EXAMPLES OR SCHEMA DEFINITIONS FROM THE CONVERSATION CONTEXT. Prefer reading relevant recipes if you have them in context for understand the body schema for API calls.',
13594
+ body: [
13595
+ 'The request body as a JSON object or array with all the required fields and values, including nested objects. Pass the actual value (object or array), NOT a JSON string. YOU MUST NEVER MAKE UP A BODY - the body should be based on the conversation context, i.e from the user prompt OR got into the conversation context by the "ReadFullDocsArticle" tool OR by the "SearchWixAPISpec" tool OR by the "ReadFullDocsMethodSchema" tool - i.e based on the API docs, a relevant recipe you read (preferably), a code example you found in the docs, a schema you read etc.. YOU MUST NEVER ASSUME YOU KNOW WHAT THE BODY SCHEMA IS WITHOUT CONCRETE EXAMPLES OR SCHEMA DEFINITIONS FROM THE CONVERSATION CONTEXT. Prefer reading relevant recipes if you have them in context for understand the body schema for API calls.',
13596
+ WQL_FILTER_RULE
13597
+ ].join("\n"),
13580
13598
  reason: "One sentence explaining the original user request and why you are calling this API to complete it.",
13581
13599
  sourceDocUrl: [
13582
13600
  "The URL of the documentation or recipe where you found this API endpoint.",
@@ -13900,15 +13918,17 @@ Failed to fetch content: ${errorMsg}`
13900
13918
  const baseContentsPromise = Promise.all(
13901
13919
  baseDocsWithoutRecipes.map(fetchDoc)
13902
13920
  );
13903
- const skillsContentPromise = getSkillsByPortal(httpClient, {
13921
+ const skillsContentPromise = skillsTags?.length ? getSkillsByPortal(httpClient, {
13904
13922
  portalId: REST_PORTAL_ID,
13905
13923
  ...repo && { repo },
13906
13924
  ...commitHash && { commitHash },
13907
- ...skillsTags && skillsTags.length > 0 && { tags: skillsTags }
13925
+ tags: skillsTags
13908
13926
  }).catch((err) => {
13909
13927
  console.error("[WixREADME] Failed to fetch skills by portal:", err);
13910
13928
  return null;
13911
- });
13929
+ }) : fetchDoc({ action: "include", url: RECIPES_INDEX_URL }).then(
13930
+ (doc) => doc?.text ?? null
13931
+ );
13912
13932
  const filter = {};
13913
13933
  if (siteId) filter.siteId = siteId;
13914
13934
  else if (siteName) filter.siteName = siteName;
@@ -14944,6 +14964,14 @@ ${text}`
14944
14964
 
14945
14965
  // src/tool-utils.ts
14946
14966
  var REST_METHOD_CONTRACT_RETRY_HINT = "Before retrying, make sure you have everything needed for a correct call: the right endpoint URL, HTTP method, request body shape, and response shape. Use the SearchWixRESTDocumentation tool or BrowseWixRESTDocsMenu tool to find the correct method or relevant related articles, the ReadFullDocsArticle tool to read the method description and all code examples, and the SearchWixAPISpec tool for precise field names and schema details.";
14967
+ var SINGLE_OPERATOR_PER_FIELD_HINT = 'WQL takes one operator per field object. Split the conditions into separate expressions under the matching logical operator \u2014 `{"$and": [{"field": {"$gte": ...}}, {"field": {"$lte": ...}}]}` \u2014 and retry without re-searching the docs.';
14968
+ var FIELD_CAPABILITIES_HINT = "This endpoint declares its filterable and sortable fields with their operators. Read the map with SearchWixAPISpec (`queryMethodData.queryFieldsCapabilitiesMap`, or `searchMethodData.searchFieldsCapabilitiesMap` on search methods) and use only what it lists; otherwise fetch a bounded page and filter or sort the results yourself.";
14969
+ var getRetryHint = (errorDetails) => {
14970
+ if (!/Filter contains unsupported operator/i.test(errorDetails)) {
14971
+ return REST_METHOD_CONTRACT_RETRY_HINT;
14972
+ }
14973
+ return /"operator":"\{/.test(errorDetails) ? SINGLE_OPERATOR_PER_FIELD_HINT : FIELD_CAPABILITIES_HINT;
14974
+ };
14947
14975
  var safeParseJSON = (text) => {
14948
14976
  try {
14949
14977
  return JSON.parse(text);
@@ -14967,7 +14995,7 @@ var buildErrorMessage = ({
14967
14995
  ].filter((str) => !!str).join("\n");
14968
14996
  return `${baseMessage}
14969
14997
 
14970
- ${REST_METHOD_CONTRACT_RETRY_HINT}`;
14998
+ ${getRetryHint(String(errorDetails))}`;
14971
14999
  };
14972
15000
  var handleWixAPIResponse = async (response) => {
14973
15001
  const requestId = response.headers?.["x-wix-request-id"];
@@ -16634,12 +16662,31 @@ function formatExecuteResult(data, maxResponseSize, reportBi) {
16634
16662
  reportBi?.({
16635
16663
  originalLength: typeof data.result === "string" ? data.result.length : JSON.stringify(data.result)?.length
16636
16664
  });
16665
+ const base64Text = base64PayloadText(data.result);
16666
+ if (base64Text !== null) {
16667
+ if (base64Text.length <= MAX_ALLOWED_RESPONSE_CHARS) {
16668
+ return { content: [{ type: "text", text: base64Text }] };
16669
+ }
16670
+ const approxKb = Math.ceil(base64Text.length / 1024).toLocaleString();
16671
+ const limitKb = Math.floor(
16672
+ MAX_ALLOWED_RESPONSE_CHARS / 1024
16673
+ ).toLocaleString();
16674
+ return executeErrorResult(
16675
+ `Binary (base64) result is ~${approxKb} KB, too large to return intact (limit ~${limitKb} KB); truncating it would corrupt the base64. Process the bytes inside your ExecuteWixAPI script \u2014 decode, edit, and re-upload in the same call \u2014 and return only a small summary.`
16676
+ );
16677
+ }
16637
16678
  return {
16638
16679
  content: [
16639
16680
  { type: "text", text: truncateResponse(data.result, maxResponseSize) }
16640
16681
  ]
16641
16682
  };
16642
16683
  }
16684
+ function base64PayloadText(result) {
16685
+ if (result !== null && typeof result === "object" && result.encoding === "base64" && typeof result.data === "string") {
16686
+ return JSON.stringify(result);
16687
+ }
16688
+ return null;
16689
+ }
16643
16690
  function addExecuteTool(server, options) {
16644
16691
  const {
16645
16692
  codeModeBaseUrl,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/mcp",
3
- "version": "1.0.86",
3
+ "version": "1.0.87",
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": "bfa0ad2bd45ba9e54844e736741354d379ec2790f92872287c5fc1d2"
136
+ "falconPackageHash": "c9087b06450361359889e6ef0ea5562b59ca3f0ea641de700d905ce2"
137
137
  }