@ssolis-ti/mcp-compra-agil 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +355 -0
  3. package/dist/api/compra-agil-client.d.ts +268 -0
  4. package/dist/api/compra-agil-client.d.ts.map +1 -0
  5. package/dist/api/compra-agil-client.js +137 -0
  6. package/dist/api/compra-agil-client.js.map +1 -0
  7. package/dist/index.d.ts +3 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +95 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/prompts/analizar-competencia.d.ts +9 -0
  12. package/dist/prompts/analizar-competencia.d.ts.map +1 -0
  13. package/dist/prompts/analizar-competencia.js +50 -0
  14. package/dist/prompts/analizar-competencia.js.map +1 -0
  15. package/dist/prompts/buscar-oportunidades.d.ts +9 -0
  16. package/dist/prompts/buscar-oportunidades.d.ts.map +1 -0
  17. package/dist/prompts/buscar-oportunidades.js +48 -0
  18. package/dist/prompts/buscar-oportunidades.js.map +1 -0
  19. package/dist/resources/compras-template.d.ts +10 -0
  20. package/dist/resources/compras-template.d.ts.map +1 -0
  21. package/dist/resources/compras-template.js +40 -0
  22. package/dist/resources/compras-template.js.map +1 -0
  23. package/dist/resources/documentacion.d.ts +6 -0
  24. package/dist/resources/documentacion.d.ts.map +1 -0
  25. package/dist/resources/documentacion.js +100 -0
  26. package/dist/resources/documentacion.js.map +1 -0
  27. package/dist/resources/estados.d.ts +9 -0
  28. package/dist/resources/estados.d.ts.map +1 -0
  29. package/dist/resources/estados.js +51 -0
  30. package/dist/resources/estados.js.map +1 -0
  31. package/dist/resources/glosario.d.ts +9 -0
  32. package/dist/resources/glosario.d.ts.map +1 -0
  33. package/dist/resources/glosario.js +77 -0
  34. package/dist/resources/glosario.js.map +1 -0
  35. package/dist/resources/regiones.d.ts +9 -0
  36. package/dist/resources/regiones.d.ts.map +1 -0
  37. package/dist/resources/regiones.js +37 -0
  38. package/dist/resources/regiones.js.map +1 -0
  39. package/dist/services/monitor.d.ts +2 -0
  40. package/dist/services/monitor.d.ts.map +1 -0
  41. package/dist/services/monitor.js +87 -0
  42. package/dist/services/monitor.js.map +1 -0
  43. package/dist/tools/auditar-desiertas.d.ts +4 -0
  44. package/dist/tools/auditar-desiertas.d.ts.map +1 -0
  45. package/dist/tools/auditar-desiertas.js +242 -0
  46. package/dist/tools/auditar-desiertas.js.map +1 -0
  47. package/dist/tools/buscar-compras.d.ts +10 -0
  48. package/dist/tools/buscar-compras.d.ts.map +1 -0
  49. package/dist/tools/buscar-compras.js +121 -0
  50. package/dist/tools/buscar-compras.js.map +1 -0
  51. package/dist/tools/detalle-compra.d.ts +10 -0
  52. package/dist/tools/detalle-compra.d.ts.map +1 -0
  53. package/dist/tools/detalle-compra.js +119 -0
  54. package/dist/tools/detalle-compra.js.map +1 -0
  55. package/dist/tools/detalle-oc.d.ts +10 -0
  56. package/dist/tools/detalle-oc.d.ts.map +1 -0
  57. package/dist/tools/detalle-oc.js +81 -0
  58. package/dist/tools/detalle-oc.js.map +1 -0
  59. package/dist/tools/documentos.d.ts +6 -0
  60. package/dist/tools/documentos.d.ts.map +1 -0
  61. package/dist/tools/documentos.js +245 -0
  62. package/dist/tools/documentos.js.map +1 -0
  63. package/dist/tools/estadisticas-uso.d.ts +10 -0
  64. package/dist/tools/estadisticas-uso.d.ts.map +1 -0
  65. package/dist/tools/estadisticas-uso.js +22 -0
  66. package/dist/tools/estadisticas-uso.js.map +1 -0
  67. package/dist/tools/generar-borrador.d.ts +4 -0
  68. package/dist/tools/generar-borrador.d.ts.map +1 -0
  69. package/dist/tools/generar-borrador.js +178 -0
  70. package/dist/tools/generar-borrador.js.map +1 -0
  71. package/dist/tools/monitorear-cambios.d.ts +10 -0
  72. package/dist/tools/monitorear-cambios.d.ts.map +1 -0
  73. package/dist/tools/monitorear-cambios.js +68 -0
  74. package/dist/tools/monitorear-cambios.js.map +1 -0
  75. package/dist/tools/radar-oportunidades.d.ts +4 -0
  76. package/dist/tools/radar-oportunidades.d.ts.map +1 -0
  77. package/dist/tools/radar-oportunidades.js +148 -0
  78. package/dist/tools/radar-oportunidades.js.map +1 -0
  79. package/dist/tools/recomendar-precio.d.ts +4 -0
  80. package/dist/tools/recomendar-precio.d.ts.map +1 -0
  81. package/dist/tools/recomendar-precio.js +180 -0
  82. package/dist/tools/recomendar-precio.js.map +1 -0
  83. package/dist/tools/verificar-oc.d.ts +13 -0
  84. package/dist/tools/verificar-oc.d.ts.map +1 -0
  85. package/dist/tools/verificar-oc.js +94 -0
  86. package/dist/tools/verificar-oc.js.map +1 -0
  87. package/dist/utils/env-loader.d.ts +6 -0
  88. package/dist/utils/env-loader.d.ts.map +1 -0
  89. package/dist/utils/env-loader.js +35 -0
  90. package/dist/utils/env-loader.js.map +1 -0
  91. package/dist/utils/error-handler.d.ts +28 -0
  92. package/dist/utils/error-handler.d.ts.map +1 -0
  93. package/dist/utils/error-handler.js +74 -0
  94. package/dist/utils/error-handler.js.map +1 -0
  95. package/dist/utils/logger.d.ts +15 -0
  96. package/dist/utils/logger.d.ts.map +1 -0
  97. package/dist/utils/logger.js +48 -0
  98. package/dist/utils/logger.js.map +1 -0
  99. package/dist/utils/rate-limiter.d.ts +39 -0
  100. package/dist/utils/rate-limiter.d.ts.map +1 -0
  101. package/dist/utils/rate-limiter.js +82 -0
  102. package/dist/utils/rate-limiter.js.map +1 -0
  103. package/package.json +53 -0
