Files
agenticSystem/mcp-server/tools/hooks/index.js
Jordan Diaz 41ebd39908 middleware
2026-04-19 09:18:48 +00:00

145 lines
6.3 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 { pythonGet, pythonPost } from "../helpers/pythonServerClient.js";
import { getCurrentProjectInfo } from "../files/helpers.js";
import { canEditCode } from "../helpers/roleCheck.js";
/**
* Tools para leer/escribir el `middleWare` de hooks globales del layout.
*
* El middleware vive en `layout.json["hooks"][i].middleWare` y determina cuando
* un hook global se ejecuta automaticamente antes de renderizar paginas:
* - [] → solo cuando se llama explicitamente.
* - ["allurls"] → antes de cada URL del sitio.
* - ["<tableName>-<num>", ...] → solo antes de ciertos registros.
*/
function registerGetHookMiddlewareTool(server) {
server.tool(
"get_hook_middleware",
`Check which pages trigger a global hook as middleware. Middleware config determines whether the hook runs automatically BEFORE rendering specific pages (or all pages). Returns the list of middleware entries.
Use this when the user asks about hook behavior or to verify config before changing it.
hookEndPoint format: starts and ends with '/', with '/' as separator. E.g. file "hooks/hooks.parse_styles.php" → endPoint "/hooks/parse_styles/".
Returns:
- middleWare: [] → hook only runs on explicit call (<hook>, Twig filter, CmsApi).
- middleWare: ["allurls"] → runs before every page.
- middleWare: ["cms_apartados-8", ...] → runs before those specific records ("<tableName>-<num>").`,
withAuthParams({
hookEndPoint: z.string().describe('Hook endpoint path, e.g. "/hooks/parse_styles/"'),
}),
{ readOnlyHint: true, destructiveHint: false },
withAuth(async ({ hookEndPoint }, extra) => {
try {
const { projectSlug } = getCurrentProjectInfo();
const result = await pythonGet("/api/creator/hook-middleware", {
project: projectSlug,
endPoint: hookEndPoint,
});
if (!result?.success) {
return {
content: [{
type: "text",
text: JSON.stringify({
success: false,
error: result?.error || "No se pudo leer el middleware",
}),
}],
isError: true,
};
}
return {
content: [{
type: "text",
text: JSON.stringify({
success: true,
exists: !!result.exists,
middleWare: result.middleWare || [],
hookEndPoint,
}, null, 2),
}],
};
} catch (error) {
return handleToolError(error, "get_hook_middleware", { hookEndPoint });
}
})
);
}
function registerSetHookMiddlewareTool(server) {
server.tool(
"set_hook_middleware",
`Configure when a global hook runs automatically (middleware). This updates layout.json['hooks'][i].middleWare for the hook matching hookEndPoint.
Use this AFTER creating or editing a hook file (via acai-write) if the hook should execute BEFORE rendering specific pages. The hook file alone is not enough — the file exists but won't auto-run as middleware without this config.
middleWare values:
- [] → hook runs only when called explicitly (default for new hooks).
- ["allurls"] → runs before every page of the site.
- ["<tableName>-<num>", ...] → runs before specific records. Get num+tableName from the CMS records.
Examples:
- Redirect logic that must run on the homepage only: middleWare=["cms_apartados-2"] (assuming num=2 is home).
- Global analytics injection: middleWare=["allurls"].
- Just a reusable utility hook called from modules/twig: middleWare=[] (default).`,
withAuthParams({
hookEndPoint: z.string().describe('Hook endpoint path, e.g. "/hooks/parse_styles/"'),
middleWare: z.array(z.string()).describe('Array de strings. Vacio, ["allurls"], o ["<tableName>-<num>", ...]'),
}),
{ readOnlyHint: false, destructiveHint: false },
withAuth(async ({ hookEndPoint, middleWare }, extra) => {
try {
const { projectSlug } = getCurrentProjectInfo();
const result = await pythonPost("/api/creator/hook-middleware", {
project: projectSlug,
endPoint: hookEndPoint,
middleWare,
});
if (!result?.success) {
return {
content: [{
type: "text",
text: JSON.stringify({
success: false,
error: result?.error || "No se pudo guardar",
}),
}],
isError: true,
};
}
return {
content: [{
type: "text",
text: JSON.stringify({
success: true,
message: "Middleware actualizado",
middleWare: result.middleWare || [],
hookEndPoint,
}, null, 2),
}],
};
} catch (error) {
return handleToolError(error, "set_hook_middleware", { hookEndPoint, middleWare });
}
})
);
}
/**
* Registra las tools de configuracion de hooks globales.
*
* `get_hook_middleware` es de solo lectura y se registra siempre. El set
* modifica el layout y solo se expone si el rol puede editar codigo — sigue
* el mismo criterio que otras tools de escritura (ver project/index.js).
*/
export function registerHookTools(server) {
registerGetHookMiddlewareTool(server);
if (canEditCode()) {
registerSetHookMiddlewareTool(server);
}
}