From c7d4dbeea6d21a33dc199e929c2d41606e412ded Mon Sep 17 00:00:00 2001 From: josedario87 Date: Tue, 3 Jun 2025 17:04:15 -0600 Subject: [PATCH] agregado datos de log para el MCP --- mcp/index.js | 146 +++++++++++++++++++++++++++++---------------------- 1 file changed, 83 insertions(+), 63 deletions(-) diff --git a/mcp/index.js b/mcp/index.js index 2430bdf..b063bfa 100644 --- a/mcp/index.js +++ b/mcp/index.js @@ -5,11 +5,29 @@ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/ import express from "express"; import { z } from "zod"; +// ------------------------------- +// 🔧 VARIABLES Y HELPERS GLOBALES +// ------------------------------- const API_BASE_URL = process.env.PLANILLA_API_URL || "http://localhost:4000"; -const log = (...args) => console.log("[MCP]", ...args); +const log = (...args) => console.log("[MCP]", ...args); +const bootLog = (...args) => console.log("[BOOT]", ...args); -// 👀 Log de cada request al API -async function fetchJSON(path, options = {}) { +// Imprime detalles del runtime apenas carga el módulo +(function printBootInfo () { + bootLog("Iniciando Planilla MCP v0.1.0"); + bootLog(`Node : ${process.version} (${process.platform}-${process.arch})`); + bootLog(`Working directory : ${process.cwd()}`); + bootLog(`PLANILLA_API_URL : ${API_BASE_URL}`); + bootLog(`PORT (HTTP) : ${process.env.PORT ?? "5000 (default)"}`); + bootLog(`Args : ${process.argv.slice(2).join(" ") || ""}`); + const rss = (process.memoryUsage().rss / 1024 ** 2).toFixed(1); + bootLog(`Boot RSS Memory : ${rss} MB`); +})(); + +// -------------------------------- +// ⛑️ FETCH HELPER CON LOGGING +// -------------------------------- +async function fetchJSON (path, options = {}) { const method = options.method || "GET"; console.log(`[API] ${method} ${API_BASE_URL}${path}`); const res = await fetch(`${API_BASE_URL}${path}`, { @@ -23,8 +41,12 @@ async function fetchJSON(path, options = {}) { return res.json(); } -function createServer() { +// ------------------------------- +// 🏗️ CREACIÓN DEL MCP SERVER +// ------------------------------- +function createServer () { const server = new McpServer({ name: "planilla-mcp", version: "0.1.0" }); + log("Servidor MCP instanciado"); // ----- Resources ----- server.resource("planilla-list", "planilla://list", async (uri) => { @@ -48,21 +70,21 @@ function createServer() { "create-planilla", "Crea una planilla", { - empleado_id: z.number(), - fecha_desde: z.string(), - fecha_hasta: z.string(), - titulo: z.string(), - total: z.number().optional(), - estado: z.string().optional(), - fecha_anulado: z.string().optional(), - creador_id: z.number().optional(), - anulador_id: z.number().optional(), + empleado_id: z.number(), + fecha_desde: z.string(), + fecha_hasta: z.string(), + titulo: z.string(), + total: z.number().optional(), + estado: z.string().optional(), + fecha_anulado:z.string().optional(), + creador_id: z.number().optional(), + anulador_id: z.number().optional(), }, async (params) => { log("Tool invocada", "create-planilla", params); const planilla = await fetchJSON("/api/planillas", { method: "POST", - body: JSON.stringify(params), + body: JSON.stringify(params), }); return { content: [{ type: "text", text: JSON.stringify(planilla) }] }; } @@ -72,21 +94,21 @@ function createServer() { "update-planilla", "Actualiza una planilla existente", { - id: z.number(), - empleado_id: z.number().optional(), - fecha_desde: z.string().optional(), - fecha_hasta: z.string().optional(), - titulo: z.string().optional(), - total: z.number().optional(), - estado: z.string().optional(), - fecha_anulado: z.string().optional(), - anulador_id: z.number().optional(), + id: z.number(), + empleado_id: z.number().optional(), + fecha_desde: z.string().optional(), + fecha_hasta: z.string().optional(), + titulo: z.string().optional(), + total: z.number().optional(), + estado: z.string().optional(), + fecha_anulado:z.string().optional(), + anulador_id: z.number().optional(), }, async ({ id, ...updates }) => { log("Tool invocada", "update-planilla", { id, ...updates }); const planilla = await fetchJSON(`/api/planillas/${id}`, { method: "PUT", - body: JSON.stringify(updates), + body: JSON.stringify(updates), }); return { content: [{ type: "text", text: JSON.stringify(planilla) }] }; } @@ -103,52 +125,50 @@ function createServer() { } ); + server.tool( + "search-planillas", + "Busca planillas. `q` es un texto libre que matchea id, empleado_id, título o estado. Si no mandás ningún argumento devuelve los primeros 100 registros.", + { + q: z.string().optional(), + empleado_id: z.number().optional(), + estado: z.string().optional(), + titulo: z.string().optional(), + fecha_desde_desde: z.string().optional(), + fecha_desde_hasta: z.string().optional(), + fecha_hasta_desde: z.string().optional(), + fecha_hasta_hasta: z.string().optional(), + }, + async (params) => { + log("Tool invocada", "search-planillas", params); + const qs = new URLSearchParams( + Object.entries(params).filter(([, v]) => v !== undefined).map(([k, v]) => [k, String(v)]) + ); -server.tool( - "search-planillas", - "Busca planillas. `q` es un texto libre que matchea id, empleado_id, título o estado. " -+ "Si no mandás ningún argumento devuelve los primeros 100 registros.", - { - q: z.string().optional(), - empleado_id: z.number().optional(), - estado: z.string().optional(), - titulo: z.string().optional(), - fecha_desde_desde: z.string().optional(), - fecha_desde_hasta: z.string().optional(), - fecha_hasta_desde: z.string().optional(), - fecha_hasta_hasta: z.string().optional(), - }, - async (params) => { - log("Tool invocada", "search-planillas", params); - const qs = new URLSearchParams( - Object.entries(params).filter(([, v]) => v !== undefined).map(([k, v]) => [k, String(v)]) - ); - - // 👇 Si no hay filtros, limit=100 - if (qs.toString() === "") qs.append("limit", "100"); - - const planillas = await fetchJSON(`/api/planillas/search?${qs.toString()}`); - return { content: [{ type: "text", text: JSON.stringify(planillas) }] }; - } -); - + // 👇 Si no hay filtros, limit=100 + if (qs.toString() === "") qs.append("limit", "100"); + const planillas = await fetchJSON(`/api/planillas/search?${qs.toString()}`); + return { content: [{ type: "text", text: JSON.stringify(planillas) }] }; + } + ); return server; } - - - -async function main() { +// -------------------------------- +// 🚀 PUNTO DE ENTRADA +// -------------------------------- +async function main () { const useStdio = process.argv.includes("--stdio"); if (useStdio) { - const server = createServer(); + bootLog("Modo transporte: stdio"); + const server = createServer(); const transport = new StdioServerTransport(); await server.connect(transport); console.log("MCP Planilla server listo (stdio)"); } else { - const app = express(); + bootLog("Modo transporte: HTTP streamable"); + const app = express(); app.use(express.json()); // 🌐 Log de cada request HTTP entrante @@ -161,7 +181,7 @@ async function main() { app.post("/mcp", async (req, res) => { try { - const server = createServer(); + const server = createServer(); const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined }); res.on("close", () => { transport.close(); @@ -174,8 +194,8 @@ async function main() { if (!res.headersSent) { res.status(500).json({ jsonrpc: "2.0", - error: { code: -32603, message: "Internal server error" }, - id: null, + error: { code: -32603, message: "Internal server error" }, + id: null, }); } } @@ -185,8 +205,8 @@ async function main() { app[m]("/mcp", (_req, res) => res.status(405).json({ jsonrpc: "2.0", - error: { code: -32000, message: "Method not allowed." }, - id: null, + error: { code: -32000, message: "Method not allowed." }, + id: null, }) ) );