@wix/mcp 1.0.84 → 1.0.86

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.
@@ -6,14 +6,17 @@ import { validateExecuteCode } from './validation.js';
6
6
  import { desc } from '../config/param-descriptions.js';
7
7
  import { rethrowIfUnauthorized } from '../auth/index.js';
8
8
  import { WixFetchError } from '../wix-fetch-error.js';
9
+ // Looks `fetch` up per call so a host or test that swaps the global is honored.
10
+ const defaultCodeModeFetch = (url, init) => fetch(url, init);
9
11
  const SEARCH_TOOL_NAME = 'SearchWixAPISpec';
10
12
  export const EXECUTE_TOOL_NAME = 'ExecuteWixAPI';
11
13
  export async function addCodeModeTools(server, options) {
12
- const { codeModeBaseUrl, authStrategy, disableTools = [], toolDescriptions, maxResponseSize } = options;
14
+ const { codeModeBaseUrl, codeModeFetch, authStrategy, disableTools = [], toolDescriptions, maxResponseSize } = options;
13
15
  addSearchCodeModeTool(server, options);
14
16
  if (!disableTools.includes(EXECUTE_TOOL_NAME) && authStrategy) {
15
17
  addExecuteCodeModeTool(server, {
16
18
  codeModeBaseUrl,
19
+ codeModeFetch,
17
20
  authStrategy,
18
21
  disableTools,
19
22
  toolDescriptions,
@@ -29,21 +32,22 @@ export async function addCodeModeTools(server, options) {
29
32
  * lightIndex.
30
33
  */
31
34
  export function addSearchCodeModeTool(server, options) {
32
- const { codeModeBaseUrl, authStrategy, disableTools = [], toolDescriptions, maxResponseSize } = options;
35
+ const { codeModeBaseUrl, codeModeFetch, authStrategy, disableTools = [], toolDescriptions, maxResponseSize } = options;
33
36
  if (disableTools.includes(SEARCH_TOOL_NAME)) {
34
37
  return;
35
38
  }
36
39
  const description = toolDescriptions?.[SEARCH_TOOL_NAME] ??
37
40
  defaultToolDescriptions.SearchWixAPISpec;
38
- registerSearchTool(server, codeModeBaseUrl, description, maxResponseSize, authStrategy);
41
+ registerSearchTool(server, codeModeBaseUrl, description, maxResponseSize, authStrategy, codeModeFetch);
39
42
  }
40
43
  export function addExecuteCodeModeTool(server, options) {
41
- const { codeModeBaseUrl, authStrategy, visitor, disableTools = [], toolDescriptions, maxResponseSize } = options;
44
+ const { codeModeBaseUrl, codeModeFetch, authStrategy, visitor, disableTools = [], toolDescriptions, maxResponseSize } = options;
42
45
  if ((!authStrategy && !visitor) || disableTools.includes(EXECUTE_TOOL_NAME)) {
43
46
  return;
44
47
  }
45
48
  addExecuteTool(server, {
46
49
  codeModeBaseUrl,
50
+ codeModeFetch,
47
51
  authStrategy,
48
52
  visitor,
49
53
  toolDescriptions,
@@ -64,7 +68,7 @@ async function resolveLoopbackAuthorization(authStrategy) {
64
68
  return undefined;
65
69
  }
66
70
  }
67
- function registerSearchTool(server, codeModeBaseUrl, description, maxResponseSize, authStrategy) {
71
+ function registerSearchTool(server, codeModeBaseUrl, description, maxResponseSize, authStrategy, codeModeFetch = defaultCodeModeFetch) {
68
72
  const searchUrl = `${codeModeBaseUrl}/api/code-mode/search`;
69
73
  server.tool(SEARCH_TOOL_NAME, description, {
70
74
  code: z
@@ -77,7 +81,7 @@ function registerSearchTool(server, codeModeBaseUrl, description, maxResponseSiz
77
81
  logger.log(`[SearchWixAPISpec] Executing search (${code.length} chars), reason="${reason}"`);
78
82
  try {
79
83
  const authorization = await resolveLoopbackAuthorization(authStrategy);
80
- const resp = await fetch(searchUrl, {
84
+ const resp = await codeModeFetch(searchUrl, {
81
85
  method: 'POST',
82
86
  headers: {
83
87
  'Content-Type': 'application/json',
@@ -135,8 +139,8 @@ function registerSearchTool(server, codeModeBaseUrl, description, maxResponseSiz
135
139
  * the call looked anonymous to `rateLimiterMiddleware` and shared its IP-keyed
136
140
  * bucket — it comes from the Durable Object, not the client.
137
141
  */
138
- async function postExecute(executeUrl, body, authorization) {
139
- const resp = await fetch(executeUrl, {
142
+ async function postExecute(executeUrl, body, authorization, codeModeFetch = defaultCodeModeFetch) {
143
+ const resp = await codeModeFetch(executeUrl, {
140
144
  method: 'POST',
141
145
  headers: {
142
146
  'Content-Type': 'application/json',
@@ -179,7 +183,7 @@ function formatExecuteResult(data, maxResponseSize, reportBi) {
179
183
  };
180
184
  }
181
185
  function addExecuteTool(server, options) {
182
- const { codeModeBaseUrl, authStrategy, visitor, toolDescriptions, maxResponseSize } = options;
186
+ const { codeModeBaseUrl, codeModeFetch, authStrategy, visitor, toolDescriptions, maxResponseSize } = options;
183
187
  const executeUrl = `${codeModeBaseUrl}/api/code-mode/execute`;
184
188
  const d = desc('ExecuteWixAPI');
185
189
  server.tool(EXECUTE_TOOL_NAME, toolDescriptions?.[EXECUTE_TOOL_NAME] ??
@@ -289,7 +293,7 @@ function addExecuteTool(server, options) {
289
293
  siteAuthContext
290
294
  }, visitor
291
295
  ? visitorToken
292
- : (accountHeaders?.Authorization ?? siteHeaders?.Authorization));
296
+ : (accountHeaders?.Authorization ?? siteHeaders?.Authorization), codeModeFetch);
293
297
  // Visitor mode can't refresh server-side, so steer the agent to regenerate.
294
298
  if (data.authErrorStatus && visitor) {
295
299
  return executeErrorResult(`Visitor token rejected (HTTP ${data.authErrorStatus}). Call GenerateVisitorToken to obtain a fresh token, then retry.`);
@@ -47,7 +47,9 @@ function getErrorMessage(error) {
47
47
  }
48
48
  function shouldTryMenuFallbackForDocsRead(error, articleUrl) {
49
49
  const message = getErrorMessage(error);
50
- if (!message.includes('404') || !articleUrl.includes('/api-reference/')) {
50
+ const { pathname } = new URL(articleUrl);
51
+ const isMenuFallbackUrl = articleUrl.includes('/api-reference/') || pathname.startsWith('/docs/velo');
52
+ if (!message.includes('404') || !isMenuFallbackUrl) {
51
53
  return false;
52
54
  }
53
55
  return !['This resource is deprecated', 'No schema found'].some((knownArticleError) => message.includes(knownArticleError));
@@ -671,7 +673,7 @@ export const addDocsTools = (server, allowedTools = [
671
673
  content: [
672
674
  {
673
675
  type: 'text',
674
- text: `Note: "${articleUrl}" is a documentation category, not an article. Showing its menu contents below. For category URLs, use BrowseWixRESTDocsMenu directly next time.\n\n${text}`
676
+ text: `Note: "${articleUrl}" is not an article. Showing the closest documentation menu below; read the article you need from its links. For category URLs, use BrowseWixRESTDocsMenu directly next time.\n\n${text}`
675
677
  }
676
678
  ]
677
679
  };
@@ -746,7 +748,7 @@ export const addDocsTools = (server, allowedTools = [
746
748
  content: [
747
749
  {
748
750
  type: 'text',
749
- text: `Note: "${articleUrl}" is a documentation category, not an article. Showing its menu contents below. For category URLs, use BrowseWixRESTDocsMenu directly next time.\n\n${text}`
751
+ text: `Note: "${articleUrl}" is not an article. Showing the closest documentation menu below; read the article you need from its links. For category URLs, use BrowseWixRESTDocsMenu directly next time.\n\n${text}`
750
752
  }
751
753
  ]
752
754
  };
@@ -21,7 +21,7 @@ export type { WixToolCallResult, WixToolContentBlock, WixToolAnnotations } from
21
21
  export { createWixToolkit, extractText, type WixTool, type WixToolkit, type WixToolkitOptions, type WixToolkitHooks, type WixToolkitAuth, type WixToolkitDocsConfig, type WixToolkitApiConfig } from './toolkit.js';
22
22
  export { fetchRecipesIndex, fetchArticle, RECIPES_INDEX_URL } from './docs/fetch-article.js';
23
23
  export { generateDocsNavigationTree, fetchMenuContent, MENU_CONTENT_THRESHOLD, normalizeMenuContent, summarizeLargeMenu, parseDirectChildren } from './docs/normalize-menu-content.js';
24
- export { addCodeModeTools, addExecuteCodeModeTool, addSearchCodeModeTool, type CodeModeOptions } from './code-mode/index.js';
24
+ export { addCodeModeTools, addExecuteCodeModeTool, addSearchCodeModeTool, type CodeModeFetch, type CodeModeOptions } from './code-mode/index.js';
25
25
  export { validateExecuteCode, EXECUTE_FUNCTION_EXPRESSION_HINT, type CodeValidationResult } from './code-mode/validation.js';
26
26
  export { addGraphqlTools, resetGraphqlSchemaCache, GRAPHQL_TOOL_NAMES, SEARCH_GRAPHQL_TOOL_NAME, INSPECT_GRAPHQL_TOOL_NAME, EXECUTE_GRAPHQL_TOOL_NAME, WIX_GRAPHQL_ENDPOINT, type GraphqlToolsOptions, type GraphqlToolName } from './graphql/index.js';
27
27
  export { defaultConfig, defaultToolDescriptions, defaultReadmeDocs, widgetSiteCreationConfig, SITE_CREATION_COPY, toWidget, executeCodeModeToolDescriptions, SYSTEM_REMINDER_GUIDELINES, SYSTEM_REMINDER, mergeConfig, type ModeDefaultConfig } from './config/default-config.js';
@@ -6,7 +6,11 @@ import { wixMcpRequestSrc39Evid1607, executeWixApiToolRequestSrc39Evid1612 } fro
6
6
  * and concatenates text blocks with newlines.
7
7
  */
8
8
  export declare function extractText(result: WixToolCallResult): string;
9
- export declare function formatToolResultAdditionalFields(result: WixToolCallResult, extras?: Record<string, unknown>): string | undefined;
9
+ export interface ToolResultClient {
10
+ name?: string;
11
+ userAgent?: string;
12
+ }
13
+ export declare function formatToolResultAdditionalFields(result: WixToolCallResult, extras?: Record<string, unknown>, client?: ToolResultClient): string | undefined;
10
14
  export declare function createToolBiEvent(params: Parameters<typeof wixMcpRequestSrc39Evid1607>[0]): import("@wix/bi-logger-api-infra-data/v2/types").LogObject<import("@wix/bi-logger-api-infra-data/v2/types").wixMcpRequestSrc39Evid1607Params>;
11
15
  export declare function createExecuteWixAPICallToolBiEvent(params: Parameters<typeof executeWixApiToolRequestSrc39Evid1612>[0]): import("@wix/bi-logger-api-infra-data/v2/types").LogObject<import("@wix/bi-logger-api-infra-data/v2/types").executeWixApiToolRequestSrc39Evid1612Params>;
12
16
  //# sourceMappingURL=tool-bi.d.ts.map
@@ -11,7 +11,27 @@ export function extractText(result) {
11
11
  .join('\n');
12
12
  }
13
13
  const TOOL_RESULT_PREVIEW_MAX_CHARS = 4000;
14
- export function formatToolResultAdditionalFields(result, extras) {
14
+ // Codex keeps 10,000 tokens of a tool result by default, estimated at 4 bytes
15
+ // per token, and drops the middle of anything longer.
16
+ const CODEX_OUTPUT_BUDGET_BYTES = 40_000;
17
+ // Predicted from the default budget: a user who raised Codex's
18
+ // tool_output_token_limit is flagged here but not actually truncated.
19
+ function getCodexTruncation(resultText, client) {
20
+ const isCodex = [client?.name, client?.userAgent].some((identity) => identity?.toLowerCase().includes('codex'));
21
+ if (!isCodex) {
22
+ return undefined;
23
+ }
24
+ const resultBytes = new TextEncoder().encode(resultText).length;
25
+ if (resultBytes <= CODEX_OUTPUT_BUDGET_BYTES) {
26
+ return undefined;
27
+ }
28
+ return {
29
+ resultBytes,
30
+ budgetBytes: CODEX_OUTPUT_BUDGET_BYTES,
31
+ truncatedBytes: resultBytes - CODEX_OUTPUT_BUDGET_BYTES
32
+ };
33
+ }
34
+ export function formatToolResultAdditionalFields(result, extras, client) {
15
35
  const resultText = extractText(result);
16
36
  const contentTypes = [
17
37
  ...new Set(result.content?.map((content) => content.type) ?? [])
@@ -24,6 +44,7 @@ export function formatToolResultAdditionalFields(result, extras) {
24
44
  resultTextLength: resultText.length,
25
45
  resultPreviewTruncated: resultText.length > TOOL_RESULT_PREVIEW_MAX_CHARS,
26
46
  resultContentTypes: contentTypes,
47
+ codexTruncation: getCodexTruncation(resultText, client),
27
48
  ...extras
28
49
  });
29
50
  }
@@ -163,13 +163,23 @@ export interface ToolHintsConfig {
163
163
  destructiveHint?: boolean;
164
164
  openWorldHint?: boolean;
165
165
  }
166
+ /**
167
+ * Transport for the code-mode endpoints (`/api/code-mode/search|execute`).
168
+ * Defaults to the global `fetch`; a host that serves those endpoints itself
169
+ * can pass an in-runtime loopback instead.
170
+ */
171
+ export type CodeModeFetch = (url: string, init: RequestInit) => Promise<Response>;
166
172
  /**
167
173
  * Safely extract all text content from a WixToolCallResult.
168
174
  * Filters out non-text content blocks (images, audio, resources)
169
175
  * and concatenates text blocks with newlines.
170
176
  */
171
177
  export declare function extractText(result: WixToolCallResult): string;
172
- export declare function formatToolResultAdditionalFields(result: WixToolCallResult, extras?: Record<string, unknown>): string | undefined;
178
+ export interface ToolResultClient {
179
+ name?: string;
180
+ userAgent?: string;
181
+ }
182
+ export declare function formatToolResultAdditionalFields(result: WixToolCallResult, extras?: Record<string, unknown>, client?: ToolResultClient): string | undefined;
173
183
  /** A single tool extracted from @wix/mcp, ready to execute. */
174
184
  export interface WixTool {
175
185
  /** Tool name (e.g. 'CallWixSiteAPI', 'SearchWixRESTDocumentation') */
@@ -251,6 +261,8 @@ export interface WixToolkitApiConfig {
251
261
  maxResponseSize?: number;
252
262
  /** Base URL for code-mode tools such as ExecuteWixAPI */
253
263
  codeModeBaseUrl?: string;
264
+ /** Transport for the code-mode endpoints; defaults to the global `fetch`. */
265
+ codeModeFetch?: CodeModeFetch;
254
266
  }
255
267
  /** Options for createWixToolkit. */
256
268
  export interface WixToolkitOptions {
@@ -163,13 +163,23 @@ export interface ToolHintsConfig {
163
163
  destructiveHint?: boolean;
164
164
  openWorldHint?: boolean;
165
165
  }
166
+ /**
167
+ * Transport for the code-mode endpoints (`/api/code-mode/search|execute`).
168
+ * Defaults to the global `fetch`; a host that serves those endpoints itself
169
+ * can pass an in-runtime loopback instead.
170
+ */
171
+ export type CodeModeFetch = (url: string, init: RequestInit) => Promise<Response>;
166
172
  /**
167
173
  * Safely extract all text content from a WixToolCallResult.
168
174
  * Filters out non-text content blocks (images, audio, resources)
169
175
  * and concatenates text blocks with newlines.
170
176
  */
171
177
  export declare function extractText(result: WixToolCallResult): string;
172
- export declare function formatToolResultAdditionalFields(result: WixToolCallResult, extras?: Record<string, unknown>): string | undefined;
178
+ export interface ToolResultClient {
179
+ name?: string;
180
+ userAgent?: string;
181
+ }
182
+ export declare function formatToolResultAdditionalFields(result: WixToolCallResult, extras?: Record<string, unknown>, client?: ToolResultClient): string | undefined;
173
183
  /** A single tool extracted from @wix/mcp, ready to execute. */
174
184
  export interface WixTool {
175
185
  /** Tool name (e.g. 'CallWixSiteAPI', 'SearchWixRESTDocumentation') */
@@ -251,6 +261,8 @@ export interface WixToolkitApiConfig {
251
261
  maxResponseSize?: number;
252
262
  /** Base URL for code-mode tools such as ExecuteWixAPI */
253
263
  codeModeBaseUrl?: string;
264
+ /** Transport for the code-mode endpoints; defaults to the global `fetch`. */
265
+ codeModeFetch?: CodeModeFetch;
254
266
  }
255
267
  /** Options for createWixToolkit. */
256
268
  export interface WixToolkitOptions {
@@ -30,6 +30,7 @@ import type { WixToolCallResult, WixToolAnnotations } from './toolkit-types.js';
30
30
  import { z } from 'zod';
31
31
  import { type DocsToolsOptions, type DocsTool } from './docs/docs.js';
32
32
  import { type ToolHintsConfig } from './api-call/index.js';
33
+ import { type CodeModeFetch } from './code-mode/index.js';
33
34
  import type { McpAuthenticationStrategy, McpHeaders } from './auth/index.js';
34
35
  import { extractText, formatToolResultAdditionalFields } from './infra/tool-bi.js';
35
36
  /** A single tool extracted from @wix/mcp, ready to execute. */
@@ -113,6 +114,8 @@ export interface WixToolkitApiConfig {
113
114
  maxResponseSize?: number;
114
115
  /** Base URL for code-mode tools such as ExecuteWixAPI */
115
116
  codeModeBaseUrl?: string;
117
+ /** Transport for the code-mode endpoints; defaults to the global `fetch`. */
118
+ codeModeFetch?: CodeModeFetch;
116
119
  }
117
120
  /** Options for createWixToolkit. */
118
121
  export interface WixToolkitOptions {
@@ -193,7 +193,7 @@ export function createWixToolkit(options) {
193
193
  }
194
194
  // Register API tools
195
195
  if (api) {
196
- const { tools: apiTools, disableTools, enableTools, toolDescriptions, toolHints, maxResponseSize, codeModeBaseUrl = 'https://mcp.wix.com' } = api;
196
+ const { tools: apiTools, disableTools, enableTools, toolDescriptions, toolHints, maxResponseSize, codeModeBaseUrl = 'https://mcp.wix.com', codeModeFetch } = api;
197
197
  // Precedence (low → high): README-free defaults, code-mode variant, consumer overrides.
198
198
  const effectiveToolDescriptions = {
199
199
  ...descriptionsWithoutReadme,
@@ -209,6 +209,7 @@ export function createWixToolkit(options) {
209
209
  !disableTools?.includes('SearchWixAPISpec')) {
210
210
  addSearchCodeModeTool(server, {
211
211
  codeModeBaseUrl,
212
+ codeModeFetch,
212
213
  authStrategy,
213
214
  disableTools,
214
215
  toolDescriptions: effectiveToolDescriptions,
@@ -219,6 +220,7 @@ export function createWixToolkit(options) {
219
220
  !disableTools?.includes('ExecuteWixAPI')) {
220
221
  addExecuteCodeModeTool(server, {
221
222
  codeModeBaseUrl,
223
+ codeModeFetch,
222
224
  authStrategy,
223
225
  disableTools,
224
226
  toolDescriptions: effectiveToolDescriptions,
@@ -317,7 +319,7 @@ export function createWixToolkit(options) {
317
319
  additionalFields = formatToolResultAdditionalFields(cbResult, {
318
320
  returnedRows: toolBiParams.returnedRows,
319
321
  originalLength: toolBiParams.originalLength
320
- });
322
+ }, { name: clientName });
321
323
  }
322
324
  // Panorama: finish or report error
323
325
  if (!isDevEnvironment) {
@@ -183,6 +183,9 @@ export class WixMcpServer extends McpServer {
183
183
  additionalFields = formatToolResultAdditionalFields(cbResult, {
184
184
  returnedRows: toolBiParams.returnedRows,
185
185
  originalLength: toolBiParams.originalLength
186
+ }, {
187
+ name: this.getClientName?.() || this.server.getClientVersion()?.name,
188
+ userAgent: this.getUserAgent?.()
186
189
  });
187
190
  }
188
191
  if (toolSucceeded && !isDevEnvironment) {
@@ -29740,7 +29740,25 @@ function extractText(result) {
29740
29740
  return result.content.filter((content) => content.type === "text" && content.text != null).map((content) => content.text).join("\n");
29741
29741
  }
29742
29742
  var TOOL_RESULT_PREVIEW_MAX_CHARS = 4e3;
29743
- function formatToolResultAdditionalFields(result, extras) {
29743
+ var CODEX_OUTPUT_BUDGET_BYTES = 4e4;
29744
+ function getCodexTruncation(resultText, client) {
29745
+ const isCodex = [client?.name, client?.userAgent].some(
29746
+ (identity) => identity?.toLowerCase().includes("codex")
29747
+ );
29748
+ if (!isCodex) {
29749
+ return void 0;
29750
+ }
29751
+ const resultBytes = new TextEncoder().encode(resultText).length;
29752
+ if (resultBytes <= CODEX_OUTPUT_BUDGET_BYTES) {
29753
+ return void 0;
29754
+ }
29755
+ return {
29756
+ resultBytes,
29757
+ budgetBytes: CODEX_OUTPUT_BUDGET_BYTES,
29758
+ truncatedBytes: resultBytes - CODEX_OUTPUT_BUDGET_BYTES
29759
+ };
29760
+ }
29761
+ function formatToolResultAdditionalFields(result, extras, client) {
29744
29762
  const resultText = extractText(result);
29745
29763
  const contentTypes = [
29746
29764
  ...new Set(
@@ -29757,6 +29775,7 @@ function formatToolResultAdditionalFields(result, extras) {
29757
29775
  resultTextLength: resultText.length,
29758
29776
  resultPreviewTruncated: resultText.length > TOOL_RESULT_PREVIEW_MAX_CHARS,
29759
29777
  resultContentTypes: contentTypes,
29778
+ codexTruncation: getCodexTruncation(resultText, client),
29760
29779
  ...extras
29761
29780
  });
29762
29781
  }
@@ -29938,10 +29957,17 @@ var WixMcpServer = class extends McpServer {
29938
29957
  if (!toolSucceeded) {
29939
29958
  errorBody = extractText(cbResult);
29940
29959
  } else {
29941
- additionalFields = formatToolResultAdditionalFields(cbResult, {
29942
- returnedRows: toolBiParams.returnedRows,
29943
- originalLength: toolBiParams.originalLength
29944
- });
29960
+ additionalFields = formatToolResultAdditionalFields(
29961
+ cbResult,
29962
+ {
29963
+ returnedRows: toolBiParams.returnedRows,
29964
+ originalLength: toolBiParams.originalLength
29965
+ },
29966
+ {
29967
+ name: this.getClientName?.() || this.server.getClientVersion()?.name,
29968
+ userAgent: this.getUserAgent?.()
29969
+ }
29970
+ );
29945
29971
  }
29946
29972
  if (toolSucceeded && !isDevEnvironment) {
29947
29973
  panorama.transaction(toolName).finish({ toolInvocationId });
@@ -31996,6 +32022,22 @@ function renderApps(apps, knownApps) {
31996
32022
  }
31997
32023
  return lines.join("\n");
31998
32024
  }
32025
+ function sanitizeCustomAppName(raw) {
32026
+ return raw.replace(/[\x00-\x1f\x7f]/g, " ").replace(/[`*_[\]|<>]/g, "").replace(/\s+/g, " ").trim().slice(0, 60);
32027
+ }
32028
+ function renderCustomAppsWithSkillsTools(apps) {
32029
+ const relevant = apps.filter((a2) => a2.appId && (a2.hasSkills || a2.hasTools)).sort(
32030
+ (a2, b2) => (a2.appName ?? a2.appId ?? "").localeCompare(b2.appName ?? b2.appId ?? "")
32031
+ );
32032
+ if (!relevant.length) return "";
32033
+ const lines = [];
32034
+ for (const app of relevant) {
32035
+ const sanitizedName = app.appName ? sanitizeCustomAppName(app.appName) : "";
32036
+ const name = sanitizedName || app.appId;
32037
+ lines.push(`- \`${name}\` (ID: \`${app.appId}\`)`);
32038
+ }
32039
+ return lines.join("\n");
32040
+ }
31999
32041
  function renderProperties(props) {
32000
32042
  const sections = [];
32001
32043
  const regionalFormat = [];
@@ -32058,6 +32100,15 @@ function renderSite(site, index, knownApps) {
32058
32100
  lines.push("");
32059
32101
  lines.push(appsContent);
32060
32102
  }
32103
+ const customAppsWithSkillsToolsContent = renderCustomAppsWithSkillsTools(
32104
+ site.customApps ?? []
32105
+ );
32106
+ if (customAppsWithSkillsToolsContent) {
32107
+ lines.push("");
32108
+ lines.push("### Custom Apps with skills and tools");
32109
+ lines.push("");
32110
+ lines.push(customAppsWithSkillsToolsContent);
32111
+ }
32061
32112
  lines.push("");
32062
32113
  lines.push("---");
32063
32114
  lines.push("");
@@ -32860,7 +32911,9 @@ function getErrorMessage(error2) {
32860
32911
  }
32861
32912
  function shouldTryMenuFallbackForDocsRead(error2, articleUrl) {
32862
32913
  const message = getErrorMessage(error2);
32863
- if (!message.includes("404") || !articleUrl.includes("/api-reference/")) {
32914
+ const { pathname } = new URL(articleUrl);
32915
+ const isMenuFallbackUrl = articleUrl.includes("/api-reference/") || pathname.startsWith("/docs/velo");
32916
+ if (!message.includes("404") || !isMenuFallbackUrl) {
32864
32917
  return false;
32865
32918
  }
32866
32919
  return !["This resource is deprecated", "No schema found"].some(
@@ -33513,7 +33566,7 @@ var addDocsTools = (server, allowedTools = [
33513
33566
  content: [
33514
33567
  {
33515
33568
  type: "text",
33516
- text: `Note: "${articleUrl}" is a documentation category, not an article. Showing its menu contents below. For category URLs, use BrowseWixRESTDocsMenu directly next time.
33569
+ text: `Note: "${articleUrl}" is not an article. Showing the closest documentation menu below; read the article you need from its links. For category URLs, use BrowseWixRESTDocsMenu directly next time.
33517
33570
 
33518
33571
  ${text}`
33519
33572
  }
@@ -33605,7 +33658,7 @@ ${text}`
33605
33658
  content: [
33606
33659
  {
33607
33660
  type: "text",
33608
- text: `Note: "${articleUrl}" is a documentation category, not an article. Showing its menu contents below. For category URLs, use BrowseWixRESTDocsMenu directly next time.
33661
+ text: `Note: "${articleUrl}" is not an article. Showing the closest documentation menu below; read the article you need from its links. For category URLs, use BrowseWixRESTDocsMenu directly next time.
33609
33662
 
33610
33663
  ${text}`
33611
33664
  }
@@ -46602,11 +46655,13 @@ function validateExecuteCode(code) {
46602
46655
  }
46603
46656
 
46604
46657
  // src/code-mode/index.ts
46658
+ var defaultCodeModeFetch = (url, init) => fetch(url, init);
46605
46659
  var SEARCH_TOOL_NAME = "SearchWixAPISpec";
46606
46660
  var EXECUTE_TOOL_NAME = "ExecuteWixAPI";
46607
46661
  async function addCodeModeTools(server, options) {
46608
46662
  const {
46609
46663
  codeModeBaseUrl,
46664
+ codeModeFetch,
46610
46665
  authStrategy,
46611
46666
  disableTools = [],
46612
46667
  toolDescriptions,
@@ -46616,6 +46671,7 @@ async function addCodeModeTools(server, options) {
46616
46671
  if (!disableTools.includes(EXECUTE_TOOL_NAME) && authStrategy) {
46617
46672
  addExecuteCodeModeTool(server, {
46618
46673
  codeModeBaseUrl,
46674
+ codeModeFetch,
46619
46675
  authStrategy,
46620
46676
  disableTools,
46621
46677
  toolDescriptions,
@@ -46626,6 +46682,7 @@ async function addCodeModeTools(server, options) {
46626
46682
  function addSearchCodeModeTool(server, options) {
46627
46683
  const {
46628
46684
  codeModeBaseUrl,
46685
+ codeModeFetch,
46629
46686
  authStrategy,
46630
46687
  disableTools = [],
46631
46688
  toolDescriptions,
@@ -46640,12 +46697,14 @@ function addSearchCodeModeTool(server, options) {
46640
46697
  codeModeBaseUrl,
46641
46698
  description,
46642
46699
  maxResponseSize,
46643
- authStrategy
46700
+ authStrategy,
46701
+ codeModeFetch
46644
46702
  );
46645
46703
  }
46646
46704
  function addExecuteCodeModeTool(server, options) {
46647
46705
  const {
46648
46706
  codeModeBaseUrl,
46707
+ codeModeFetch,
46649
46708
  authStrategy,
46650
46709
  visitor,
46651
46710
  disableTools = [],
@@ -46657,6 +46716,7 @@ function addExecuteCodeModeTool(server, options) {
46657
46716
  }
46658
46717
  addExecuteTool(server, {
46659
46718
  codeModeBaseUrl,
46719
+ codeModeFetch,
46660
46720
  authStrategy,
46661
46721
  visitor,
46662
46722
  toolDescriptions,
@@ -46671,7 +46731,7 @@ async function resolveLoopbackAuthorization(authStrategy) {
46671
46731
  return void 0;
46672
46732
  }
46673
46733
  }
46674
- function registerSearchTool(server, codeModeBaseUrl, description, maxResponseSize, authStrategy) {
46734
+ function registerSearchTool(server, codeModeBaseUrl, description, maxResponseSize, authStrategy, codeModeFetch = defaultCodeModeFetch) {
46675
46735
  const searchUrl = `${codeModeBaseUrl}/api/code-mode/search`;
46676
46736
  server.tool(
46677
46737
  SEARCH_TOOL_NAME,
@@ -46691,7 +46751,7 @@ function registerSearchTool(server, codeModeBaseUrl, description, maxResponseSiz
46691
46751
  );
46692
46752
  try {
46693
46753
  const authorization3 = await resolveLoopbackAuthorization(authStrategy);
46694
- const resp = await fetch(searchUrl, {
46754
+ const resp = await codeModeFetch(searchUrl, {
46695
46755
  method: "POST",
46696
46756
  headers: {
46697
46757
  "Content-Type": "application/json",
@@ -46742,8 +46802,8 @@ function registerSearchTool(server, codeModeBaseUrl, description, maxResponseSiz
46742
46802
  }
46743
46803
  );
46744
46804
  }
46745
- async function postExecute(executeUrl, body, authorization3) {
46746
- const resp = await fetch(executeUrl, {
46805
+ async function postExecute(executeUrl, body, authorization3, codeModeFetch = defaultCodeModeFetch) {
46806
+ const resp = await codeModeFetch(executeUrl, {
46747
46807
  method: "POST",
46748
46808
  headers: {
46749
46809
  "Content-Type": "application/json",
@@ -46785,6 +46845,7 @@ function formatExecuteResult(data, maxResponseSize, reportBi) {
46785
46845
  function addExecuteTool(server, options) {
46786
46846
  const {
46787
46847
  codeModeBaseUrl,
46848
+ codeModeFetch,
46788
46849
  authStrategy,
46789
46850
  visitor,
46790
46851
  toolDescriptions,
@@ -46873,7 +46934,8 @@ function addExecuteTool(server, options) {
46873
46934
  accountId: accountHeaders?.["wix-account-id"],
46874
46935
  siteAuthContext
46875
46936
  },
46876
- visitor ? visitorToken : accountHeaders?.Authorization ?? siteHeaders?.Authorization
46937
+ visitor ? visitorToken : accountHeaders?.Authorization ?? siteHeaders?.Authorization,
46938
+ codeModeFetch
46877
46939
  );
46878
46940
  if (data.authErrorStatus && visitor) {
46879
46941
  return executeErrorResult(
@@ -47033,7 +47095,8 @@ function createWixToolkit(options) {
47033
47095
  toolDescriptions,
47034
47096
  toolHints,
47035
47097
  maxResponseSize,
47036
- codeModeBaseUrl = "https://mcp.wix.com"
47098
+ codeModeBaseUrl = "https://mcp.wix.com",
47099
+ codeModeFetch
47037
47100
  } = api;
47038
47101
  const effectiveToolDescriptions = {
47039
47102
  ...descriptionsWithoutReadme,
@@ -47057,6 +47120,7 @@ function createWixToolkit(options) {
47057
47120
  if (requestedTools.has("SearchWixAPISpec") && !disableTools?.includes("SearchWixAPISpec")) {
47058
47121
  addSearchCodeModeTool(server, {
47059
47122
  codeModeBaseUrl,
47123
+ codeModeFetch,
47060
47124
  authStrategy,
47061
47125
  disableTools,
47062
47126
  toolDescriptions: effectiveToolDescriptions,
@@ -47066,6 +47130,7 @@ function createWixToolkit(options) {
47066
47130
  if (requestedTools.has("ExecuteWixAPI") && !disableTools?.includes("ExecuteWixAPI")) {
47067
47131
  addExecuteCodeModeTool(server, {
47068
47132
  codeModeBaseUrl,
47133
+ codeModeFetch,
47069
47134
  authStrategy,
47070
47135
  disableTools,
47071
47136
  toolDescriptions: effectiveToolDescriptions,
@@ -47148,10 +47213,14 @@ function createWixToolkit(options) {
47148
47213
  if (!toolSucceeded) {
47149
47214
  errorBody = extractText(cbResult);
47150
47215
  } else {
47151
- additionalFields = formatToolResultAdditionalFields(cbResult, {
47152
- returnedRows: toolBiParams.returnedRows,
47153
- originalLength: toolBiParams.originalLength
47154
- });
47216
+ additionalFields = formatToolResultAdditionalFields(
47217
+ cbResult,
47218
+ {
47219
+ returnedRows: toolBiParams.returnedRows,
47220
+ originalLength: toolBiParams.originalLength
47221
+ },
47222
+ { name: clientName }
47223
+ );
47155
47224
  }
47156
47225
  if (!isDevEnvironment) {
47157
47226
  if (toolSucceeded) {