Files
agenticSystem/mcp-server/tools/modules/updateMetadata.js

89 lines
4.7 KiB
JavaScript

import { z } from "zod";
import { withAuth } from "../../auth/index.js";
import { withAuthParams } from "../helpers/authSchema.js";
import { handleToolError } from "../helpers/errorHandler.js";
import { pythonPost } from "../helpers/pythonServerClient.js";
import { getCurrentProjectInfo } from "../files/helpers.js";
// Tool: update_module_metadata
// Edita la metadata de builder.json de un modulo (label, description,
// onlyAdminModule, MJMLModule) delegando en /api/modules/update-metadata.
// El id/carpeta del modulo NO se puede renombrar y el endpoint rechaza los
// modulos generados del layout (custom-header/footer[-twig]).
// Claves editables del builder.json. Se envian solo las que llegan definidas,
// de modo que el endpoint hace un merge parcial y no pisa el resto.
const EDITABLE_KEYS = ["label", "description", "onlyAdminModule", "MJMLModule"];
export function registerUpdateModuleMetadataTool(server) {
server.tool(
"update_module_metadata",
`Edit a module's metadata in its builder.json: 'label' (display name shown in the visual builder), 'description' (short help text for editors), 'onlyAdminModule' (true = the module is only visible to admin users in the builder), 'MJMLModule' (true = the module is an email/MJML module).
The module id (its folder name under template/estandar/modulos/) CANNOT be renamed with this tool — there is no rename option at all. Only the fields above change; everything else in builder.json is preserved.
At least one of label, description, onlyAdminModule or MJMLModule is required. Fields you omit are left untouched.
Not applicable to the generated layout modules (custom-header, custom-footer, custom-header-twig, custom-footer-twig): those are artifacts of the global layout and the request will be rejected — use set_layout_field for them.`,
withAuthParams({
module: z.string().min(1).describe("Module id (the folder name under template/estandar/modulos/). Cannot be renamed."),
label: z.string().optional().describe("Display name of the module in the visual builder"),
description: z.string().optional().describe("Short description shown to editors in the builder"),
onlyAdminModule: z.boolean().optional().describe("If true, the module is only visible to admin users in the builder"),
MJMLModule: z.boolean().optional().describe("If true, the module is treated as an email (MJML) module"),
}),
{ readOnlyHint: false, destructiveHint: false },
withAuth(async ({ module, label, description, onlyAdminModule, MJMLModule }, _extra) => {
try {
const provided = { label, description, onlyAdminModule, MJMLModule };
// Validacion temprana: sin ninguna clave editable no tiene
// sentido llamar al endpoint. Ojo con los booleanos false —
// se comprueba `undefined`, no truthiness.
const changedKeys = EDITABLE_KEYS.filter((key) => provided[key] !== undefined);
if (changedKeys.length === 0) {
return handleToolError(
`Nothing to update: provide at least one of ${EDITABLE_KEYS.join(", ")}. The module id cannot be renamed with this tool.`,
"update_module_metadata",
{ module, editableFields: EDITABLE_KEYS }
);
}
const { projectSlug } = getCurrentProjectInfo();
const body = { project: projectSlug, module };
for (const key of changedKeys) body[key] = provided[key];
const result = await pythonPost("/api/modules/update-metadata", body);
if (!result?.success) {
return {
content: [{
type: "text",
text: JSON.stringify({
success: false,
error: result?.error || "Could not update module metadata",
}),
}],
isError: true,
};
}
return {
content: [{
type: "text",
text: JSON.stringify({
success: true,
module: result.module || module,
updatedFields: changedKeys,
metadata: result.metadata || {},
}, null, 2),
}],
};
} catch (error) {
return handleToolError(error, "update_module_metadata", { module });
}
})
);
}