From 76221ee1d4a543d0ee0235fb9ac3f0562b8b57a5 Mon Sep 17 00:00:00 2001 From: Jordan Diaz Date: Thu, 13 Aug 2026 15:21:16 +0000 Subject: [PATCH] refactor: set_module_example_data escribe via el server Python MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit La tool llamaba a `action_ws=setStaticVars`, que hace un file_put_contents del builder.json ENTERO en la web para cambiar una sola clave. Eso se saltaba las dos garantias que protegen ese fichero: el bloqueo de escritura de la API de ficheros (BLOCKED_GENERATED_FILENAMES en handlers/files.py) y la allowlist de /api/modules/update-metadata. El riesgo no era teorico. El builder.json es la unica memoria de que variable vive en que columna de builder_custom: si una compilacion caia entre la lectura y la escritura de setStaticVars, esta devolvia el mapeo var->columna anterior encima del recien generado y el contenido guardado quedaba colgado de la variable equivocada en TODAS las paginas que usan el modulo. Ahora delega en /api/modules/update-metadata, que ya es la via quirurgica para la metadata y acepta staticVars en su allowlist (objeto, <=64KB, <=200 claves). Se aprovecha para quitar el volcado del schema y del payload completos por consola en cada llamada. Companion en el repo de Forge: compiler.js reenvia staticVars en cada compilacion. Antes no lo mandaba, asi que el CMS lo tiraba al regenerar el builder.json — solo 5 de 4870 modulos lo conservaban. Co-Authored-By: Claude Opus 5 (1M context) --- mcp-server/tools/modules/setExampleData.js | 56 ++++++++++++---------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/mcp-server/tools/modules/setExampleData.js b/mcp-server/tools/modules/setExampleData.js index 37d638f..7207368 100644 --- a/mcp-server/tools/modules/setExampleData.js +++ b/mcp-server/tools/modules/setExampleData.js @@ -1,7 +1,17 @@ import { z } from "zod"; -import { withAuth, getSessionCredentials, getApiClient, getCommonParams } from "../../auth/index.js"; -import { handleToolError, validateRequired, handleApiResponse } from "../helpers/errorHandler.js"; +import { withAuth } from "../../auth/index.js"; +import { handleToolError, validateRequired } from "../helpers/errorHandler.js"; import { withAuthParams } from "../helpers/authSchema.js"; +import { pythonPost } from "../helpers/pythonServerClient.js"; +import { getCurrentProjectInfo } from "../files/helpers.js"; + +// Antes esta tool llamaba a `action_ws=setStaticVars`, que hacia un +// file_put_contents del builder.json ENTERO en la web para cambiar una sola +// clave. Eso se saltaba el bloqueo de escritura de builder.json y, si caia una +// compilacion entre su lectura y su escritura, devolvia el mapeo var->columna +// anterior encima del recien generado (contenido rotado en todas las paginas +// que usan el modulo). Ahora delega en el endpoint quirurgico de Forge, que +// escribe SOLO las claves de su allowlist. export function registerSetModuleExampleDataTool(server) { server.tool( @@ -50,42 +60,36 @@ Si dudas del formato exacto, lee 'read_doc({ name: "01-builder-fields" })'.`, } } - const credentials = await getSessionCredentials(extra.sessionId); - const client = await getApiClient(extra.sessionId); + console.error(`[set_module_example_data] Module ID: ${moduleId}, vars: ${Object.keys(exampleData).length}`); - // Log data for debugging - console.error(`[set_module_example_data] Module ID: ${moduleId}`); - console.error(`[set_module_example_data] Module Schema:`, JSON.stringify(moduleSchema, null, 2)); - console.error(`[set_module_example_data] Example Data:`, JSON.stringify(exampleData, null, 2)); - - // Prepare payload for setStaticVars action - const payload = await getCommonParams(extra.sessionId, { - action_ws: "setStaticVars", - moduleId: moduleId, + const { projectSlug } = getCurrentProjectInfo(); + const result = await pythonPost("/api/modules/update-metadata", { + project: projectSlug, + module: moduleId, staticVars: exampleData, - schema: moduleSchema }); - console.error(`[set_module_example_data] Full Payload:`, JSON.stringify(payload, null, 2)); - - // Send to viewer_functions - const response = await client.post("/cms/lib/viewer_functions.php", payload); - - console.error(`[set_module_example_data] Response:`, JSON.stringify(response.data, null, 2)); - - // Check for API errors in response - const apiError = handleApiResponse(response.data, 'set_module_example_data'); - if (apiError) return apiError; + if (!result?.success) { + return { + content: [{ + type: "text", + text: JSON.stringify({ + success: false, + error: result?.error || "Could not set module example data", + }), + }], + isError: true, + }; + } return { content: [{ type: "text", text: JSON.stringify({ success: true, message: `Example data set successfully for module '${moduleId}'`, - moduleId: moduleId, + moduleId: result.module || moduleId, dataCount: Object.keys(exampleData).length, schemaVarsCount: moduleSchema?.codeVars ? Object.keys(moduleSchema.codeVars).length : 0, - response: response.data }, null, 2) }], };