@@ -0,0 +1,180 @@
1
+ import { z } from 'zod';
2
+ import { CompraAgilApiError } from '../utils/error-handler.js';
3
+ import { logger } from '../utils/logger.js';
4
+ const TOOL_NAME = 'recomendar_precio_ganador';
5
+ const TOOL_DESCRIPTION = `Analiza procesos históricos similares de Compra Ágil que ya fueron cerrados y adjudicados para estimar y sugerir un precio unitario o total óptimo y competitivo para postular.
6
+ Admite ingresar el código de una compra activa para extraer automáticamente las palabras clave o un término de búsqueda genérico.
7
+ Nota: Realiza consultas en paralelo acotadas por el rate limiter.`;
8
+ const inputSchema = {
9
+ codigo_compra: z.string().optional().describe('Código de la Compra Ágil activa para analizar (ej: "1057539-228-COT26"). Opcional si se especifica "q".'),
10
+ q: z.string().optional().describe('Término de búsqueda de producto/servicio a cotizar (ej: "resmas papel", "soporte computadores"). Opcional si se especifica "codigo_compra".'),
11
+ region: z.string().optional().describe('Código de la región para acotar el análisis histórico (1-16). Ej: "13" para Metropolitana.'),
12
+ limite_analisis: z.number().min(1).max(8).default(5).optional().describe('Cantidad máxima de procesos históricos a auditar (1-8, default 5) para no agotar la cuota de la API.'),
13
+ };
14
+ export function registerRecomendarPrecio(server, client) {
15
+ server.registerTool(TOOL_NAME, {
16
+ description: TOOL_DESCRIPTION,
17
+ inputSchema: inputSchema,
18
+ }, async (args) => {
19
+ try {
20
+ let keyword = args.q || '';
21
+ let region = args.region || '';
22
+ let targetProductDetail = '';
23
+ // 1. Si hay un código de compra activa, obtener su detalle para sacar las palabras clave
24
+ if (args.codigo_compra) {
25
+ logger.info(`recomendar_precio_ganador: Obteniendo detalle de compra activa ${args.codigo_compra}`);
26
+ const activeDetail = await client.detalle(args.codigo_compra);
27
+ if (activeDetail.productos_solicitados && activeDetail.productos_solicitados.length > 0) {
28
+ const firstProd = activeDetail.productos_solicitados[0];
29
+ keyword = firstProd.nombre;
30
+ targetProductDetail = `Producto solicitado en la compra activa: "${firstProd.nombre}" (Cantidad: ${firstProd.cantidad} ${firstProd.unidad_medida})`;
31
+ }
32
+ else {
33
+ keyword = activeDetail.nombre;
34
+ targetProductDetail = `Proceso activo: "${activeDetail.nombre}"`;
35
+ }
36
+ // Si no se especificó región en los argumentos, usar la región de la compra activa
37
+ if (!region && activeDetail.institucion.region !== null) {
38
+ region = String(activeDetail.institucion.region);
39
+ }
40
+ }
41
+ if (!keyword) {
42
+ return {
43
+ content: [{
44
+ type: 'text',
45
+ text: 'Error de validación: Debes proporcionar "codigo_compra" (para buscar palabras clave automáticamente) o un término de búsqueda "q".',
46
+ }],
47
+ isError: true,
48
+ };
49
+ }
50
+ // 2. Buscar procesos históricos cerrados que ya tengan proveedor seleccionado
51
+ logger.info(`recomendar_precio_ganador: Buscando procesos cerrados adjudicados para "${keyword}" en región "${region || 'Todas'}"`);
52
+ const limit = args.limite_analisis || 5;
53
+ const searchResponse = await client.buscar({
54
+ q: keyword,
55
+ estado: 'proveedor_seleccionado',
56
+ region: region || undefined,
57
+ tamano_pagina: 10, // API v2 requiere mínimo 10
58
+ numero_pagina: 1,
59
+ });
60
+ if (!searchResponse.items || searchResponse.items.length === 0) {
61
+ return {
62
+ content: [{
63
+ type: 'text',
64
+ text: `No se encontraron procesos históricos cerrados en estado "proveedor_seleccionado" que coincidan con la búsqueda "${keyword}" en la región ${region || 'todas'}. No hay datos históricos suficientes para realizar una recomendación de precios.`,
65
+ }],
66
+ };
67
+ }
68
+ // 3. Consultar en paralelo (acotado por el limitador interno de la clase client) los detalles para obtener el ganador
69
+ const prices = [];
70
+ const processedItems = [];
71
+ const itemsToProcess = searchResponse.items.slice(0, limit);
72
+ logger.info(`recomendar_precio_ganador: Analizando detalles de ${itemsToProcess.length} procesos adjudicados`);
73
+ for (const item of itemsToProcess) {
74
+ try {
75
+ const detail = await client.detalle(item.codigo);
76
+ // Buscar al adjudicado/ganador
77
+ const winner = detail.proveedores_cotizando?.find(prov => {
78
+ if (prov.proveedor_seleccionado === true || prov.proveedor_seleccionado === 1)
79
+ return true;
80
+ if (prov.seleccion && prov.seleccion.proveedor_seleccionado === true)
81
+ return true;
82
+ return false;
83
+ });
84
+ if (winner) {
85
+ const totalNeto = winner.valor_neto || winner.monto_total || 0;
86
+ let unitPrice = null;
87
+ // Intentar extraer el precio unitario del producto cotizado
88
+ if (winner.productos_cotizados && winner.productos_cotizados.length === 1) {
89
+ unitPrice = winner.productos_cotizados[0].precio_unitario;
90
+ }
91
+ else if (winner.productos_cotizados && winner.productos_cotizados.length > 1) {
92
+ // Buscar el producto cotizado que más coincida con la keyword original
93
+ const matchedProd = winner.productos_cotizados.find(p => p.nombre_producto.toLowerCase().includes(keyword.toLowerCase()));
94
+ if (matchedProd) {
95
+ unitPrice = matchedProd.precio_unitario;
96
+ }
97
+ else {
98
+ // Fallback: usar el precio del primer item
99
+ unitPrice = winner.productos_cotizados[0].precio_unitario;
100
+ }
101
+ }
102
+ const priceValue = unitPrice || totalNeto;
103
+ if (priceValue > 0) {
104
+ prices.push(priceValue);
105
+ }
106
+ processedItems.push({
107
+ codigo: item.codigo,
108
+ institucion: item.institucion.organismo_comprador,
109
+ fecha_cierre: item.fechas.fecha_cierre,
110
+ ganador: winner.razon_social,
111
+ es_emt: winner.es_emt,
112
+ monto_total_adjudicado: winner.monto_total,
113
+ precio_unitario_adjudicado: unitPrice,
114
+ criterio_seleccion: winner.seleccion?.criterio_seleccion || 'No especificado',
115
+ });
116
+ }
117
+ }
118
+ catch (detailError) {
119
+ logger.warn(`recomendar_precio_ganador: Error al consultar detalle de ${item.codigo}: ${String(detailError)}`);
120
+ }
121
+ }
122
+ if (prices.length === 0) {
123
+ return {
124
+ content: [{
125
+ type: 'text',
126
+ text: `Se encontraron ${searchResponse.items.length} procesos históricos que coinciden con "${keyword}", pero no se pudo extraer información económica de los ganadores debido a datos incompletos en la API.`,
127
+ }],
128
+ };
129
+ }
130
+ // 4. Calcular estadísticas
131
+ prices.sort((a, b) => a - b);
132
+ const min = prices[0];
133
+ const max = prices[prices.length - 1];
134
+ const sum = prices.reduce((acc, val) => acc + val, 0);
135
+ const avg = Math.round(sum / prices.length);
136
+ // Mediana
137
+ const mid = Math.floor(prices.length / 2);
138
+ const median = prices.length % 2 !== 0 ? prices[mid] : Math.round((prices[mid - 1] + prices[mid]) / 2);
139
+ // 5. Sugerir precio competitivo (5% por debajo del promedio como referencia competitiva, acotada por el mínimo)
140
+ let recommended = Math.round(avg * 0.95);
141
+ if (recommended < min) {
142
+ recommended = min;
143
+ }
144
+ const result = {
145
+ proceso_activo: targetProductDetail || undefined,
146
+ termino_clave_utilizado: keyword,
147
+ region_analisis: region ? `Región ${region}` : 'Todas las regiones',
148
+ procesos_analizados_exitosamente: prices.length,
149
+ estadisticas_precios: {
150
+ minimo_historico: min,
151
+ maximo_historico: max,
152
+ promedio_historico: avg,
153
+ mediana_historica: median,
154
+ },
155
+ sugerencia_de_precio_competitivo: recommended,
156
+ rango_sugerido: {
157
+ min: Math.round(recommended * 0.95),
158
+ max: Math.round(recommended * 1.05),
159
+ },
160
+ detalle_de_casos_historicos: processedItems,
161
+ };
162
+ return {
163
+ content: [{
164
+ type: 'text',
165
+ text: JSON.stringify(result, null, 2),
166
+ }],
167
+ };
168
+ }
169
+ catch (error) {
170
+ const message = error instanceof CompraAgilApiError
171
+ ? error.actionableMessage
172
+ : `Error inesperado al recomendar precio: ${String(error)}`;
173
+ return {
174
+ content: [{ type: 'text', text: message }],
175
+ isError: true,
176
+ };
177
+ }
178
+ });
179
+ }
180
+ //# sourceMappingURL=recomendar-precio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recomendar-precio.js","sourceRoot":"","sources":["../../src/tools/recomendar-precio.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Tool: verificar_orden_compra
3
+ *
4
+ * Verifica si una Compra Ágil ya tiene una Orden de Compra (OC) emitida.
5
+ * Resuelve la limitación documentada donde el estado "oc_emitida" no aparece
6
+ * en la práctica y el campo codigo_orden_compra retorna null incluso con OC emitida.
7
+ *
8
+ * Implementa la lógica del Ejemplo 8.6 de la documentación oficial.
9
+ */
10
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
11
+ import { CompraAgilClient } from '../api/compra-agil-client.js';
12
+ export declare function registerVerificarOC(server: McpServer, client: CompraAgilClient): void;
13
+ //# sourceMappingURL=verificar-oc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verificar-oc.d.ts","sourceRoot":"","sources":["../../src/tools/verificar-oc.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAgBhE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,gBAAgB,GAAG,IAAI,CA+ErF"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Tool: verificar_orden_compra
3
+ *
4
+ * Verifica si una Compra Ágil ya tiene una Orden de Compra (OC) emitida.
5
+ * Resuelve la limitación documentada donde el estado "oc_emitida" no aparece
6
+ * en la práctica y el campo codigo_orden_compra retorna null incluso con OC emitida.
7
+ *
8
+ * Implementa la lógica del Ejemplo 8.6 de la documentación oficial.
9
+ */
10
+ import { z } from 'zod';
11
+ import { CompraAgilApiError } from '../utils/error-handler.js';
12
+ import { logger } from '../utils/logger.js';
13
+ const TOOL_NAME = 'verificar_orden_compra';
14
+ const TOOL_DESCRIPTION = `Verifica si una Compra Ágil específica ya tiene una Orden de Compra (OC) emitida.
15
+ IMPORTANTE: El estado "oc_emitida" de la API NO funciona en la práctica. Esta herramienta resuelve esa limitación
16
+ consultando el detalle del proceso y cruzando con la API de Órdenes de Compra de Mercado Público si existe un id_orden_compra.`;
17
+ const inputSchema = {
18
+ codigo: z.string().describe('Código único de la Compra Ágil a verificar. Formato: XXXXXX-YYY-COTXX. Ej: "1057539-228-COT26".'),
19
+ };
20
+ export function registerVerificarOC(server, client) {
21
+ server.registerTool(TOOL_NAME, {
22
+ description: TOOL_DESCRIPTION,
23
+ inputSchema: inputSchema,
24
+ }, async (args) => {
25
+ try {
26
+ const detalle = await client.detalle(args.codigo);
27
+ const idOrdenCompra = detalle.id_orden_compra ?? detalle.orden_compra?.id_orden_compra ?? null;
28
+ const idOc = detalle.orden_compra?.id_oc ?? null;
29
+ const tieneOC = idOrdenCompra !== null && idOrdenCompra !== undefined;
30
+ let detalleOCInfo = null;
31
+ if (tieneOC) {
32
+ try {
33
+ const ocResponse = await client.obtenerDetalleOC(idOrdenCompra);
34
+ if (ocResponse.Listado && ocResponse.Listado.length > 0) {
35
+ const oc = ocResponse.Listado[0];
36
+ detalleOCInfo = {
37
+ codigo_oc: oc.Codigo,
38
+ nombre_oc: oc.Nombre,
39
+ estado_oc: oc.Estado,
40
+ codigo_estado_oc: oc.CodigoEstado,
41
+ monto_total: oc.Total,
42
+ fecha_creacion: oc.FechaCreacion,
43
+ fecha_aceptacion: oc.FechaAceptacion,
44
+ };
45
+ }
46
+ }
47
+ catch (e) {
48
+ logger.warn(`No se pudo obtener el detalle de la OC ${idOrdenCompra} desde la API: ${String(e)}`);
49
+ }
50
+ }
51
+ const result = {
52
+ codigo: detalle.codigo,
53
+ nombre: detalle.nombre,
54
+ estado_actual: detalle.estado.glosa,
55
+ convocatoria: detalle.convocatoria.descripcion,
56
+ verificacion_oc: {
57
+ tiene_orden_compra: tieneOC,
58
+ id_orden_compra: idOrdenCompra,
59
+ id_oc: idOc,
60
+ codigo_orden_compra: detalleOCInfo?.codigo_oc ?? detalle.orden_compra?.codigo_orden_compra ?? null,
61
+ estado_orden_compra: detalleOCInfo?.estado_oc ?? detalle.orden_compra?.estado_orden_compra ?? null,
62
+ detalle_orden: detalleOCInfo,
63
+ nota: tieneOC
64
+ ? `La OC fue emitida. Código: ${detalleOCInfo?.codigo_oc ?? 'Desconocido'}. Usa la herramienta obtener_detalle_orden_compra para profundizar.`
65
+ : 'No se ha emitido una Orden de Compra para esta Compra Ágil aún.',
66
+ },
67
+ proveedor_seleccionado: detalle.proveedores_cotizando
68
+ .filter((p) => p.proveedor_seleccionado === 1 || p.proveedor_seleccionado === true || p.seleccion?.proveedor_seleccionado === true || p.estado_por_comprador === '1')
69
+ .map((p) => ({
70
+ rut: p.rut_proveedor,
71
+ razon_social: p.razon_social,
72
+ monto_total: p.monto_total,
73
+ })),
74
+ presupuesto_clp: detalle.presupuesto.monto_disponible_clp,
75
+ };
76
+ return {
77
+ content: [{
78
+ type: 'text',
79
+ text: JSON.stringify(result, null, 2),
80
+ }],
81
+ };
82
+ }
83
+ catch (error) {
84
+ const message = error instanceof CompraAgilApiError
85
+ ? error.actionableMessage
86
+ : `Error inesperado: ${String(error)}`;
87
+ return {
88
+ content: [{ type: 'text', text: message }],
89
+ isError: true,
90
+ };
91
+ }
92
+ });
93
+ }
94
+ //# sourceMappingURL=verificar-oc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verificar-oc.js","sourceRoot":"","sources":["../../src/tools/verificar-oc.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Carga de forma manual las variables de entorno de un archivo `.env` local.
3
+ * Útil para entornos MCP que no soportan dotenv nativamente o se ejecutan sin variables externas predefinidas.
4
+ */
5
+ export declare function loadEnvManual(): void;
6
+ //# sourceMappingURL=env-loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-loader.d.ts","sourceRoot":"","sources":["../../src/utils/env-loader.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,wBAAgB,aAAa,IAAI,IAAI,CA2BpC"}
@@ -0,0 +1,35 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ /**
4
+ * Carga de forma manual las variables de entorno de un archivo `.env` local.
5
+ * Útil para entornos MCP que no soportan dotenv nativamente o se ejecutan sin variables externas predefinidas.
6
+ */
7
+ export function loadEnvManual() {
8
+ try {
9
+ const envPath = path.resolve(process.cwd(), '.env');
10
+ if (fs.existsSync(envPath)) {
11
+ const content = fs.readFileSync(envPath, 'utf8');
12
+ for (const line of content.split('\n')) {
13
+ const trimmed = line.trim();
14
+ // Ignorar líneas vacías y comentarios
15
+ if (trimmed && !trimmed.startsWith('#')) {
16
+ const parts = trimmed.split('=');
17
+ const key = parts[0]?.trim();
18
+ const value = parts.slice(1).join('=').trim();
19
+ if (key && value) {
20
+ // Eliminar comillas dobles o simples que encierran el valor
21
+ const cleanValue = value.replace(/^['"]|['"]$/g, '');
22
+ // Solo asignar si no está definida previamente a nivel de sistema para respetar prioridades
23
+ if (process.env[key] === undefined) {
24
+ process.env[key] = cleanValue;
25
+ }
26
+ }
27
+ }
28
+ }
29
+ }
30
+ }
31
+ catch (e) {
32
+ console.error('Error al parsear el archivo .env de forma manual:', e);
33
+ }
34
+ }
35
+ //# sourceMappingURL=env-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-loader.js","sourceRoot":"","sources":["../../src/utils/env-loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB;;;GAGG;AACH,MAAM,UAAU,aAAa;IAC3B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,CAAC;QACpD,IAAI,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC3B,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YACjD,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBACvC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;gBAC5B,sCAAsC;gBACtC,IAAI,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;oBACxC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;oBACjC,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;oBAC7B,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;oBAC9C,IAAI,GAAG,IAAI,KAAK,EAAE,CAAC;wBACjB,4DAA4D;wBAC5D,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;wBAErD,4FAA4F;wBAC5F,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE,CAAC;4BACnC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC;wBAChC,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CAAC,mDAAmD,EAAE,CAAC,CAAC,CAAC;IACxE,CAAC;AACH,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Traductor de errores HTTP de la API Compra Ágil a mensajes accionables para LLMs.
3
+ *
4
+ * Cada mensaje está redactado para que un agente de IA entienda
5
+ * exactamente qué salió mal y qué acción tomar.
6
+ */
7
+ export interface ApiError {
8
+ codigo: string;
9
+ mensaje: string;
10
+ detalle: string | null;
11
+ }
12
+ export interface ApiErrorResponse {
13
+ success: 'NOK';
14
+ trace: string | null;
15
+ payload: null;
16
+ errors: ApiError[];
17
+ }
18
+ export declare class CompraAgilApiError extends Error {
19
+ readonly httpStatus: number;
20
+ readonly apiErrors: ApiError[];
21
+ readonly actionableMessage: string;
22
+ constructor(httpStatus: number, apiErrors?: ApiError[]);
23
+ }
24
+ /**
25
+ * Parsea la respuesta de error de la API y lanza una excepción tipada.
26
+ */
27
+ export declare function handleApiResponse(response: Response): Promise<unknown>;
28
+ //# sourceMappingURL=error-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-handler.d.ts","sourceRoot":"","sources":["../../src/utils/error-handler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,KAAK,CAAC;IACf,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,EAAE,IAAI,CAAC;IACd,MAAM,EAAE,QAAQ,EAAE,CAAC;CACpB;AAED,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,SAAgB,UAAU,EAAE,MAAM,CAAC;IACnC,SAAgB,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtC,SAAgB,iBAAiB,EAAE,MAAM,CAAC;gBAE9B,UAAU,EAAE,MAAM,EAAE,SAAS,GAAE,QAAQ,EAAO;CAQ3D;AAqCD;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,CAoB5E"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Traductor de errores HTTP de la API Compra Ágil a mensajes accionables para LLMs.
3
+ *
4
+ * Cada mensaje está redactado para que un agente de IA entienda
5
+ * exactamente qué salió mal y qué acción tomar.
6
+ */
7
+ export class CompraAgilApiError extends Error {
8
+ httpStatus;
9
+ apiErrors;
10
+ actionableMessage;
11
+ constructor(httpStatus, apiErrors = []) {
12
+ const actionable = getActionableMessage(httpStatus, apiErrors);
13
+ super(actionable);
14
+ this.name = 'CompraAgilApiError';
15
+ this.httpStatus = httpStatus;
16
+ this.apiErrors = apiErrors;
17
+ this.actionableMessage = actionable;
18
+ }
19
+ }
20
+ function getActionableMessage(httpStatus, apiErrors) {
21
+ const detail = apiErrors.length > 0
22
+ ? ` Detalle de la API: "${apiErrors[0].mensaje}"`
23
+ : '';
24
+ switch (httpStatus) {
25
+ case 400:
26
+ return `Parámetros inválidos enviados a la API de Compra Ágil. Verifica el formato de fechas (ISO-8601), que 'q' e 'id' no se usen juntos, y que los códigos de región estén entre 1 y 16.${detail}`;
27
+ case 401:
28
+ return `Ticket de acceso no proporcionado. Configura la variable de entorno COMPRA_AGIL_TICKET con un ticket válido obtenido en https://www.chilecompra.cl/api/.${detail}`;
29
+ case 403:
30
+ return `Ticket de acceso inválido, inactivo o bloqueado. Verifica que el ticket sea correcto y esté vigente. Si fue bloqueado, solicita uno nuevo en https://www.chilecompra.cl/api/.${detail}`;
31
+ case 404:
32
+ return `No se encontró una Compra Ágil con el código proporcionado. Verifica que el código tenga el formato correcto (ej: 1057539-228-COT26) y que el proceso exista y sea público.${detail}`;
33
+ case 429:
34
+ return formatRateLimitMessage(detail);
35
+ case 500:
36
+ return `Error interno del servidor de Mercado Público (api2.mercadopublico.cl). Esto no es un problema de tu consulta. Reintenta en unos minutos.${detail}`;
37
+ case 503:
38
+ return `El servicio de Mercado Público está temporalmente no disponible (posible mantenimiento). Reintenta más tarde.${detail}`;
39
+ default:
40
+ return `Error inesperado HTTP ${httpStatus} de la API de Compra Ágil.${detail}`;
41
+ }
42
+ }
43
+ function formatRateLimitMessage(detail) {
44
+ const now = new Date();
45
+ const tomorrow = new Date(now);
46
+ tomorrow.setUTCDate(tomorrow.getUTCDate() + 1);
47
+ tomorrow.setUTCHours(0, 1, 0, 0);
48
+ const waitHours = Math.ceil((tomorrow.getTime() - now.getTime()) / (1000 * 60 * 60));
49
+ return `Cuota diaria de la API agotada. El límite se restablece al inicio del próximo día calendario UTC (en aproximadamente ${waitHours} horas). Para reducir el consumo: usa filtros más específicos (estado, región, fechas), evita consultas masivas, y usa 'ttl_cambio_ms' para sincronización incremental en vez de descargas completas. Si necesitas más cuota, contacta a ChileCompra.${detail}`;
50
+ }
51
+ /**
52
+ * Parsea la respuesta de error de la API y lanza una excepción tipada.
53
+ */
54
+ export async function handleApiResponse(response) {
55
+ if (response.ok) {
56
+ const json = await response.json();
57
+ if (json.success === 'NOK') {
58
+ throw new CompraAgilApiError(response.status, json.errors);
59
+ }
60
+ return json.payload;
61
+ }
62
+ let apiErrors = [];
63
+ try {
64
+ const errorJson = await response.json();
65
+ if (errorJson.errors) {
66
+ apiErrors = errorJson.errors;
67
+ }
68
+ }
69
+ catch {
70
+ // Response body was not JSON, proceed with HTTP status only
71
+ }
72
+ throw new CompraAgilApiError(response.status, apiErrors);
73
+ }
74
+ //# sourceMappingURL=error-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-handler.js","sourceRoot":"","sources":["../../src/utils/error-handler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Logger seguro para servidores MCP con transporte Stdio.
3
+ *
4
+ * REGLA CRÍTICA: En servidores MCP que usan Stdio, JAMÁS se debe escribir
5
+ * a stdout (console.log) ya que corrompe el stream JSON-RPC.
6
+ * Todo el logging va exclusivamente a stderr (console.error).
7
+ */
8
+ export declare function setMcpServer(server: any): void;
9
+ export declare const logger: {
10
+ debug: (msg: string, data?: unknown) => void;
11
+ info: (msg: string, data?: unknown) => void;
12
+ warn: (msg: string, data?: unknown) => void;
13
+ error: (msg: string, data?: unknown) => void;
14
+ };
15
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAmBH,wBAAgB,YAAY,CAAC,MAAM,EAAE,GAAG,GAAG,IAAI,CAE9C;AAyBD,eAAO,MAAM,MAAM;iBACJ,MAAM,SAAS,OAAO;gBACvB,MAAM,SAAS,OAAO;gBACtB,MAAM,SAAS,OAAO;iBACrB,MAAM,SAAS,OAAO;CACpC,CAAC"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Logger seguro para servidores MCP con transporte Stdio.
3
+ *
4
+ * REGLA CRÍTICA: En servidores MCP que usan Stdio, JAMÁS se debe escribir
5
+ * a stdout (console.log) ya que corrompe el stream JSON-RPC.
6
+ * Todo el logging va exclusivamente a stderr (console.error).
7
+ */
8
+ const LOG_LEVELS = {
9
+ debug: 0,
10
+ info: 1,
11
+ warn: 2,
12
+ error: 3,
13
+ };
14
+ const currentLevel = process.env.LOG_LEVEL || 'info';
15
+ function formatTimestamp() {
16
+ return new Date().toISOString();
17
+ }
18
+ let mcpServer = null;
19
+ export function setMcpServer(server) {
20
+ mcpServer = server;
21
+ }
22
+ function log(level, message, data) {
23
+ if (LOG_LEVELS[level] < LOG_LEVELS[currentLevel])
24
+ return;
25
+ const prefix = `[${formatTimestamp()}] [${level.toUpperCase()}]`;
26
+ const line = data
27
+ ? `${prefix} ${message} ${JSON.stringify(data)}`
28
+ : `${prefix} ${message}`;
29
+ // SIEMPRE stderr, NUNCA stdout
30
+ console.error(line);
31
+ // Intentar enviar el log de forma nativa al cliente MCP si el servidor está configurado
32
+ if (mcpServer) {
33
+ mcpServer.sendLoggingMessage({
34
+ level,
35
+ logger: 'mcp-compra-agil',
36
+ data: data ? `${message} ${JSON.stringify(data)}` : message,
37
+ }).catch(() => {
38
+ // Ignorar fallos silenciosamente para no interrumpir el flujo principal
39
+ });
40
+ }
41
+ }
42
+ export const logger = {
43
+ debug: (msg, data) => log('debug', msg, data),
44
+ info: (msg, data) => log('info', msg, data),
45
+ warn: (msg, data) => log('warn', msg, data),
46
+ error: (msg, data) => log('error', msg, data),
47
+ };
48
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,UAAU,GAA6B;IAC3C,KAAK,EAAE,CAAC;IACR,IAAI,EAAE,CAAC;IACP,IAAI,EAAE,CAAC;IACP,KAAK,EAAE,CAAC;CACT,CAAC;AAEF,MAAM,YAAY,GAAc,OAAO,CAAC,GAAG,CAAC,SAAsB,IAAI,MAAM,CAAC;AAE7E,SAAS,eAAe;IACtB,OAAO,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AAClC,CAAC;AAED,IAAI,SAAS,GAAQ,IAAI,CAAC;AAE1B,MAAM,UAAU,YAAY,CAAC,MAAW;IACtC,SAAS,GAAG,MAAM,CAAC;AACrB,CAAC;AAED,SAAS,GAAG,CAAC,KAAe,EAAE,OAAe,EAAE,IAAc;IAC3D,IAAI,UAAU,CAAC,KAAK,CAAC,GAAG,UAAU,CAAC,YAAY,CAAC;QAAE,OAAO;IAEzD,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,MAAM,KAAK,CAAC,WAAW,EAAE,GAAG,CAAC;IACjE,MAAM,IAAI,GAAG,IAAI;QACf,CAAC,CAAC,GAAG,MAAM,IAAI,OAAO,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE;QAChD,CAAC,CAAC,GAAG,MAAM,IAAI,OAAO,EAAE,CAAC;IAE3B,+BAA+B;IAC/B,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAEpB,wFAAwF;IACxF,IAAI,SAAS,EAAE,CAAC;QACd,SAAS,CAAC,kBAAkB,CAAC;YAC3B,KAAK;YACL,MAAM,EAAE,iBAAiB;YACzB,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,OAAO,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO;SAC5D,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;YACZ,wEAAwE;QAC1E,CAAC,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,KAAK,EAAE,CAAC,GAAW,EAAE,IAAc,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC;IAC/D,IAAI,EAAE,CAAC,GAAW,EAAE,IAAc,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC;IAC7D,IAAI,EAAE,CAAC,GAAW,EAAE,IAAc,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC;IAC7D,KAAK,EAAE,CAAC,GAAW,EAAE,IAAc,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC;CAChE,CAAC"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Control inteligente de rate limiting para la API de Compra Ágil.
3
+ *
4
+ * La API usa cuota por día calendario (se resetea a medianoche UTC).
5
+ * Este módulo lleva un contador local de requests para advertir
6
+ * proactivamente antes de alcanzar el límite.
7
+ */
8
+ export declare class RateLimiter {
9
+ private requestCount;
10
+ private currentDay;
11
+ private isLimited;
12
+ private limitResetTime;
13
+ constructor();
14
+ private getTodayUTC;
15
+ /**
16
+ * Registra un request exitoso. Resetea el contador si cambió el día.
17
+ */
18
+ recordRequest(): void;
19
+ /**
20
+ * Marca que se recibió un error 429.
21
+ */
22
+ markLimited(): void;
23
+ /**
24
+ * Verifica si estamos actualmente limitados.
25
+ */
26
+ checkLimit(): {
27
+ limited: boolean;
28
+ resetIn?: string;
29
+ };
30
+ /**
31
+ * Obtiene estadísticas del uso actual.
32
+ */
33
+ getStats(): {
34
+ requestsToday: number;
35
+ isLimited: boolean;
36
+ resetTime: string | null;
37
+ };
38
+ }
39
+ //# sourceMappingURL=rate-limiter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../../src/utils/rate-limiter.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,qBAAa,WAAW;IACtB,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,cAAc,CAAqB;;IAM3C,OAAO,CAAC,WAAW;IAInB;;OAEG;IACH,aAAa,IAAI,IAAI;IAarB;;OAEG;IACH,WAAW,IAAI,IAAI;IAUnB;;OAEG;IACH,UAAU,IAAI;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE;IAyBpD;;OAEG;IACH,QAAQ,IAAI;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,OAAO,CAAC;QAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE;CAOpF"}