coreto-mcp-glpi
Version:
MCP Server para integração CORETO AI com GLPI via tools de tickets
153 lines (135 loc) • 4.49 kB
JavaScript
import { mcpLogger } from '../logger.js'
import { TICKET_STATUS, TICKET_PRIORITY } from '../constants.js'
/**
* Get user tickets from GLPI
* @param {Object} args - Tool arguments
* @param {Object} tenantContext - Tenant context with GLPI connector
* @returns {Object} Tool execution result
*/
async function getUserTickets(args, tenantContext) {
const logger = mcpLogger.child({ tool: 'get_user_tickets' })
try {
const { status = 'open', limit = 10 } = args
const { glpiConnector, tenant_id } = tenantContext
// Validate parameters
const validStatuses = ['open', 'closed', 'all']
if (!validStatuses.includes(status)) {
throw new Error(`Status deve ser: ${validStatuses.join(', ')}`)
}
const limitNumber = parseInt(limit)
if (isNaN(limitNumber) || limitNumber < 1 || limitNumber > 50) {
throw new Error('Limite deve ser um número entre 1 e 50')
}
logger.info('Getting user tickets', {
tenantId: tenant_id,
status,
limit: limitNumber
})
// Build search criteria based on status
let criteria = {}
if (status === 'open') {
// Open tickets: status 1-4 (Novo, Em atendimento, Pendente)
criteria.status = '1,2,3,4'
} else if (status === 'closed') {
// Closed tickets: status 5-6 (Solucionado, Fechado)
criteria.status = '5,6'
}
// 'all' = no status filter
// Search tickets
const tickets = await glpiConnector.searchTickets(criteria)
// Process and format tickets
const processedTickets = tickets
.slice(0, limitNumber)
.map(ticket => {
const formatDate = (dateStr) => {
if (!dateStr || dateStr === '0000-00-00 00:00:00') return null
try {
return new Date(dateStr).toLocaleString('pt-BR')
} catch {
return dateStr
}
}
return {
id: ticket.id,
title: ticket.name || 'Sem título',
status: TICKET_STATUS[ticket.status] || `Status ${ticket.status}`,
status_code: ticket.status,
priority: TICKET_PRIORITY[ticket.priority] || `Prioridade ${ticket.priority}`,
priority_code: ticket.priority,
created_date: formatDate(ticket.date),
last_update: formatDate(ticket.date_mod),
type: ticket.type === 1 ? 'Incidente' : ticket.type === 2 ? 'Solicitação' : 'Outro',
category_id: ticket.itilcategories_id || 0
}
})
// Build summary
const statusCounts = {}
tickets.forEach(ticket => {
const statusName = TICKET_STATUS[ticket.status] || `Status ${ticket.status}`
statusCounts[statusName] = (statusCounts[statusName] || 0) + 1
})
logger.info('User tickets retrieved successfully', {
tenantId: tenant_id,
totalFound: tickets.length,
returned: processedTickets.length,
status
})
return {
success: true,
message: `Encontrados ${tickets.length} chamados (exibindo ${processedTickets.length})`,
data: {
tickets: processedTickets,
summary: {
total_found: tickets.length,
displayed: processedTickets.length,
filter_status: status,
status_counts: statusCounts
}
}
}
} catch (error) {
logger.error('Error getting user tickets', {
tenantId: tenantContext.tenant_id,
error: error.message,
args
})
// Handle specific error cases
if (error.message.includes('GLPI')) {
return {
success: false,
error: `Erro de conexão com GLPI: ${error.message}`,
code: 'GLPI_CONNECTION_ERROR'
}
}
return {
success: false,
error: error.message,
code: 'TICKET_SEARCH_ERROR'
}
}
}
// Tool configuration
const getUserTicketsTool = {
name: 'get_user_tickets',
description: 'Listar chamados do usuário com filtros de status e limite',
inputSchema: {
type: 'object',
properties: {
status: {
type: 'string',
enum: ['open', 'closed', 'all'],
description: 'Filtrar por status: open=em aberto, closed=fechados, all=todos',
default: 'open'
},
limit: {
type: 'number',
description: 'Número máximo de chamados a retornar (1-50)',
default: 10,
minimum: 1,
maximum: 50
}
}
},
handler: getUserTickets
}
export default getUserTicketsTool