UNPKG

@grec0/mcp-s2s-asterisk

Version:

MCP server para asistente telefónico conversacional con Asterisk S2S

259 lines (258 loc) 10.1 kB
// 🛠️ Tool MCP para Asistente Telefónico Conversacional import * as phoneOps from '../operations/realtime-assistant.js'; /** * Realizar una llamada telefónica conversacional */ export async function makePhoneCall(args) { const { usuario, telefono, proposito, contexto, herramientas_personalizadas } = args; const timeout = args.timeout || 40; // Parsear herramientas personalizadas si se proporcionan let herramientasPersonalizadas = []; if (herramientas_personalizadas) { try { herramientasPersonalizadas = JSON.parse(herramientas_personalizadas); } catch (error) { throw new Error(`Error al parsear herramientas personalizadas: ${error instanceof Error ? error.message : 'JSON inválido'}`); } } // Herramientas básicas conversacionales (mínimas) const herramientasBasicas = [ // Herramienta para confirmar información obtenida { name: 'confirmar_informacion', description: 'Confirma información importante obtenida durante la conversación', endpoint: `${process.env.MCP_CALLBACK_URL || 'http://localhost:3000'}/api/phone/confirm-info`, method: 'POST', parameters: [ { name: 'callId', type: 'string', description: 'ID de la llamada', required: true }, { name: 'tipo_informacion', type: 'string', description: 'Tipo de información (contacto, cita, preferencia, etc.)', required: true }, { name: 'datos', type: 'string', description: 'Datos confirmados en formato JSON', required: true }, { name: 'usuario_confirmo', type: 'boolean', description: 'Si el usuario confirmó explícitamente', required: true } ], authentication: { type: 'api_key', header: 'X-MCP-API-Key', key: process.env.MCP_CALLBACK_API_KEY || 'mcp-default-key' } } ]; // Combinar herramientas básicas con personalizadas const todasLasHerramientas = [...herramientasBasicas, ...herramientasPersonalizadas]; // Construir request para el asistente telefónico const request = { usuario, telefono, timeout, proposito, contexto, herramientas: todasLasHerramientas }; // Realizar llamada telefónica return await phoneOps.makePhoneCall(request); } /** * Obtener estado de una llamada */ export async function getCallStatus(args) { const { callId } = args; const status = await phoneOps.getCallStatus(callId); if (!status) { return null; } return { status: status.status, duration: status.duration, lastUpdate: status.lastUpdate, usuario: status.usuario, telefono: status.telefono, proposito: status.proposito }; } /** * Cancelar una llamada en curso */ export async function cancelCall(args) { const { callId } = args; try { const success = await phoneOps.cancelCall(callId); return { success, message: success ? 'Llamada cancelada exitosamente' : 'No se pudo cancelar la llamada' }; } catch (error) { return { success: false, message: error instanceof Error ? error.message : 'Error desconocido al cancelar llamada' }; } } /** * Obtener métricas de llamadas telefónicas */ export async function getCallMetrics() { const metrics = phoneOps.getCallMetrics(); const successRate = metrics.totalCalls > 0 ? (metrics.successfulCalls / metrics.totalCalls) * 100 : 0; return { ...metrics, successRate: Math.round(successRate * 100) / 100 }; } /** * Obtener historial de conversaciones recientes */ export async function getConversationHistory(args) { const limit = args?.limit || 20; return phoneOps.getConversationHistory(limit); } /** * Obtener llamadas activas */ export async function getActiveCalls() { return phoneOps.getActiveCalls().map(call => ({ callId: call.callId, status: call.status, usuario: call.usuario, telefono: call.telefono, proposito: call.proposito, startTime: call.startTime, duration: call.duration })); } /** * Health check del sistema telefónico */ export async function healthCheck() { const health = await phoneOps.healthCheck(); return { ...health, timestamp: new Date().toISOString() }; } /** * Obtener logs del sistema */ export async function getSystemLogs(args) { const limit = args?.limit || 50; const logs = phoneOps.getSystemLogs(limit * 2); // Obtener más para filtrar // Filtrar por nivel y componente si se especifica let filteredLogs = logs; if (args?.level) { filteredLogs = filteredLogs.filter(log => log.level === args.level); } if (args?.component) { filteredLogs = filteredLogs.filter(log => log.component === args.component); } return filteredLogs.slice(0, limit); } /** * Obtener último resultado de conversación procesado para un callId específico */ export async function getLastConversationResult(args) { const { callId } = args; const history = phoneOps.getConversationHistory(100); // Buscar en historial reciente const result = history.find(h => h.callId === callId); if (!result) { return { found: false }; } return { found: true, response_for_user: result.response_for_user, actions_taken: result.actions_taken, processed_at: new Date().toISOString() // Simplificado }; } /** * Crear herramientas HTTP personalizadas para diferentes tipos de conversaciones */ export function createCustomToolsForPurpose(purpose) { const baseUrl = process.env.MCP_CALLBACK_URL || 'http://localhost:3000'; const apiKey = process.env.MCP_CALLBACK_API_KEY || 'mcp-default-key'; const scenarios = { consulta_medica: [ { name: 'registrar_sintomas', description: 'Registra síntomas reportados por el paciente', endpoint: `${baseUrl}/api/medical/symptoms`, method: 'POST', parameters: [ { name: 'callId', type: 'string', description: 'ID de la llamada', required: true }, { name: 'sintomas', type: 'string', description: 'Lista de síntomas', required: true }, { name: 'severidad', type: 'string', description: 'Nivel de severidad (leve, moderado, grave)', required: true }, { name: 'duracion', type: 'string', description: 'Duración de los síntomas', required: false } ], authentication: { type: 'api_key', header: 'X-MCP-API-Key', key: apiKey } } ], soporte_tecnico: [ { name: 'registrar_problema', description: 'Registra el problema técnico reportado', endpoint: `${baseUrl}/api/support/issue`, method: 'POST', parameters: [ { name: 'callId', type: 'string', description: 'ID de la llamada', required: true }, { name: 'tipo_problema', type: 'string', description: 'Categoría del problema', required: true }, { name: 'descripcion', type: 'string', description: 'Descripción detallada', required: true }, { name: 'prioridad', type: 'string', description: 'Prioridad (baja, media, alta, crítica)', required: true } ], authentication: { type: 'api_key', header: 'X-MCP-API-Key', key: apiKey } } ], ventas: [ { name: 'registrar_interes', description: 'Registra el interés del cliente en productos/servicios', endpoint: `${baseUrl}/api/sales/interest`, method: 'POST', parameters: [ { name: 'callId', type: 'string', description: 'ID de la llamada', required: true }, { name: 'producto_interes', type: 'string', description: 'Producto de interés', required: true }, { name: 'nivel_interes', type: 'string', description: 'Nivel de interés (bajo, medio, alto)', required: true }, { name: 'presupuesto', type: 'string', description: 'Rango de presupuesto', required: false }, { name: 'timeframe', type: 'string', description: 'Marco temporal para compra', required: false } ], authentication: { type: 'api_key', header: 'X-MCP-API-Key', key: apiKey } } ], servicio_cliente: [ { name: 'registrar_consulta', description: 'Registra la consulta o queja del cliente', endpoint: `${baseUrl}/api/customer/query`, method: 'POST', parameters: [ { name: 'callId', type: 'string', description: 'ID de la llamada', required: true }, { name: 'tipo_consulta', type: 'string', description: 'Tipo de consulta (queja, sugerencia, consulta)', required: true }, { name: 'departamento', type: 'string', description: 'Departamento responsable', required: true }, { name: 'resolucion_requerida', type: 'boolean', description: 'Si requiere seguimiento', required: true } ], authentication: { type: 'api_key', header: 'X-MCP-API-Key', key: apiKey } } ] }; return scenarios[purpose]; }