Merge pull request #18 from josedario87/feature/refactor-resources-add-delete-chat
All checks were successful
Deploy conversation layer / deploy (push) Successful in 2m14s
All checks were successful
Deploy conversation layer / deploy (push) Successful in 2m14s
Feature/refactor resources add delete chat
This commit is contained in:
5
Makefile
5
Makefile
@@ -1,4 +1,4 @@
|
||||
.PHONY: sync-from-github sync-to-github chat router agent
|
||||
.PHONY: sync-from-github sync-to-github chat router agent mcp
|
||||
|
||||
# Pull latest changes from the GitHub mirror and push them to Gitea
|
||||
sync-from-github:
|
||||
@@ -18,4 +18,5 @@ router:
|
||||
agent:
|
||||
cd conversation-layer-agent && npm install && npm run dev
|
||||
|
||||
|
||||
mcp:
|
||||
cd mcp && npm install && npm run dev
|
||||
@@ -55,7 +55,7 @@ let mcpTransport: StreamableHTTPClientTransport | undefined;
|
||||
|
||||
async function getMcpClient(): Promise<Client> {
|
||||
if (!mcpClient) {
|
||||
mcpClient = new Client({ name: 'planilla-client', version: '1.0.0' });
|
||||
mcpClient = new Client({ name: 'conversation-layer-mcp-client', version: '1.0.0' });
|
||||
mcpTransport = new StreamableHTTPClientTransport(new URL(MCP_URL));
|
||||
await mcpClient.connect(mcpTransport);
|
||||
}
|
||||
@@ -73,7 +73,7 @@ const systemPromt = `
|
||||
- cuando sos activado, tenes que entender los mensajes del objeto 'conversation' desde el ultimo mensaje pues es el mas nuevo.
|
||||
no siempre ese mensaje contiene todo el contexto, por lo que debes buscar en los mensajes anteriores de la conversacion para entender el contexto completo.
|
||||
- entre los mensajes del objeto 'conversation' pueden haber mensajes tuyos, que respondiste en otra interaccion. recorda que podes aprovechar esta capacidad para hablar con vos mismo en el futuro
|
||||
- tenes la capacidad de llamar de manera secuencial a las herramientas del mcp planilla, eso significa que podes llamar una herramienta, esperar su respuesta y usar esa respuesta para llamar a la siguiente
|
||||
- tenes la capacidad de llamar de manera secuencial a las herramientas del mcp que maneja la conversation-layer, eso significa que podes llamar una herramienta, esperar su respuesta y usar esa respuesta para llamar a la siguiente
|
||||
- la respuesta final siempre la tenes que dar hasta terminar de llamar a todas tus herramientas y obtener un resultado de cada una de ellas para luego usar eso para guiar tu respuesta final
|
||||
|
||||
## tu proposito
|
||||
@@ -95,6 +95,11 @@ const systemPromt = `
|
||||
###aclaratorias
|
||||
- los mensajes e2e son mensajes que utiliza whatsapp para notificar cosas de su sistema, no son mensajes de los usuarios y no debes responderlos.
|
||||
- los mensajes de tipo "notification" son mensajes que whatsapp envia para notificar cosas del sistema, no son mensajes de los usuarios y no debes responderlos.
|
||||
|
||||
### mcp
|
||||
aqui se encuentrar registradas todas las herramientas que podes utilizar, hay dos grandes grupos de herramientas: conversation y whatsapp.
|
||||
- las herramientas de conversation son para manipular los conversation objects que al final es todo lo que todos los agents ven
|
||||
- las herramientas de whatsapp son para manipular las acciones que nucleo toma en su propiia cuenta de whatsapp, por ejemplo enviar mensajes, crear grupos, etc.
|
||||
`;
|
||||
|
||||
const app = express();
|
||||
@@ -110,14 +115,14 @@ app.post('/', async (req, res) => {
|
||||
|
||||
try {
|
||||
const contents = `systemPrompt: ${systemPromt}\nConversation:\n${JSON.stringify(conversation)}\n`;
|
||||
console.log(' contents', contents);
|
||||
// console.log(' contents', contents);
|
||||
|
||||
const config: any = {};
|
||||
// if (message.toLowerCase().includes('/planilla')) {
|
||||
if (true) {
|
||||
console.log('Using Model Context Protocol tools ', MCP_URL);
|
||||
// const client = await getMcpClient();
|
||||
// config.tools = [mcpToTool(client)];
|
||||
const client = await getMcpClient();
|
||||
config.tools = [mcpToTool(client)];
|
||||
}
|
||||
const result = await genAI.models.generateContent({
|
||||
model: 'gemini-2.0-flash',
|
||||
|
||||
@@ -45,12 +45,24 @@ services:
|
||||
environment:
|
||||
- PORT=8001
|
||||
- GEMINI_API_KEY= AIzaSyA9fI1mron-NVgghygu7B4sco7t6raXB8M
|
||||
- MCP_URL= http:planilla-mcp:5000/mcp
|
||||
- MCP_URL=http://conversation-layer-mcp:5000/mcp
|
||||
ports:
|
||||
- "8001:8001"
|
||||
networks:
|
||||
- principal
|
||||
|
||||
conversation-layer-mcp:
|
||||
build: ./mcp
|
||||
image: gitea.interno.com/nucleo000/conversation-layer-mcp:latest
|
||||
container_name: conversation-layer-mcp
|
||||
environment:
|
||||
- PORT=5000
|
||||
- WHATSAPP_ROUTER_URL=http://whatsapp-router:3001
|
||||
ports:
|
||||
- "5000:5000"
|
||||
networks:
|
||||
- principal
|
||||
|
||||
volumes:
|
||||
nucleo_whatsapp_sessions:
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
|
||||
import registerTareas from "./modules/tareas.js";
|
||||
import registerWhatsappIntegration from "./modules/whatsappIntegration.js";
|
||||
import registerConversationIntegration from "./modules/conversationIntegration.js";
|
||||
|
||||
export function createServer() {
|
||||
const server = new McpServer({ name: "planilla-mcp", version: "0.1.0" });
|
||||
const server = new McpServer({ name: "conversation-layer-mcp", version: "0.1.0" });
|
||||
|
||||
registerTareas(server);
|
||||
registerWhatsappIntegration(server);
|
||||
registerConversationIntegration(server);
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/
|
||||
import express from "express";
|
||||
import { createServer } from "./createServer.js";
|
||||
|
||||
console.log('este no tiene variables de entorno, es un servidor MCP Planilla');
|
||||
console.log('este no tiene variables de entorno, es un servidor MCP conversation-layer');
|
||||
|
||||
|
||||
async function main() {
|
||||
@@ -13,14 +13,14 @@ async function main() {
|
||||
const server = createServer();
|
||||
const transport = new StdioServerTransport();
|
||||
await server.connect(transport);
|
||||
console.log("MCP Planilla server listo (stdio)");
|
||||
console.log("MCP conversation-layer server listo (stdio)");
|
||||
} else {
|
||||
// bootLog("Modo transporte: HTTP streamable");
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
|
||||
app.use((req, _res, next) => {
|
||||
console.log(`[HTTP] ${req.method} ${req.originalUrl} ${req.statusCode} ${req.res.body}`);
|
||||
console.log(`[HTTP] ${req.method} ${req.originalUrl} ${req.statusCode}`);
|
||||
next();
|
||||
});
|
||||
|
||||
@@ -59,7 +59,7 @@ async function main() {
|
||||
);
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`MCP Planilla HTTP server listening on port ${port}`);
|
||||
console.log(`MCP conversation-layer HTTP server listening on port ${port}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
export const API_BASE_URL = process.env.PLANILLA_API_URL || "http://localhost:4000";
|
||||
import dotenv from "dotenv";
|
||||
dotenv.config();
|
||||
|
||||
export const API_BASE_URL = process.env.WHATSAPP_ROUTER_URL;
|
||||
|
||||
if (!API_BASE_URL) {
|
||||
console.error("FATAL: WHATSAPP_ROUTER_URL environment variable is not set.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
export async function fetchJSON(path, options = {}) {
|
||||
const method = options.method || "GET";
|
||||
|
||||
69
mcp/modules/conversationIntegration.js
Normal file
69
mcp/modules/conversationIntegration.js
Normal file
@@ -0,0 +1,69 @@
|
||||
// mcp/modules/conversationIntegration.js
|
||||
import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { z } from "zod";
|
||||
import { fetchJSON } from "../lib/api.js";
|
||||
|
||||
const log = (...args) => console.log("[MCP ConversationIntegration]", ...args); // Changed log prefix
|
||||
|
||||
export default function registerConversationIntegration(server) {
|
||||
// --- Conversation Actions ---
|
||||
|
||||
// Tool: conversation.list-conversations
|
||||
server.tool(
|
||||
"conversation.list-conversations",
|
||||
"Retrieves a list of all conversations.",
|
||||
{}, // No input parameters
|
||||
async () => {
|
||||
log("Tool invoked", "conversation.list-conversations");
|
||||
const result = await fetchJSON("/conversations");
|
||||
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
||||
}
|
||||
);
|
||||
|
||||
// Tool: conversation.get-conversation-details
|
||||
server.tool(
|
||||
"conversation.get-conversation-details",
|
||||
"Retrieves details for a specific conversation by its ID.",
|
||||
{
|
||||
id: z.string().describe("ID of the conversation"),
|
||||
},
|
||||
async (params) => {
|
||||
log("Tool invoked", "conversation.get-conversation-details", params);
|
||||
const result = await fetchJSON(`/conversations/${params.id}`);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
||||
}
|
||||
);
|
||||
|
||||
// Tool: conversation.update
|
||||
server.tool(
|
||||
"conversation.update",
|
||||
"Updates/rebuilds a conversation by its ID.",
|
||||
{
|
||||
id: z.string().describe("ID of the conversation to update"),
|
||||
},
|
||||
async (params) => {
|
||||
log("Tool invoked", "conversation.update", params);
|
||||
const result = await fetchJSON(`/conversations/${params.id}/update`, {
|
||||
method: "POST",
|
||||
// No body needed for this specific route as per analysis
|
||||
});
|
||||
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
||||
}
|
||||
);
|
||||
|
||||
// Tool: conversation.delete
|
||||
server.tool(
|
||||
"conversation.delete",
|
||||
"Deletes a conversation by its ID.",
|
||||
{
|
||||
id: z.string().describe("ID of the conversation to delete"),
|
||||
},
|
||||
async (params) => {
|
||||
log("Tool invoked", "conversation.delete", params);
|
||||
const result = await fetchJSON(`/conversations/${params.id}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { z } from "zod";
|
||||
import { fetchJSON } from "../lib/api.js";
|
||||
|
||||
const log = (...args) => console.log("[MCP]", ...args);
|
||||
|
||||
export default function registerTareas(server) {
|
||||
server.resource("tarea-list", "tarea://list", async (uri) => {
|
||||
log("Recurso solicitado", "tarea-list");
|
||||
const tareas = await fetchJSON("/api/tareas");
|
||||
return { contents: [{ uri: uri.href, text: JSON.stringify(tareas) }] };
|
||||
});
|
||||
|
||||
server.resource(
|
||||
"tarea",
|
||||
new ResourceTemplate("tarea://{id}", { list: undefined }),
|
||||
async (uri, { id }) => {
|
||||
log("Recurso solicitado", `tarea ${id}`);
|
||||
const tarea = await fetchJSON(`/api/tareas/${id}`);
|
||||
return { contents: [{ uri: uri.href, text: JSON.stringify(tarea) }] };
|
||||
}
|
||||
);
|
||||
|
||||
server.tool(
|
||||
"create-tarea",
|
||||
"Crea una tarea",
|
||||
{
|
||||
empleado_id: z.number(),
|
||||
planilla_id: z.number().optional(),
|
||||
titulo: z.string(),
|
||||
precio: z.number().optional(),
|
||||
estado: z.string().optional(),
|
||||
observacion: z.string().optional(),
|
||||
fecha: z.string(),
|
||||
tipo: z.string().optional(),
|
||||
fecha_anulado: z.string().optional(),
|
||||
creador_id: z.number().optional(),
|
||||
anulador_id: z.number().optional(),
|
||||
},
|
||||
async (params) => {
|
||||
log("Tool invocada", "create-tarea", params);
|
||||
const tarea = await fetchJSON("/api/tareas", {
|
||||
method: "POST",
|
||||
body: JSON.stringify(params),
|
||||
});
|
||||
return { content: [{ type: "text", text: JSON.stringify(tarea) }] };
|
||||
}
|
||||
);
|
||||
|
||||
server.tool(
|
||||
"update-tarea",
|
||||
"Actualiza una tarea",
|
||||
{
|
||||
id: z.number(),
|
||||
empleado_id: z.number().optional(),
|
||||
planilla_id: z.number().optional(),
|
||||
titulo: z.string().optional(),
|
||||
precio: z.number().optional(),
|
||||
estado: z.string().optional(),
|
||||
observacion: z.string().optional(),
|
||||
fecha: z.string().optional(),
|
||||
tipo: z.string().optional(),
|
||||
fecha_anulado: z.string().optional(),
|
||||
anulador_id: z.number().optional(),
|
||||
},
|
||||
async ({ id, ...updates }) => {
|
||||
log("Tool invocada", "update-tarea", { id, ...updates });
|
||||
const tarea = await fetchJSON(`/api/tareas/${id}`, {
|
||||
method: "PUT",
|
||||
body: JSON.stringify(updates),
|
||||
});
|
||||
return { content: [{ type: "text", text: JSON.stringify(tarea) }] };
|
||||
}
|
||||
);
|
||||
|
||||
server.tool(
|
||||
"delete-tarea",
|
||||
"Elimina una tarea",
|
||||
{ id: z.number() },
|
||||
async ({ id }) => {
|
||||
log("Tool invocada", "delete-tarea", { id });
|
||||
await fetchJSON(`/api/tareas/${id}`, { method: "DELETE" });
|
||||
return { content: [{ type: "text", text: `Tarea ${id} eliminada` }] };
|
||||
}
|
||||
);
|
||||
|
||||
server.tool(
|
||||
"search-tareas",
|
||||
"Busca tareas. `q` matchea id, empleado_id, planilla_id o título. Si no mandas filtros devuelve los primeros 100 registros.",
|
||||
{
|
||||
q: z.string().optional(),
|
||||
empleado_id: z.number().optional(),
|
||||
planilla_id: z.number().optional(),
|
||||
estado: z.string().optional(),
|
||||
titulo: z.string().optional(),
|
||||
fecha_desde: z.string().optional(),
|
||||
fecha_hasta: z.string().optional(),
|
||||
},
|
||||
async (params) => {
|
||||
log("Tool invocada", "search-tareas", params);
|
||||
const qs = new URLSearchParams(
|
||||
Object.entries(params)
|
||||
.filter(([, v]) => v !== undefined)
|
||||
.map(([k, v]) => [k, String(v)])
|
||||
);
|
||||
if (qs.toString() === "") qs.append("limit", "100");
|
||||
const tareas = await fetchJSON(`/api/tareas/search?${qs.toString()}`);
|
||||
return { content: [{ type: "text", text: JSON.stringify(tareas) }] };
|
||||
}
|
||||
);
|
||||
}
|
||||
211
mcp/modules/whatsappIntegration.js
Normal file
211
mcp/modules/whatsappIntegration.js
Normal file
@@ -0,0 +1,211 @@
|
||||
// mcp/modules/whatsappIntegration.js
|
||||
import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { z } from "zod";
|
||||
import { fetchJSON } from "../lib/api.js";
|
||||
|
||||
const log = (...args) => console.log("[MCP WhatsAppIntegration]", ...args); // Changed log prefix
|
||||
|
||||
export default function registerWhatsappIntegration(server) {
|
||||
// --- WhatsApp Actions ---
|
||||
|
||||
// Tool: whatsapp.send-text
|
||||
server.tool(
|
||||
"whatsapp.send-text",
|
||||
"Sends a text message via WhatsApp.",
|
||||
{
|
||||
to: z.string().describe("Recipient ID (e.g., 1234567890@c.us)"),
|
||||
content: z.string().describe("Text message content"),
|
||||
},
|
||||
async (params) => {
|
||||
log("Tool invoked", "whatsapp.send-text", params);
|
||||
const result = await fetchJSON("/send-text", {
|
||||
method: "POST",
|
||||
body: JSON.stringify(params),
|
||||
});
|
||||
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
||||
}
|
||||
);
|
||||
|
||||
// Tool: whatsapp.send-image
|
||||
server.tool(
|
||||
"whatsapp.send-image",
|
||||
"Sends an image message via WhatsApp.",
|
||||
{
|
||||
to: z.string().describe("Recipient ID"),
|
||||
path: z.string().describe("Path or URL to the image"),
|
||||
caption: z.string().optional().describe("Image caption"),
|
||||
},
|
||||
async (params) => {
|
||||
log("Tool invoked", "whatsapp.send-image", params);
|
||||
const result = await fetchJSON("/send-image", {
|
||||
method: "POST",
|
||||
body: JSON.stringify(params),
|
||||
});
|
||||
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
||||
}
|
||||
);
|
||||
|
||||
// Tool: whatsapp.send-file
|
||||
server.tool(
|
||||
"whatsapp.send-file",
|
||||
"Sends a file message via WhatsApp.",
|
||||
{
|
||||
to: z.string().describe("Recipient ID"),
|
||||
path: z.string().describe("Path or URL to the file"),
|
||||
filename: z.string().optional().describe("Name of the file"),
|
||||
caption: z.string().optional().describe("File caption"),
|
||||
},
|
||||
async (params) => {
|
||||
log("Tool invoked", "whatsapp.send-file", params);
|
||||
const result = await fetchJSON("/send-file", {
|
||||
method: "POST",
|
||||
body: JSON.stringify(params),
|
||||
});
|
||||
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
||||
}
|
||||
);
|
||||
|
||||
// Tool: whatsapp.list-chats
|
||||
server.tool(
|
||||
"whatsapp.list-chats",
|
||||
"Retrieves a list of all chats.",
|
||||
{}, // No input parameters
|
||||
async () => {
|
||||
log("Tool invoked", "whatsapp.list-chats");
|
||||
const result = await fetchJSON("/chats");
|
||||
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
||||
}
|
||||
);
|
||||
|
||||
// Tool: whatsapp.get-chat-details
|
||||
server.tool(
|
||||
"whatsapp.get-chat-details",
|
||||
"Retrieves details for a specific chat by its ID.",
|
||||
{
|
||||
chatId: z.string().describe("ID of the chat (e.g., 1234567890@c.us)"),
|
||||
},
|
||||
async (params) => {
|
||||
log("Tool invoked", "whatsapp.get-chat-details", params);
|
||||
const result = await fetchJSON(`/chats/${params.chatId}`);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
||||
}
|
||||
);
|
||||
|
||||
// Tool: whatsapp.get-chat-messages
|
||||
server.tool(
|
||||
"whatsapp.get-chat-messages",
|
||||
"Retrieves messages for a specific chat.",
|
||||
{
|
||||
chatId: z.string().describe("ID of the chat"),
|
||||
limit: z.number().optional().describe("Number of messages to retrieve"),
|
||||
includeMe: z.boolean().optional().describe("Include messages sent by me"),
|
||||
includeNotifications: z.boolean().optional().describe("Include notification messages"),
|
||||
},
|
||||
async ({ chatId, ...queryParams}) => {
|
||||
log("Tool invoked", "whatsapp.get-chat-messages", { chatId, queryParams });
|
||||
const qs = new URLSearchParams(
|
||||
Object.entries(queryParams)
|
||||
.filter(([, v]) => v !== undefined)
|
||||
.map(([k, v]) => [k, String(v)])
|
||||
);
|
||||
const result = await fetchJSON(`/chats/${chatId}/messages?${qs.toString()}`);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
||||
}
|
||||
);
|
||||
|
||||
server.tool(
|
||||
"whatsapp.delete-chat",
|
||||
"Deletes a chat by its ID. (Note: The underlying OpenWA endpoint for this is assumed and might need verification)",
|
||||
{
|
||||
chatId: z.string().describe("ID of the chat to delete (e.g., 1234567890@c.us)"),
|
||||
},
|
||||
async (params) => {
|
||||
log("Tool invoked", "whatsapp.delete-chat", params);
|
||||
const result = await fetchJSON(`/chats/${params.chatId}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
// Consider what a successful deletion should return.
|
||||
// OpenWA might return a success message or just a 200/204.
|
||||
// For now, we'll return the full result.
|
||||
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
||||
}
|
||||
);
|
||||
|
||||
// Tool: whatsapp.create-group
|
||||
server.tool(
|
||||
"whatsapp.create-group",
|
||||
"Creates a new WhatsApp group.",
|
||||
{
|
||||
groupName: z.string().describe("Name of the group"),
|
||||
contactIds: z.array(z.string()).describe("Array of contact IDs to add to the group"),
|
||||
},
|
||||
async (params) => {
|
||||
log("Tool invoked", "whatsapp.create-group", params);
|
||||
const result = await fetchJSON("/groups", {
|
||||
method: "POST",
|
||||
body: JSON.stringify(params),
|
||||
});
|
||||
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
||||
}
|
||||
);
|
||||
|
||||
// Tool: whatsapp.get-contact-details
|
||||
server.tool(
|
||||
"whatsapp.get-contact-details",
|
||||
"Retrieves details for a specific contact by ID.",
|
||||
{
|
||||
contactId: z.string().describe("ID of the contact (e.g., 1234567890@c.us)"),
|
||||
},
|
||||
async (params) => {
|
||||
log("Tool invoked", "whatsapp.get-contact-details", params);
|
||||
const result = await fetchJSON(`/contacts/${params.contactId}`);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
||||
}
|
||||
);
|
||||
|
||||
// Tool: whatsapp.get-blocklist
|
||||
server.tool(
|
||||
"whatsapp.get-blocklist",
|
||||
"Retrieves the blocklist.",
|
||||
{}, // No input parameters
|
||||
async () => {
|
||||
log("Tool invoked", "whatsapp.get-blocklist");
|
||||
const result = await fetchJSON("/blocklist");
|
||||
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
||||
}
|
||||
);
|
||||
|
||||
// Tool: whatsapp.block-contact
|
||||
server.tool(
|
||||
"whatsapp.block-contact",
|
||||
"Blocks a contact on WhatsApp.",
|
||||
{
|
||||
contactId: z.string().describe("ID of the contact to block"),
|
||||
},
|
||||
async (params) => {
|
||||
log("Tool invoked", "whatsapp.block-contact", params);
|
||||
const result = await fetchJSON("/blocklist/block", {
|
||||
method: "POST",
|
||||
body: JSON.stringify(params),
|
||||
});
|
||||
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
||||
}
|
||||
);
|
||||
|
||||
// Tool: whatsapp.unblock-contact
|
||||
server.tool(
|
||||
"whatsapp.unblock-contact",
|
||||
"Unblocks a contact on WhatsApp.",
|
||||
{
|
||||
contactId: z.string().describe("ID of the contact to unblock"),
|
||||
},
|
||||
async (params) => {
|
||||
log("Tool invoked", "whatsapp.unblock-contact", params);
|
||||
const result = await fetchJSON("/blocklist/unblock", {
|
||||
method: "POST",
|
||||
body: JSON.stringify(params),
|
||||
});
|
||||
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
||||
}
|
||||
);
|
||||
}
|
||||
337
mcp/package-lock.json
generated
337
mcp/package-lock.json
generated
@@ -1,19 +1,21 @@
|
||||
{
|
||||
"name": "planilla-mcp-server",
|
||||
"name": "conversation-layer-mcp-server",
|
||||
"version": "0.1.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "planilla-mcp-server",
|
||||
"name": "conversation-layer-mcp-server",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/sdk": "^1.0.0",
|
||||
"dotenv": "^16.5.0",
|
||||
"express": "^5.1.0",
|
||||
"zod": "^3.24.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"node-cron": "^4.0.5",
|
||||
"nodemon": "^3.1.10",
|
||||
"prisma": "^6.8.2"
|
||||
}
|
||||
},
|
||||
@@ -104,6 +106,37 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/anymatch": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
|
||||
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"normalize-path": "^3.0.0",
|
||||
"picomatch": "^2.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/binary-extensions": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
|
||||
"integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz",
|
||||
@@ -124,6 +157,28 @@
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/braces": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
|
||||
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"fill-range": "^7.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/bytes": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
||||
@@ -161,6 +216,36 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/chokidar": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
|
||||
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"anymatch": "~3.1.2",
|
||||
"braces": "~3.0.2",
|
||||
"glob-parent": "~5.1.2",
|
||||
"is-binary-path": "~2.1.0",
|
||||
"is-glob": "~4.0.1",
|
||||
"normalize-path": "~3.0.0",
|
||||
"readdirp": "~3.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.10.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/content-disposition": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz",
|
||||
@@ -248,6 +333,17 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "16.5.0",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz",
|
||||
"integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://dotenvx.com"
|
||||
}
|
||||
},
|
||||
"node_modules/dunder-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||
@@ -393,6 +489,18 @@
|
||||
"express": "^4.11 || 5 || ^5.0.0-beta.1"
|
||||
}
|
||||
},
|
||||
"node_modules/fill-range": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/finalhandler": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz",
|
||||
@@ -427,6 +535,20 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
@@ -473,6 +595,18 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/glob-parent": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-glob": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/gopd": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||
@@ -485,6 +619,15 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/has-symbols": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||
@@ -536,6 +679,12 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ignore-by-default": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
|
||||
"integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
@@ -549,6 +698,48 @@
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/is-binary-path": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"binary-extensions": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/is-extglob": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-glob": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
||||
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-extglob": "^2.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-number": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-promise": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
|
||||
@@ -619,6 +810,18 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
@@ -643,6 +846,43 @@
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/nodemon": {
|
||||
"version": "3.1.10",
|
||||
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.10.tgz",
|
||||
"integrity": "sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"chokidar": "^3.5.2",
|
||||
"debug": "^4",
|
||||
"ignore-by-default": "^1.0.1",
|
||||
"minimatch": "^3.1.2",
|
||||
"pstree.remy": "^1.1.8",
|
||||
"semver": "^7.5.3",
|
||||
"simple-update-notifier": "^2.0.0",
|
||||
"supports-color": "^5.5.0",
|
||||
"touch": "^3.1.0",
|
||||
"undefsafe": "^2.0.5"
|
||||
},
|
||||
"bin": {
|
||||
"nodemon": "bin/nodemon.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/nodemon"
|
||||
}
|
||||
},
|
||||
"node_modules/normalize-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
@@ -698,6 +938,18 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/pkce-challenge": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.0.tgz",
|
||||
@@ -743,6 +995,12 @@
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/pstree.remy": {
|
||||
"version": "1.1.8",
|
||||
"resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
|
||||
"integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.14.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
|
||||
@@ -780,6 +1038,18 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/readdirp": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"picomatch": "^2.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/router": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
|
||||
@@ -828,6 +1098,18 @@
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.7.2",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
|
||||
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/send": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz",
|
||||
@@ -961,6 +1243,18 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/simple-update-notifier": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
|
||||
"integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"semver": "^7.5.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/statuses": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
||||
@@ -969,6 +1263,30 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"has-flag": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-number": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/toidentifier": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
||||
@@ -977,6 +1295,15 @@
|
||||
"node": ">=0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/touch": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz",
|
||||
"integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"nodetouch": "bin/nodetouch.js"
|
||||
}
|
||||
},
|
||||
"node_modules/type-is": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
|
||||
@@ -991,6 +1318,12 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/undefsafe": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
|
||||
"integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/unpipe": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "planilla-mcp-server",
|
||||
"name": "conversation-layer-mcp-server",
|
||||
"version": "0.1.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
@@ -8,11 +8,13 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/sdk": "^1.0.0",
|
||||
"dotenv": "^16.5.0",
|
||||
"express": "^5.1.0",
|
||||
"zod": "^3.24.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"devDependencies": {
|
||||
"node-cron": "^4.0.5",
|
||||
"nodemon": "^3.1.10",
|
||||
"prisma": "^6.8.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,29 @@ router.post('/send-text', async (req: Request, res: Response) => {
|
||||
}
|
||||
});
|
||||
|
||||
// DELETE /chats/:chatId
|
||||
router.delete('/chats/:chatId', async (req: Request, res: Response) => {
|
||||
try {
|
||||
const { chatId } = req.params;
|
||||
if (!chatId) {
|
||||
return res.status(400).json({ error: 'Missing "chatId" in request params' });
|
||||
}
|
||||
// openWaUrl is checked by middleware and available in module scope
|
||||
const result = await whatsappClient.deleteChat(openWaUrl!, chatId);
|
||||
res.json(result);
|
||||
} catch (error: any) {
|
||||
console.error(`[routes/whatsappActions] Error in DELETE /chats/${req.params.chatId}:`, error.message);
|
||||
try {
|
||||
// Attempt to parse error message if it's from whatsappClient's structured error
|
||||
const parsedError = JSON.parse(error.message.substring(error.message.indexOf('{')));
|
||||
return res.status(parsedError.status || 500).json({ error: parsedError });
|
||||
} catch (e) {
|
||||
// If not, send the plain error message
|
||||
res.status(500).json({ error: error.message || 'Failed to delete chat' });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// POST /send-image
|
||||
router.post('/send-image', async (req: Request, res: Response) => {
|
||||
try {
|
||||
|
||||
@@ -42,6 +42,34 @@ export async function sendTextMessage(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a chat by its ID via OpenWA.
|
||||
* (Assumes OpenWA supports a /deleteChat endpoint or similar via POST)
|
||||
* @param openWaUrl The base URL of the OpenWA instance.
|
||||
* @param chatId The ID of the chat to delete.
|
||||
* @returns A promise that resolves to the API response.
|
||||
*/
|
||||
export async function deleteChat(
|
||||
openWaUrl: string,
|
||||
chatId: string
|
||||
): Promise<OpenWAResponse> { // Using OpenWAResponse<any> for now
|
||||
try {
|
||||
// Assuming OpenWA uses a POST request for actions like deleteChat
|
||||
// The actual endpoint name ('/deleteChat') is a guess and might need adjustment.
|
||||
const response = await axios.post(`${openWaUrl}/deleteChat`, {
|
||||
args: { chatId },
|
||||
});
|
||||
return response.data?.response || response.data;
|
||||
} catch (error: any) {
|
||||
console.error(`[whatsappClient] Error deleting chat ${chatId}:`, error.message);
|
||||
if (axios.isAxiosError(error) && error.response) {
|
||||
console.error('[whatsappClient] Axios error details:', error.response.data);
|
||||
throw new Error(`whatsappClient API error (${openWaUrl}/deleteChat): ${error.response.status} - ${JSON.stringify(error.response.data)}`);
|
||||
}
|
||||
throw new Error(`whatsappClient error (${openWaUrl}/deleteChat): ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an image message via OpenWA.
|
||||
* @param openWaUrl The base URL of the OpenWA instance.
|
||||
|
||||
Reference in New Issue
Block a user