[TASK-2026-01-25-ERP-INTEGRACIONES] feat(mcp): Add ERP-specific MCP tools

- Add SalesToolsService with 7 tools (sales summary, reports, top products/customers)
- Add FinancialToolsService with 5 tools (reports, accounts receivable/payable, cash flow, KPIs)
- Add BranchToolsService with 6 tools (branch info, reports, team performance, schedules)
- Register new tool providers in MCP module
- Total: 18 new MCP tools for ERP operations

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Adrian Flores Cortes 2026-01-25 01:49:11 -06:00
parent fd8a0a508e
commit 3bfa564d43
5 changed files with 921 additions and 0 deletions

View File

@ -9,6 +9,9 @@ import {
OrdersToolsService,
CustomersToolsService,
FiadosToolsService,
SalesToolsService,
FinancialToolsService,
BranchToolsService,
} from './tools';
export interface McpModuleOptions {
@ -48,6 +51,9 @@ export class McpModule {
this.toolRegistry.registerProvider(new OrdersToolsService());
this.toolRegistry.registerProvider(new CustomersToolsService());
this.toolRegistry.registerProvider(new FiadosToolsService());
this.toolRegistry.registerProvider(new SalesToolsService());
this.toolRegistry.registerProvider(new FinancialToolsService());
this.toolRegistry.registerProvider(new BranchToolsService());
// MCP Server Service
this.mcpService = new McpServerService(this.toolRegistry, toolLogger);

View File

@ -0,0 +1,292 @@
import {
McpToolProvider,
McpToolDefinition,
McpToolHandler,
McpContext,
} from '../interfaces';
/**
* Branch Tools Service
* Provides MCP tools for branch management and team operations.
* Used by: ADMIN, SUPERVISOR roles
*/
export class BranchToolsService implements McpToolProvider {
getTools(): McpToolDefinition[] {
return [
{
name: 'get_branch_info',
description: 'Obtiene informacion de una sucursal',
category: 'branches',
parameters: {
type: 'object',
properties: {
branch_id: {
type: 'string',
format: 'uuid',
description: 'ID de la sucursal (usa la actual si no se especifica)',
},
},
},
returns: {
type: 'object',
properties: {
id: { type: 'string' },
name: { type: 'string' },
address: { type: 'string' },
phone: { type: 'string' },
operating_hours: { type: 'object' },
},
},
},
{
name: 'get_branch_report',
description: 'Genera reporte de desempeno de sucursal',
category: 'branches',
parameters: {
type: 'object',
properties: {
branch_id: { type: 'string', format: 'uuid' },
period: {
type: 'string',
enum: ['today', 'week', 'month'],
default: 'today',
},
},
},
returns: { type: 'object' },
},
{
name: 'get_team_performance',
description: 'Obtiene metricas de desempeno del equipo',
category: 'branches',
parameters: {
type: 'object',
properties: {
branch_id: { type: 'string', format: 'uuid' },
period: {
type: 'string',
enum: ['today', 'week', 'month'],
default: 'today',
},
},
},
returns: {
type: 'object',
properties: {
team_size: { type: 'number' },
members: { type: 'array' },
},
},
},
{
name: 'get_employee_schedule',
description: 'Obtiene horarios de empleados',
category: 'branches',
parameters: {
type: 'object',
properties: {
branch_id: { type: 'string', format: 'uuid' },
date: { type: 'string', format: 'date' },
employee_id: { type: 'string', format: 'uuid' },
},
},
returns: { type: 'array', items: { type: 'object' } },
},
{
name: 'get_branch_hours',
description: 'Obtiene horarios de atencion de la sucursal',
category: 'branches',
parameters: {
type: 'object',
properties: {
branch_id: { type: 'string', format: 'uuid' },
},
},
returns: {
type: 'object',
properties: {
regular: { type: 'object' },
holidays: { type: 'array' },
},
},
},
{
name: 'get_promotions',
description: 'Obtiene promociones activas',
category: 'branches',
parameters: {
type: 'object',
properties: {
branch_id: { type: 'string', format: 'uuid' },
active_only: { type: 'boolean', default: true },
},
},
returns: { type: 'array', items: { type: 'object' } },
},
];
}
getHandler(toolName: string): McpToolHandler | undefined {
const handlers: Record<string, McpToolHandler> = {
get_branch_info: this.getBranchInfo.bind(this),
get_branch_report: this.getBranchReport.bind(this),
get_team_performance: this.getTeamPerformance.bind(this),
get_employee_schedule: this.getEmployeeSchedule.bind(this),
get_branch_hours: this.getBranchHours.bind(this),
get_promotions: this.getPromotions.bind(this),
};
return handlers[toolName];
}
private async getBranchInfo(
params: { branch_id?: string },
context: McpContext
): Promise<any> {
// TODO: Connect to BranchesService
const branchId = params.branch_id || context.branchId;
return {
id: branchId,
name: 'Sucursal Centro',
code: 'SUC-001',
type: 'store',
address: {
street: 'Av. Principal 123',
city: 'Ciudad de Mexico',
state: 'CDMX',
postal_code: '06600',
},
phone: '+52 55 1234 5678',
email: 'centro@erp.com',
manager: {
id: 'mgr-001',
name: 'Juan Perez',
},
operating_hours: {
monday: { open: '09:00', close: '20:00' },
tuesday: { open: '09:00', close: '20:00' },
wednesday: { open: '09:00', close: '20:00' },
thursday: { open: '09:00', close: '20:00' },
friday: { open: '09:00', close: '20:00' },
saturday: { open: '10:00', close: '18:00' },
sunday: { open: 'closed', close: 'closed' },
},
message: 'Conectar a BranchesService real',
};
}
private async getBranchReport(
params: { branch_id?: string; period?: string },
context: McpContext
): Promise<any> {
// TODO: Connect to ReportsService
return {
branch_id: params.branch_id || context.branchId,
period: params.period || 'today',
sales: {
total: 15750.00,
count: 42,
avg_ticket: 375.00,
},
inventory: {
value: 250000.00,
low_stock_items: 5,
out_of_stock: 2,
},
staff: {
present: 8,
absent: 1,
late: 0,
},
goals: {
sales_target: 20000.00,
progress: 78.75,
},
message: 'Conectar a ReportsService real',
};
}
private async getTeamPerformance(
params: { branch_id?: string; period?: string },
context: McpContext
): Promise<any> {
// TODO: Connect to HRService + SalesService
return {
branch_id: params.branch_id || context.branchId,
period: params.period || 'today',
team_size: 8,
members: [
{ name: 'Ana Garcia', role: 'Vendedor', sales: 4500.00, transactions: 12, avg_ticket: 375.00 },
{ name: 'Carlos Lopez', role: 'Vendedor', sales: 3800.00, transactions: 10, avg_ticket: 380.00 },
{ name: 'Maria Rodriguez', role: 'Cajero', sales: 2500.00, transactions: 8, avg_ticket: 312.50 },
],
top_performer: 'Ana Garcia',
message: 'Conectar a HRService real',
};
}
private async getEmployeeSchedule(
params: { branch_id?: string; date?: string; employee_id?: string },
context: McpContext
): Promise<any[]> {
// TODO: Connect to ScheduleService
const date = params.date || new Date().toISOString().split('T')[0];
return [
{ employee: 'Ana Garcia', shift: 'morning', start: '09:00', end: '15:00', status: 'confirmed' },
{ employee: 'Carlos Lopez', shift: 'afternoon', start: '15:00', end: '21:00', status: 'confirmed' },
{ employee: 'Maria Rodriguez', shift: 'morning', start: '09:00', end: '15:00', status: 'confirmed' },
];
}
private async getBranchHours(
params: { branch_id?: string },
context: McpContext
): Promise<any> {
// TODO: Connect to BranchesService
return {
regular: {
monday: { open: '09:00', close: '20:00' },
tuesday: { open: '09:00', close: '20:00' },
wednesday: { open: '09:00', close: '20:00' },
thursday: { open: '09:00', close: '20:00' },
friday: { open: '09:00', close: '20:00' },
saturday: { open: '10:00', close: '18:00' },
sunday: 'Cerrado',
},
holidays: [
{ date: '2026-01-01', name: 'Año Nuevo', status: 'closed' },
{ date: '2026-02-03', name: 'Dia de la Constitucion', status: 'closed' },
],
next_closed: '2026-02-03',
message: 'Conectar a BranchesService real',
};
}
private async getPromotions(
params: { branch_id?: string; active_only?: boolean },
context: McpContext
): Promise<any[]> {
// TODO: Connect to PromotionsService
return [
{
id: 'promo-001',
name: '2x1 en productos seleccionados',
type: 'bogo',
discount: 50,
start_date: '2026-01-20',
end_date: '2026-01-31',
status: 'active',
applicable_products: ['category:electronics'],
},
{
id: 'promo-002',
name: '10% descuento con tarjeta',
type: 'percentage',
discount: 10,
start_date: '2026-01-01',
end_date: '2026-03-31',
status: 'active',
conditions: ['payment_method:card'],
},
];
}
}

View File

@ -0,0 +1,291 @@
import {
McpToolProvider,
McpToolDefinition,
McpToolHandler,
McpContext,
} from '../interfaces';
/**
* Financial Tools Service
* Provides MCP tools for financial reporting and analysis.
* Used by: ADMIN role only
*/
export class FinancialToolsService implements McpToolProvider {
getTools(): McpToolDefinition[] {
return [
{
name: 'get_financial_report',
description: 'Genera reporte financiero (ingresos, gastos, utilidad)',
category: 'financial',
parameters: {
type: 'object',
properties: {
type: {
type: 'string',
enum: ['income', 'expenses', 'profit', 'summary'],
description: 'Tipo de reporte',
default: 'summary',
},
start_date: {
type: 'string',
format: 'date',
description: 'Fecha inicial',
},
end_date: {
type: 'string',
format: 'date',
description: 'Fecha final',
},
branch_id: {
type: 'string',
format: 'uuid',
description: 'Filtrar por sucursal',
},
},
required: ['type'],
},
returns: { type: 'object' },
},
{
name: 'get_accounts_receivable',
description: 'Obtiene cuentas por cobrar (clientes que deben)',
category: 'financial',
parameters: {
type: 'object',
properties: {
status: {
type: 'string',
enum: ['all', 'current', 'overdue'],
default: 'all',
},
min_amount: { type: 'number' },
limit: { type: 'number', default: 50 },
},
},
returns: {
type: 'object',
properties: {
total: { type: 'number' },
count: { type: 'number' },
accounts: { type: 'array' },
},
},
},
{
name: 'get_accounts_payable',
description: 'Obtiene cuentas por pagar (deudas a proveedores)',
category: 'financial',
parameters: {
type: 'object',
properties: {
status: {
type: 'string',
enum: ['all', 'current', 'overdue'],
default: 'all',
},
due_date_before: { type: 'string', format: 'date' },
limit: { type: 'number', default: 50 },
},
},
returns: {
type: 'object',
properties: {
total: { type: 'number' },
count: { type: 'number' },
accounts: { type: 'array' },
},
},
},
{
name: 'get_cash_flow',
description: 'Analiza flujo de caja (entradas y salidas)',
category: 'financial',
parameters: {
type: 'object',
properties: {
period: {
type: 'string',
enum: ['week', 'month', 'quarter'],
default: 'month',
},
branch_id: { type: 'string', format: 'uuid' },
},
},
returns: {
type: 'object',
properties: {
inflows: { type: 'number' },
outflows: { type: 'number' },
net_flow: { type: 'number' },
by_category: { type: 'array' },
},
},
},
{
name: 'get_kpis',
description: 'Obtiene indicadores clave de desempeno (KPIs)',
category: 'financial',
parameters: {
type: 'object',
properties: {
period: {
type: 'string',
enum: ['month', 'quarter', 'year'],
default: 'month',
},
},
},
returns: {
type: 'object',
properties: {
gross_margin: { type: 'number' },
net_margin: { type: 'number' },
inventory_turnover: { type: 'number' },
avg_collection_days: { type: 'number' },
},
},
},
];
}
getHandler(toolName: string): McpToolHandler | undefined {
const handlers: Record<string, McpToolHandler> = {
get_financial_report: this.getFinancialReport.bind(this),
get_accounts_receivable: this.getAccountsReceivable.bind(this),
get_accounts_payable: this.getAccountsPayable.bind(this),
get_cash_flow: this.getCashFlow.bind(this),
get_kpis: this.getKPIs.bind(this),
};
return handlers[toolName];
}
private async getFinancialReport(
params: { type: string; start_date?: string; end_date?: string; branch_id?: string },
context: McpContext
): Promise<any> {
// TODO: Connect to FinancialService
return {
type: params.type,
period: {
start: params.start_date || new Date().toISOString().split('T')[0],
end: params.end_date || new Date().toISOString().split('T')[0],
},
income: 125000.00,
expenses: 85000.00,
gross_profit: 40000.00,
net_profit: 32000.00,
breakdown: {
sales: 120000.00,
services: 5000.00,
cost_of_goods: 65000.00,
operating_expenses: 20000.00,
taxes: 8000.00,
},
message: 'Conectar a FinancialService real',
};
}
private async getAccountsReceivable(
params: { status?: string; min_amount?: number; limit?: number },
context: McpContext
): Promise<any> {
// TODO: Connect to AccountsService
return {
total: 45000.00,
count: 12,
overdue_total: 15000.00,
overdue_count: 4,
accounts: [
{
customer: 'Cliente A',
amount: 5000.00,
due_date: '2026-01-20',
days_overdue: 5,
status: 'overdue',
},
{
customer: 'Cliente B',
amount: 8000.00,
due_date: '2026-02-01',
days_overdue: 0,
status: 'current',
},
].slice(0, params.limit || 50),
message: 'Conectar a AccountsService real',
};
}
private async getAccountsPayable(
params: { status?: string; due_date_before?: string; limit?: number },
context: McpContext
): Promise<any> {
// TODO: Connect to AccountsService
return {
total: 32000.00,
count: 8,
overdue_total: 5000.00,
overdue_count: 2,
accounts: [
{
supplier: 'Proveedor X',
amount: 12000.00,
due_date: '2026-01-28',
status: 'current',
},
{
supplier: 'Proveedor Y',
amount: 5000.00,
due_date: '2026-01-15',
days_overdue: 10,
status: 'overdue',
},
].slice(0, params.limit || 50),
message: 'Conectar a AccountsService real',
};
}
private async getCashFlow(
params: { period?: string; branch_id?: string },
context: McpContext
): Promise<any> {
// TODO: Connect to FinancialService
return {
period: params.period || 'month',
inflows: 95000.00,
outflows: 72000.00,
net_flow: 23000.00,
opening_balance: 45000.00,
closing_balance: 68000.00,
by_category: [
{ category: 'Ventas', type: 'inflow', amount: 90000.00 },
{ category: 'Cobranzas', type: 'inflow', amount: 5000.00 },
{ category: 'Compras', type: 'outflow', amount: 55000.00 },
{ category: 'Nomina', type: 'outflow', amount: 12000.00 },
{ category: 'Gastos operativos', type: 'outflow', amount: 5000.00 },
],
message: 'Conectar a FinancialService real',
};
}
private async getKPIs(
params: { period?: string },
context: McpContext
): Promise<any> {
// TODO: Connect to AnalyticsService
return {
period: params.period || 'month',
gross_margin: 32.5,
net_margin: 18.2,
inventory_turnover: 4.5,
avg_collection_days: 28,
current_ratio: 1.8,
quick_ratio: 1.2,
return_on_assets: 12.5,
trends: {
gross_margin_change: 2.1,
net_margin_change: 1.5,
},
message: 'Conectar a AnalyticsService real',
};
}
}

View File

@ -3,3 +3,6 @@ export { InventoryToolsService } from './inventory-tools.service';
export { OrdersToolsService } from './orders-tools.service';
export { CustomersToolsService } from './customers-tools.service';
export { FiadosToolsService } from './fiados-tools.service';
export { SalesToolsService } from './sales-tools.service';
export { FinancialToolsService } from './financial-tools.service';
export { BranchToolsService } from './branch-tools.service';

View File

@ -0,0 +1,329 @@
import {
McpToolProvider,
McpToolDefinition,
McpToolHandler,
McpContext,
} from '../interfaces';
/**
* Sales Tools Service
* Provides MCP tools for sales management and reporting.
* Used by: ADMIN, SUPERVISOR, OPERATOR roles
*/
export class SalesToolsService implements McpToolProvider {
getTools(): McpToolDefinition[] {
return [
{
name: 'get_sales_summary',
description: 'Obtiene resumen de ventas del dia, semana o mes',
category: 'sales',
parameters: {
type: 'object',
properties: {
period: {
type: 'string',
enum: ['today', 'week', 'month', 'year'],
description: 'Periodo del resumen',
default: 'today',
},
branch_id: {
type: 'string',
format: 'uuid',
description: 'Filtrar por sucursal (opcional)',
},
},
},
returns: {
type: 'object',
properties: {
total_sales: { type: 'number' },
transaction_count: { type: 'number' },
average_ticket: { type: 'number' },
},
},
},
{
name: 'get_sales_report',
description: 'Genera reporte detallado de ventas por rango de fechas',
category: 'sales',
parameters: {
type: 'object',
properties: {
start_date: {
type: 'string',
format: 'date',
description: 'Fecha inicial (YYYY-MM-DD)',
},
end_date: {
type: 'string',
format: 'date',
description: 'Fecha final (YYYY-MM-DD)',
},
group_by: {
type: 'string',
enum: ['day', 'week', 'month', 'branch', 'category', 'seller'],
description: 'Agrupar resultados por',
default: 'day',
},
branch_id: {
type: 'string',
format: 'uuid',
description: 'Filtrar por sucursal',
},
},
required: ['start_date', 'end_date'],
},
returns: { type: 'array', items: { type: 'object' } },
},
{
name: 'get_top_products',
description: 'Obtiene los productos mas vendidos',
category: 'sales',
parameters: {
type: 'object',
properties: {
period: {
type: 'string',
enum: ['today', 'week', 'month', 'year'],
default: 'month',
},
limit: { type: 'number', default: 10 },
branch_id: { type: 'string', format: 'uuid' },
},
},
returns: { type: 'array', items: { type: 'object' } },
},
{
name: 'get_top_customers',
description: 'Obtiene los clientes con mas compras',
category: 'sales',
parameters: {
type: 'object',
properties: {
period: {
type: 'string',
enum: ['month', 'quarter', 'year'],
default: 'month',
},
limit: { type: 'number', default: 10 },
order_by: {
type: 'string',
enum: ['amount', 'transactions'],
default: 'amount',
},
},
},
returns: { type: 'array', items: { type: 'object' } },
},
{
name: 'get_sales_by_branch',
description: 'Compara ventas entre sucursales',
category: 'sales',
parameters: {
type: 'object',
properties: {
period: {
type: 'string',
enum: ['today', 'week', 'month'],
default: 'today',
},
},
},
returns: { type: 'array', items: { type: 'object' } },
},
{
name: 'get_my_sales',
description: 'Obtiene las ventas del usuario actual (operador)',
category: 'sales',
parameters: {
type: 'object',
properties: {
period: {
type: 'string',
enum: ['today', 'week', 'month'],
default: 'today',
},
},
},
returns: {
type: 'object',
properties: {
total: { type: 'number' },
count: { type: 'number' },
sales: { type: 'array' },
},
},
},
{
name: 'create_sale',
description: 'Registra una nueva venta',
category: 'sales',
parameters: {
type: 'object',
properties: {
items: {
type: 'array',
items: {
type: 'object',
properties: {
product_id: { type: 'string', format: 'uuid' },
quantity: { type: 'number', minimum: 1 },
unit_price: { type: 'number' },
discount: { type: 'number', default: 0 },
},
required: ['product_id', 'quantity'],
},
},
customer_id: { type: 'string', format: 'uuid' },
payment_method: {
type: 'string',
enum: ['cash', 'card', 'transfer', 'credit'],
},
notes: { type: 'string' },
},
required: ['items', 'payment_method'],
},
returns: {
type: 'object',
properties: {
sale_id: { type: 'string' },
total: { type: 'number' },
status: { type: 'string' },
},
},
},
];
}
getHandler(toolName: string): McpToolHandler | undefined {
const handlers: Record<string, McpToolHandler> = {
get_sales_summary: this.getSalesSummary.bind(this),
get_sales_report: this.getSalesReport.bind(this),
get_top_products: this.getTopProducts.bind(this),
get_top_customers: this.getTopCustomers.bind(this),
get_sales_by_branch: this.getSalesByBranch.bind(this),
get_my_sales: this.getMySales.bind(this),
create_sale: this.createSale.bind(this),
};
return handlers[toolName];
}
private async getSalesSummary(
params: { period?: string; branch_id?: string },
context: McpContext
): Promise<any> {
// TODO: Connect to SalesService
const period = params.period || 'today';
return {
period,
branch_id: params.branch_id || 'all',
total_sales: 15750.00,
transaction_count: 42,
average_ticket: 375.00,
comparison: {
previous_period: 14200.00,
change_percent: 10.9,
},
message: 'Conectar a SalesService real',
};
}
private async getSalesReport(
params: { start_date: string; end_date: string; group_by?: string; branch_id?: string },
context: McpContext
): Promise<any[]> {
// TODO: Connect to SalesService
return [
{
date: params.start_date,
total: 5250.00,
count: 15,
avg_ticket: 350.00,
},
{
date: params.end_date,
total: 4800.00,
count: 12,
avg_ticket: 400.00,
},
];
}
private async getTopProducts(
params: { period?: string; limit?: number; branch_id?: string },
context: McpContext
): Promise<any[]> {
// TODO: Connect to SalesService
return [
{ rank: 1, product: 'Producto A', quantity: 150, revenue: 7500.00 },
{ rank: 2, product: 'Producto B', quantity: 120, revenue: 6000.00 },
{ rank: 3, product: 'Producto C', quantity: 100, revenue: 5000.00 },
].slice(0, params.limit || 10);
}
private async getTopCustomers(
params: { period?: string; limit?: number; order_by?: string },
context: McpContext
): Promise<any[]> {
// TODO: Connect to CustomersService
return [
{ rank: 1, customer: 'Cliente A', total: 25000.00, transactions: 15 },
{ rank: 2, customer: 'Cliente B', total: 18000.00, transactions: 12 },
].slice(0, params.limit || 10);
}
private async getSalesByBranch(
params: { period?: string },
context: McpContext
): Promise<any[]> {
// TODO: Connect to SalesService + BranchesService
return [
{ branch: 'Sucursal Centro', total: 8500.00, count: 25 },
{ branch: 'Sucursal Norte', total: 7250.00, count: 17 },
];
}
private async getMySales(
params: { period?: string },
context: McpContext
): Promise<any> {
// TODO: Connect to SalesService with context.userId
return {
user_id: context.userId,
period: params.period || 'today',
total: 3500.00,
count: 8,
sales: [
{ id: 'sale-1', total: 450.00, time: '10:30' },
{ id: 'sale-2', total: 680.00, time: '11:45' },
],
};
}
private async createSale(
params: {
items: Array<{ product_id: string; quantity: number; unit_price?: number; discount?: number }>;
customer_id?: string;
payment_method: string;
notes?: string;
},
context: McpContext
): Promise<any> {
// TODO: Connect to SalesService
const total = params.items.reduce((sum, item) => {
const price = item.unit_price || 100; // Default price for demo
const discount = item.discount || 0;
return sum + (price * item.quantity * (1 - discount / 100));
}, 0);
return {
sale_id: `SALE-${Date.now()}`,
total,
items_count: params.items.length,
payment_method: params.payment_method,
status: 'completed',
created_by: context.userId,
message: 'Conectar a SalesService real',
};
}
}