@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.
- package/LICENSE +21 -0
- package/README.md +355 -0
- package/dist/api/compra-agil-client.d.ts +268 -0
- package/dist/api/compra-agil-client.d.ts.map +1 -0
- package/dist/api/compra-agil-client.js +137 -0
- package/dist/api/compra-agil-client.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +95 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts/analizar-competencia.d.ts +9 -0
- package/dist/prompts/analizar-competencia.d.ts.map +1 -0
- package/dist/prompts/analizar-competencia.js +50 -0
- package/dist/prompts/analizar-competencia.js.map +1 -0
- package/dist/prompts/buscar-oportunidades.d.ts +9 -0
- package/dist/prompts/buscar-oportunidades.d.ts.map +1 -0
- package/dist/prompts/buscar-oportunidades.js +48 -0
- package/dist/prompts/buscar-oportunidades.js.map +1 -0
- package/dist/resources/compras-template.d.ts +10 -0
- package/dist/resources/compras-template.d.ts.map +1 -0
- package/dist/resources/compras-template.js +40 -0
- package/dist/resources/compras-template.js.map +1 -0
- package/dist/resources/documentacion.d.ts +6 -0
- package/dist/resources/documentacion.d.ts.map +1 -0
- package/dist/resources/documentacion.js +100 -0
- package/dist/resources/documentacion.js.map +1 -0
- package/dist/resources/estados.d.ts +9 -0
- package/dist/resources/estados.d.ts.map +1 -0
- package/dist/resources/estados.js +51 -0
- package/dist/resources/estados.js.map +1 -0
- package/dist/resources/glosario.d.ts +9 -0
- package/dist/resources/glosario.d.ts.map +1 -0
- package/dist/resources/glosario.js +77 -0
- package/dist/resources/glosario.js.map +1 -0
- package/dist/resources/regiones.d.ts +9 -0
- package/dist/resources/regiones.d.ts.map +1 -0
- package/dist/resources/regiones.js +37 -0
- package/dist/resources/regiones.js.map +1 -0
- package/dist/services/monitor.d.ts +2 -0
- package/dist/services/monitor.d.ts.map +1 -0
- package/dist/services/monitor.js +87 -0
- package/dist/services/monitor.js.map +1 -0
- package/dist/tools/auditar-desiertas.d.ts +4 -0
- package/dist/tools/auditar-desiertas.d.ts.map +1 -0
- package/dist/tools/auditar-desiertas.js +242 -0
- package/dist/tools/auditar-desiertas.js.map +1 -0
- package/dist/tools/buscar-compras.d.ts +10 -0
- package/dist/tools/buscar-compras.d.ts.map +1 -0
- package/dist/tools/buscar-compras.js +121 -0
- package/dist/tools/buscar-compras.js.map +1 -0
- package/dist/tools/detalle-compra.d.ts +10 -0
- package/dist/tools/detalle-compra.d.ts.map +1 -0
- package/dist/tools/detalle-compra.js +119 -0
- package/dist/tools/detalle-compra.js.map +1 -0
- package/dist/tools/detalle-oc.d.ts +10 -0
- package/dist/tools/detalle-oc.d.ts.map +1 -0
- package/dist/tools/detalle-oc.js +81 -0
- package/dist/tools/detalle-oc.js.map +1 -0
- package/dist/tools/documentos.d.ts +6 -0
- package/dist/tools/documentos.d.ts.map +1 -0
- package/dist/tools/documentos.js +245 -0
- package/dist/tools/documentos.js.map +1 -0
- package/dist/tools/estadisticas-uso.d.ts +10 -0
- package/dist/tools/estadisticas-uso.d.ts.map +1 -0
- package/dist/tools/estadisticas-uso.js +22 -0
- package/dist/tools/estadisticas-uso.js.map +1 -0
- package/dist/tools/generar-borrador.d.ts +4 -0
- package/dist/tools/generar-borrador.d.ts.map +1 -0
- package/dist/tools/generar-borrador.js +178 -0
- package/dist/tools/generar-borrador.js.map +1 -0
- package/dist/tools/monitorear-cambios.d.ts +10 -0
- package/dist/tools/monitorear-cambios.d.ts.map +1 -0
- package/dist/tools/monitorear-cambios.js +68 -0
- package/dist/tools/monitorear-cambios.js.map +1 -0
- package/dist/tools/radar-oportunidades.d.ts +4 -0
- package/dist/tools/radar-oportunidades.d.ts.map +1 -0
- package/dist/tools/radar-oportunidades.js +148 -0
- package/dist/tools/radar-oportunidades.js.map +1 -0
- package/dist/tools/recomendar-precio.d.ts +4 -0
- package/dist/tools/recomendar-precio.d.ts.map +1 -0
- package/dist/tools/recomendar-precio.js +180 -0
- package/dist/tools/recomendar-precio.js.map +1 -0
- package/dist/tools/verificar-oc.d.ts +13 -0
- package/dist/tools/verificar-oc.d.ts.map +1 -0
- package/dist/tools/verificar-oc.js +94 -0
- package/dist/tools/verificar-oc.js.map +1 -0
- package/dist/utils/env-loader.d.ts +6 -0
- package/dist/utils/env-loader.d.ts.map +1 -0
- package/dist/utils/env-loader.js +35 -0
- package/dist/utils/env-loader.js.map +1 -0
- package/dist/utils/error-handler.d.ts +28 -0
- package/dist/utils/error-handler.d.ts.map +1 -0
- package/dist/utils/error-handler.js +74 -0
- package/dist/utils/error-handler.js.map +1 -0
- package/dist/utils/logger.d.ts +15 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +48 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/rate-limiter.d.ts +39 -0
- package/dist/utils/rate-limiter.d.ts.map +1 -0
- package/dist/utils/rate-limiter.js +82 -0
- package/dist/utils/rate-limiter.js.map +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: buscar_compras_agiles
|
|
3
|
+
*
|
|
4
|
+
* Busca y filtra procesos de Compra Ágil en Mercado Público
|
|
5
|
+
* usando palabras clave, fechas, estados y regiones.
|
|
6
|
+
*/
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import { CompraAgilApiError } from '../utils/error-handler.js';
|
|
9
|
+
const TOOL_NAME = 'buscar_compras_agiles';
|
|
10
|
+
const TOOL_DESCRIPTION = `Busca procesos de Compra Ágil en Mercado Público de Chile.
|
|
11
|
+
Permite filtrar por palabras clave, estado del proceso, región geográfica y rango de fechas de publicación.
|
|
12
|
+
Retorna un listado resumido con código, nombre, estado, presupuesto e institución compradora.
|
|
13
|
+
Nota: los parámetros 'q' (búsqueda por texto) e 'id' (código exacto) son mutuamente excluyentes.
|
|
14
|
+
Estados válidos: publicada, cerrada, desierta, cancelada, proveedor_seleccionado.
|
|
15
|
+
Regiones: códigos del 1 al 16 (ej: 13 = Metropolitana, 5 = Valparaíso).`;
|
|
16
|
+
const inputSchema = {
|
|
17
|
+
q: z.string().optional().describe('Palabras clave para buscar en el nombre/descripción del proceso. Ej: "materiales electricos". No usar junto con "id".'),
|
|
18
|
+
id: z.string().optional().describe('Código exacto de una Compra Ágil. Ej: "1057539-228-COT26". No usar junto con "q".'),
|
|
19
|
+
estado: z.string().optional().describe('Estado(s) del proceso, separados por coma. Valores: publicada, cerrada, desierta, cancelada, proveedor_seleccionado. Ej: "publicada,proveedor_seleccionado".'),
|
|
20
|
+
region: z.string().optional().describe('Código(s) de región del organismo comprador, separados por coma (1-16). Ej: "13" para Metropolitana, "13,5" para Metropolitana y Valparaíso.'),
|
|
21
|
+
publicado_desde: z.string().optional().describe('Fecha mínima de publicación en formato ISO-8601. Ej: "2026-01-01T00:00:00Z".'),
|
|
22
|
+
publicado_hasta: z.string().optional().describe('Fecha máxima de publicación en formato ISO-8601. Ej: "2026-01-31T23:59:59Z".'),
|
|
23
|
+
palabras_clave_requeridas: z.string().optional().describe('Lista de palabras clave separadas por comas que DEBEN estar presentes en el nombre de la compra (filtro local. Ej: "software,desarrollo").'),
|
|
24
|
+
palabras_clave_excluidas: z.string().optional().describe('Lista de palabras clave separadas por comas que NO DEBEN estar en el nombre de la compra (filtro local. Ej: "soporte,licencias").'),
|
|
25
|
+
ordenar_por: z.enum(['FechaUltimaModificacion', 'FechaPublicacion']).optional().describe('Criterio de ordenamiento. "FechaPublicacion" para las más recientes primero, "FechaUltimaModificacion" (default) para las últimas modificadas.'),
|
|
26
|
+
tamano_pagina: z.number().min(10).max(50).optional().describe('Resultados por página (10-50, default 15).'),
|
|
27
|
+
numero_pagina: z.number().min(1).optional().describe('Número de página a consultar (comienza en 1).'),
|
|
28
|
+
};
|
|
29
|
+
export function registerBuscarCompras(server, client) {
|
|
30
|
+
server.registerTool(TOOL_NAME, {
|
|
31
|
+
description: TOOL_DESCRIPTION,
|
|
32
|
+
inputSchema: inputSchema,
|
|
33
|
+
}, async (args) => {
|
|
34
|
+
try {
|
|
35
|
+
// Validar exclusión mutua de q e id
|
|
36
|
+
if (args.q && args.id) {
|
|
37
|
+
return {
|
|
38
|
+
content: [{
|
|
39
|
+
type: 'text',
|
|
40
|
+
text: 'Error de validación: Los parámetros "q" (búsqueda por texto) e "id" (código exacto) no pueden usarse juntos. Usa solo uno de los dos.',
|
|
41
|
+
}],
|
|
42
|
+
isError: true,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
const response = await client.buscar({
|
|
46
|
+
q: args.q,
|
|
47
|
+
id: args.id,
|
|
48
|
+
estado: args.estado,
|
|
49
|
+
region: args.region,
|
|
50
|
+
publicado_desde: args.publicado_desde,
|
|
51
|
+
publicado_hasta: args.publicado_hasta,
|
|
52
|
+
ordenar_por: args.ordenar_por,
|
|
53
|
+
tamano_pagina: args.tamano_pagina,
|
|
54
|
+
numero_pagina: args.numero_pagina,
|
|
55
|
+
});
|
|
56
|
+
// Formatear resultado compacto para el LLM
|
|
57
|
+
let filteredItems = response.items;
|
|
58
|
+
// Filtrado local por palabras_clave_requeridas (AND lógico entre los términos)
|
|
59
|
+
if (args.palabras_clave_requeridas) {
|
|
60
|
+
const reqKeywords = args.palabras_clave_requeridas
|
|
61
|
+
.split(',')
|
|
62
|
+
.map(kw => kw.trim().toLowerCase())
|
|
63
|
+
.filter(Boolean);
|
|
64
|
+
if (reqKeywords.length > 0) {
|
|
65
|
+
filteredItems = filteredItems.filter(item => {
|
|
66
|
+
const nameLower = item.nombre.toLowerCase();
|
|
67
|
+
return reqKeywords.every(kw => nameLower.includes(kw));
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// Filtrado local por palabras_clave_excluidas (OR lógico entre los términos)
|
|
72
|
+
if (args.palabras_clave_excluidas) {
|
|
73
|
+
const excKeywords = args.palabras_clave_excluidas
|
|
74
|
+
.split(',')
|
|
75
|
+
.map(kw => kw.trim().toLowerCase())
|
|
76
|
+
.filter(Boolean);
|
|
77
|
+
if (excKeywords.length > 0) {
|
|
78
|
+
filteredItems = filteredItems.filter(item => {
|
|
79
|
+
const nameLower = item.nombre.toLowerCase();
|
|
80
|
+
return !excKeywords.some(kw => nameLower.includes(kw));
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const summary = filteredItems.map((item) => ({
|
|
85
|
+
codigo: item.codigo,
|
|
86
|
+
nombre: item.nombre,
|
|
87
|
+
estado: item.estado.glosa,
|
|
88
|
+
convocatoria: item.convocatoria.descripcion,
|
|
89
|
+
presupuesto_clp: item.montos.monto_disponible_clp,
|
|
90
|
+
moneda: item.montos.moneda,
|
|
91
|
+
institucion: item.institucion.organismo_comprador,
|
|
92
|
+
region: item.institucion.nombre_region,
|
|
93
|
+
fecha_publicacion: item.fechas.fecha_publicacion,
|
|
94
|
+
fecha_cierre: item.fechas.fecha_cierre,
|
|
95
|
+
ofertas_recibidas: item.resumen.total_ofertas_recibidas,
|
|
96
|
+
}));
|
|
97
|
+
const result = {
|
|
98
|
+
total_resultados: response.paginacion.total_resultados,
|
|
99
|
+
total_filtrados_en_pagina: filteredItems.length,
|
|
100
|
+
pagina: `${response.paginacion.numero_pagina} de ${response.paginacion.total_paginas}`,
|
|
101
|
+
resultados: summary,
|
|
102
|
+
};
|
|
103
|
+
return {
|
|
104
|
+
content: [{
|
|
105
|
+
type: 'text',
|
|
106
|
+
text: JSON.stringify(result, null, 2),
|
|
107
|
+
}],
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
const message = error instanceof CompraAgilApiError
|
|
112
|
+
? error.actionableMessage
|
|
113
|
+
: `Error inesperado: ${String(error)}`;
|
|
114
|
+
return {
|
|
115
|
+
content: [{ type: 'text', text: message }],
|
|
116
|
+
isError: true,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=buscar-compras.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buscar-compras.js","sourceRoot":"","sources":["../../src/tools/buscar-compras.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: obtener_detalle_compra
|
|
3
|
+
*
|
|
4
|
+
* Obtiene el detalle completo de una Compra Ágil específica,
|
|
5
|
+
* incluyendo productos, proveedores, cotizaciones y estado de OC.
|
|
6
|
+
*/
|
|
7
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
8
|
+
import { CompraAgilClient } from '../api/compra-agil-client.js';
|
|
9
|
+
export declare function registerDetalleCompra(server: McpServer, client: CompraAgilClient): void;
|
|
10
|
+
//# sourceMappingURL=detalle-compra.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detalle-compra.d.ts","sourceRoot":"","sources":["../../src/tools/detalle-compra.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAiBhE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAyGvF"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: obtener_detalle_compra
|
|
3
|
+
*
|
|
4
|
+
* Obtiene el detalle completo de una Compra Ágil específica,
|
|
5
|
+
* incluyendo productos, proveedores, cotizaciones y estado de OC.
|
|
6
|
+
*/
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import { CompraAgilApiError } from '../utils/error-handler.js';
|
|
9
|
+
const TOOL_NAME = 'obtener_detalle_compra';
|
|
10
|
+
const TOOL_DESCRIPTION = `Obtiene el detalle completo de una Compra Ágil específica por su código único.
|
|
11
|
+
Incluye: descripción del proceso, productos solicitados con cantidades, proveedores que cotizaron con sus montos,
|
|
12
|
+
presupuesto disponible, dirección y plazo de entrega, estado de la Orden de Compra (si fue emitida),
|
|
13
|
+
y flags de sostenibilidad (requisitos medioambientales y de impacto social).
|
|
14
|
+
NOTA: Las cotizaciones detalladas de los proveedores solo se muestran desde el estado "Cerrada" en segundo llamado en adelante.`;
|
|
15
|
+
const inputSchema = {
|
|
16
|
+
codigo: z.string().describe('Código único de la Compra Ágil. Formato: XXXXXX-YYY-COTXX. Ej: "1057539-228-COT26".'),
|
|
17
|
+
};
|
|
18
|
+
export function registerDetalleCompra(server, client) {
|
|
19
|
+
server.registerTool(TOOL_NAME, {
|
|
20
|
+
description: TOOL_DESCRIPTION,
|
|
21
|
+
inputSchema: inputSchema,
|
|
22
|
+
}, async (args) => {
|
|
23
|
+
try {
|
|
24
|
+
const detalle = await client.detalle(args.codigo);
|
|
25
|
+
// Formatear para LLM — estructura limpia y legible
|
|
26
|
+
const result = {
|
|
27
|
+
codigo: detalle.codigo,
|
|
28
|
+
nombre: detalle.nombre,
|
|
29
|
+
descripcion: detalle.descripcion,
|
|
30
|
+
estado: detalle.estado.glosa,
|
|
31
|
+
convocatoria: detalle.convocatoria.descripcion,
|
|
32
|
+
institucion: {
|
|
33
|
+
organismo: detalle.institucion.organismo_comprador,
|
|
34
|
+
rut: detalle.institucion.rut,
|
|
35
|
+
unidad: detalle.institucion.unidad_compra,
|
|
36
|
+
region: detalle.institucion.nombre_region,
|
|
37
|
+
},
|
|
38
|
+
fechas: {
|
|
39
|
+
publicacion: detalle.fechas.fecha_publicacion,
|
|
40
|
+
cierre: detalle.fechas.fecha_cierre,
|
|
41
|
+
cierre_primer_llamado: detalle.convocatoria.fecha_cierre_primer_llamado,
|
|
42
|
+
cierre_segundo_llamado: detalle.convocatoria.fecha_cierre_segundo_llamado,
|
|
43
|
+
cancelacion: detalle.fechas.fecha_cancelacion,
|
|
44
|
+
},
|
|
45
|
+
presupuesto: {
|
|
46
|
+
tipo: detalle.presupuesto.tipo_presupuesto,
|
|
47
|
+
monto_disponible_clp: detalle.presupuesto.monto_disponible_clp,
|
|
48
|
+
moneda: detalle.presupuesto.moneda,
|
|
49
|
+
presupuesto_estimado: detalle.presupuesto.presupuesto_estimado,
|
|
50
|
+
},
|
|
51
|
+
entrega: {
|
|
52
|
+
direccion: detalle.entrega.direccion_entrega,
|
|
53
|
+
plazo_dias: detalle.entrega.plazo_entrega_dias,
|
|
54
|
+
},
|
|
55
|
+
productos_solicitados: detalle.productos_solicitados.map((p) => ({
|
|
56
|
+
codigo: p.codigo_producto,
|
|
57
|
+
nombre: p.nombre,
|
|
58
|
+
descripcion: p.descripcion,
|
|
59
|
+
cantidad: p.cantidad,
|
|
60
|
+
unidad: p.unidad_medida,
|
|
61
|
+
})),
|
|
62
|
+
proveedores_cotizando: detalle.proveedores_cotizando.map((prov) => ({
|
|
63
|
+
rut: prov.rut_proveedor,
|
|
64
|
+
razon_social: prov.razon_social,
|
|
65
|
+
es_empresa_menor_tamano: prov.es_emt,
|
|
66
|
+
monto_total: prov.monto_total,
|
|
67
|
+
valor_neto: prov.valor_neto,
|
|
68
|
+
impuesto: prov.total_impuesto,
|
|
69
|
+
despacho: prov.monto_despacho,
|
|
70
|
+
descripcion: prov.descripcion_cotizacion || prov.descripcion,
|
|
71
|
+
estado_por_comprador: prov.estado_por_comprador,
|
|
72
|
+
productos_cotizados: prov.productos_cotizados?.map((pc) => ({
|
|
73
|
+
nombre: pc.nombre_producto,
|
|
74
|
+
cantidad: pc.cantidad,
|
|
75
|
+
precio_unitario: pc.precio_unitario,
|
|
76
|
+
total: pc.monto_total_producto,
|
|
77
|
+
})),
|
|
78
|
+
})),
|
|
79
|
+
orden_compra: {
|
|
80
|
+
tiene_oc: (detalle.id_orden_compra ?? detalle.orden_compra?.id_orden_compra ?? null) !== null,
|
|
81
|
+
id_orden_compra: detalle.id_orden_compra ?? detalle.orden_compra?.id_orden_compra ?? null,
|
|
82
|
+
id_oc: detalle.orden_compra?.id_oc ?? null,
|
|
83
|
+
codigo_oc: detalle.orden_compra?.codigo_orden_compra ?? null,
|
|
84
|
+
estado_oc: detalle.orden_compra?.estado_orden_compra ?? null,
|
|
85
|
+
},
|
|
86
|
+
resumen: {
|
|
87
|
+
total_ofertas: detalle.resumen.total_ofertas_recibidas,
|
|
88
|
+
total_demandas: detalle.resumen.total_demandas,
|
|
89
|
+
multa_sancion: detalle.resumen.multa_sancion,
|
|
90
|
+
},
|
|
91
|
+
motivos: detalle.motivos,
|
|
92
|
+
sostenibilidad: {
|
|
93
|
+
medioambientales: detalle.flags.considera_requisitos_medioambientales,
|
|
94
|
+
impacto_social_economico: detalle.flags.considera_requisitos_impacto_social_economico,
|
|
95
|
+
},
|
|
96
|
+
documentos_adjuntos: detalle.documentos.map((d) => ({
|
|
97
|
+
id: d.id,
|
|
98
|
+
nombre: d.nombre,
|
|
99
|
+
})),
|
|
100
|
+
};
|
|
101
|
+
return {
|
|
102
|
+
content: [{
|
|
103
|
+
type: 'text',
|
|
104
|
+
text: JSON.stringify(result, null, 2),
|
|
105
|
+
}],
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
const message = error instanceof CompraAgilApiError
|
|
110
|
+
? error.actionableMessage
|
|
111
|
+
: `Error inesperado: ${String(error)}`;
|
|
112
|
+
return {
|
|
113
|
+
content: [{ type: 'text', text: message }],
|
|
114
|
+
isError: true,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=detalle-compra.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detalle-compra.js","sourceRoot":"","sources":["../../src/tools/detalle-compra.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: obtener_detalle_orden_compra
|
|
3
|
+
*
|
|
4
|
+
* Obtiene el detalle completo de una Orden de Compra (OC) en Mercado Público.
|
|
5
|
+
* Admite tanto el ID numérico interno como el código alfanumérico (ej. "1057532-156-AG26").
|
|
6
|
+
*/
|
|
7
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
8
|
+
import { CompraAgilClient } from '../api/compra-agil-client.js';
|
|
9
|
+
export declare function registerDetalleOC(server: McpServer, client: CompraAgilClient): void;
|
|
10
|
+
//# sourceMappingURL=detalle-oc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detalle-oc.d.ts","sourceRoot":"","sources":["../../src/tools/detalle-oc.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAehE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAuEnF"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: obtener_detalle_orden_compra
|
|
3
|
+
*
|
|
4
|
+
* Obtiene el detalle completo de una Orden de Compra (OC) en Mercado Público.
|
|
5
|
+
* Admite tanto el ID numérico interno como el código alfanumérico (ej. "1057532-156-AG26").
|
|
6
|
+
*/
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import { CompraAgilApiError } from '../utils/error-handler.js';
|
|
9
|
+
const TOOL_NAME = 'obtener_detalle_orden_compra';
|
|
10
|
+
const TOOL_DESCRIPTION = `Obtiene el detalle completo de una Orden de Compra (OC) emitida en Mercado Público de Chile.
|
|
11
|
+
Admite tanto el ID numérico (id_orden_compra) como el código alfanumérico externo.
|
|
12
|
+
Retorna información sobre montos (neto, impuestos, total), comprador, proveedor adjudicado y el listado de productos/servicios adquiridos.`;
|
|
13
|
+
const inputSchema = {
|
|
14
|
+
codigo_oc: z.string().describe('Código alfanumérico (ej: "1057532-156-AG26") o ID numérico (ej: "54909627") de la Orden de Compra.'),
|
|
15
|
+
};
|
|
16
|
+
export function registerDetalleOC(server, client) {
|
|
17
|
+
server.registerTool(TOOL_NAME, {
|
|
18
|
+
description: TOOL_DESCRIPTION,
|
|
19
|
+
inputSchema: inputSchema,
|
|
20
|
+
}, async (args) => {
|
|
21
|
+
try {
|
|
22
|
+
const response = await client.obtenerDetalleOC(args.codigo_oc);
|
|
23
|
+
if (!response.Listado || response.Listado.length === 0) {
|
|
24
|
+
return {
|
|
25
|
+
content: [{
|
|
26
|
+
type: 'text',
|
|
27
|
+
text: `No se encontró ninguna Orden de Compra asociada al identificador "${args.codigo_oc}".`,
|
|
28
|
+
}],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
const oc = response.Listado[0];
|
|
32
|
+
// Estructura simplificada e informativa para el LLM
|
|
33
|
+
const result = {
|
|
34
|
+
codigo: oc.Codigo,
|
|
35
|
+
nombre: oc.Nombre,
|
|
36
|
+
estado: oc.Estado,
|
|
37
|
+
codigo_estado: oc.CodigoEstado,
|
|
38
|
+
licitacion_asociada: oc.CodigoLicitacion,
|
|
39
|
+
descripcion: oc.Descripcion,
|
|
40
|
+
fecha_creacion: oc.FechaCreacion,
|
|
41
|
+
fecha_aceptacion: oc.FechaAceptacion,
|
|
42
|
+
montos: {
|
|
43
|
+
neto: oc.MontoNeto,
|
|
44
|
+
impuestos: oc.Impuestos,
|
|
45
|
+
total: oc.Total,
|
|
46
|
+
},
|
|
47
|
+
comprador: {
|
|
48
|
+
organismo: oc.Comprador.NombreOrganismo,
|
|
49
|
+
unidad: oc.Comprador.NombreUnidad,
|
|
50
|
+
region: oc.Comprador.RegionUsuario,
|
|
51
|
+
},
|
|
52
|
+
proveedor: {
|
|
53
|
+
nombre: oc.Proveedor.Nombre,
|
|
54
|
+
rut: oc.Proveedor.Rut,
|
|
55
|
+
},
|
|
56
|
+
items: oc.Items.Listado.map((item) => ({
|
|
57
|
+
producto: item.Producto,
|
|
58
|
+
cantidad: item.Cantidad,
|
|
59
|
+
precio_neto: item.PrecioNeto,
|
|
60
|
+
total_neto: item.TotalLnea,
|
|
61
|
+
})),
|
|
62
|
+
};
|
|
63
|
+
return {
|
|
64
|
+
content: [{
|
|
65
|
+
type: 'text',
|
|
66
|
+
text: JSON.stringify(result, null, 2),
|
|
67
|
+
}],
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
const message = error instanceof CompraAgilApiError
|
|
72
|
+
? error.actionableMessage
|
|
73
|
+
: `Error inesperado: ${String(error)}`;
|
|
74
|
+
return {
|
|
75
|
+
content: [{ type: 'text', text: message }],
|
|
76
|
+
isError: true,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=detalle-oc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detalle-oc.js","sourceRoot":"","sources":["../../src/tools/detalle-oc.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
/**
|
|
3
|
+
* Registra las herramientas relacionadas con documentos y especificaciones en el servidor MCP.
|
|
4
|
+
*/
|
|
5
|
+
export declare function registerDocumentosTools(server: McpServer): void;
|
|
6
|
+
//# sourceMappingURL=documentos.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"documentos.d.ts","sourceRoot":"","sources":["../../src/tools/documentos.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAoCpE;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA2O/D"}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
import { PDFParse } from 'pdf-parse';
|
|
6
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
const packageDocsDir = path.resolve(__dirname, '../../docs');
|
|
8
|
+
const cwdDocsDir = path.resolve(process.cwd(), 'docs');
|
|
9
|
+
let DOCS_DIR = cwdDocsDir;
|
|
10
|
+
if (fs.existsSync(packageDocsDir) && fs.readdirSync(packageDocsDir).some(f => f.toLowerCase().endsWith('.pdf'))) {
|
|
11
|
+
DOCS_DIR = packageDocsDir;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Obtiene de forma recursiva todos los archivos dentro de un directorio,
|
|
15
|
+
* retornando sus rutas relativas formateadas con barras diagonales (/).
|
|
16
|
+
*/
|
|
17
|
+
function getRelativeFilesRecursively(dir, baseDir = dir) {
|
|
18
|
+
let results = [];
|
|
19
|
+
if (!fs.existsSync(dir))
|
|
20
|
+
return [];
|
|
21
|
+
const list = fs.readdirSync(dir);
|
|
22
|
+
for (const file of list) {
|
|
23
|
+
const filePath = path.join(dir, file);
|
|
24
|
+
const stat = fs.statSync(filePath);
|
|
25
|
+
if (stat && stat.isDirectory()) {
|
|
26
|
+
results = results.concat(getRelativeFilesRecursively(filePath, baseDir));
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
const relativePath = path.relative(baseDir, filePath).replace(/\\/g, '/');
|
|
30
|
+
results.push(relativePath);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return results;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Registra las herramientas relacionadas con documentos y especificaciones en el servidor MCP.
|
|
37
|
+
*/
|
|
38
|
+
export function registerDocumentosTools(server) {
|
|
39
|
+
// ─── 1. OBTENER ENLACE DE DOCUMENTO DE PROCESO ───────────────────────
|
|
40
|
+
server.registerTool('obtener_enlace_documento', {
|
|
41
|
+
description: 'Genera el enlace oficial de descarga pública en Mercado Público para un adjunto (bases, especificaciones o anexos) usando su ID de documento.',
|
|
42
|
+
inputSchema: {
|
|
43
|
+
id_documento: z.string().describe('ID único del documento. Ej: "123456" de la lista de documentos de una compra.'),
|
|
44
|
+
},
|
|
45
|
+
}, async (args) => {
|
|
46
|
+
const url = `https://www.mercadopublico.cl/FichaLicitacion/RetornaDocumento.aspx?id=${args.id_documento}`;
|
|
47
|
+
return {
|
|
48
|
+
content: [{
|
|
49
|
+
type: 'text',
|
|
50
|
+
text: `Enlace de descarga oficial del documento:\n${url}\n\nNota: Este enlace es público y se puede abrir directamente en el navegador para descargar el archivo.`,
|
|
51
|
+
}],
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
// ─── 2. DESCARGAR Y LEER DOCUMENTO DE PROCESO (REMOTO) ───────────────
|
|
55
|
+
server.registerTool('descargar_y_leer_documento', {
|
|
56
|
+
description: 'Descarga un documento adjunto de Mercado Público (bases técnicas/administrativas) en formato PDF usando su ID, extrae su texto y lo retorna al LLM. Útil para auditar requisitos técnicos de una oferta.',
|
|
57
|
+
inputSchema: {
|
|
58
|
+
id_documento: z.string().describe('ID único del documento. Ej: "123456".'),
|
|
59
|
+
query: z.string().optional().describe('Si se proporciona, busca y retorna solo fragmentos que contengan este término (case-insensitive).'),
|
|
60
|
+
max_caracteres: z.number().min(500).max(15000).default(5000).optional().describe('Límite de caracteres a retornar (default 5000) para evitar saturar el contexto de la IA.'),
|
|
61
|
+
},
|
|
62
|
+
}, async (args) => {
|
|
63
|
+
try {
|
|
64
|
+
const url = `https://www.mercadopublico.cl/FichaLicitacion/RetornaDocumento.aspx?id=${args.id_documento}`;
|
|
65
|
+
// Descargar PDF
|
|
66
|
+
const response = await fetch(url);
|
|
67
|
+
if (!response.ok) {
|
|
68
|
+
throw new Error(`Error HTTP al intentar descargar el documento: ${response.status} ${response.statusText}`);
|
|
69
|
+
}
|
|
70
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
71
|
+
const buffer = Buffer.from(arrayBuffer);
|
|
72
|
+
// Parsear PDF
|
|
73
|
+
const parser = new PDFParse({ data: buffer });
|
|
74
|
+
const pdfData = await parser.getText();
|
|
75
|
+
const text = pdfData.text || '';
|
|
76
|
+
if (!text.trim()) {
|
|
77
|
+
return {
|
|
78
|
+
content: [{
|
|
79
|
+
type: 'text',
|
|
80
|
+
text: `El documento con ID ${args.id_documento} se descargó pero parece estar vacío o no contiene texto legible (ej: escaneado sin OCR).`,
|
|
81
|
+
}],
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
// Si se provee una query, realizar filtrado local de coincidencias
|
|
85
|
+
if (args.query) {
|
|
86
|
+
const searchTerm = args.query.toLowerCase();
|
|
87
|
+
const lines = text.split('\n');
|
|
88
|
+
const matches = [];
|
|
89
|
+
for (let i = 0; i < lines.length; i++) {
|
|
90
|
+
const line = lines[i]?.trim();
|
|
91
|
+
if (line && line.toLowerCase().includes(searchTerm)) {
|
|
92
|
+
// Devolver la línea con algo de contexto (línea anterior y posterior)
|
|
93
|
+
const context = [];
|
|
94
|
+
if (i > 0 && lines[i - 1]?.trim())
|
|
95
|
+
context.push(`[Anterior] ${lines[i - 1]?.trim()}`);
|
|
96
|
+
context.push(`[COINCIDENCIA] ${line}`);
|
|
97
|
+
if (i < lines.length - 1 && lines[i + 1]?.trim())
|
|
98
|
+
context.push(`[Siguiente] ${lines[i + 1]?.trim()}`);
|
|
99
|
+
matches.push(context.join('\n'));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (matches.length === 0) {
|
|
103
|
+
return {
|
|
104
|
+
content: [{
|
|
105
|
+
type: 'text',
|
|
106
|
+
text: `No se encontraron coincidencias para "${args.query}" en el documento ID ${args.id_documento}. El texto inicial del documento es:\n\n${text.substring(0, 1000)}...`,
|
|
107
|
+
}],
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
content: [{
|
|
112
|
+
type: 'text',
|
|
113
|
+
text: `Coincidencias encontradas para "${args.query}" en el documento (ID: ${args.id_documento}):\n\n${matches.slice(0, 15).join('\n\n--- \n\n')}`,
|
|
114
|
+
}],
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
// Si no hay query, retornar el texto inicial
|
|
118
|
+
const limit = args.max_caracteres || 5000;
|
|
119
|
+
const truncated = text.length > limit ? `${text.substring(0, limit)}\n\n[... TEXTO TRUNCADO POR LÍMITE DE CONTEXTO ...] Código de descarga del documento completo: ${url}` : text;
|
|
120
|
+
return {
|
|
121
|
+
content: [{
|
|
122
|
+
type: 'text',
|
|
123
|
+
text: `Contenido extraído del documento (ID: ${args.id_documento}):\n\n${truncated}`,
|
|
124
|
+
}],
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
return {
|
|
129
|
+
content: [{
|
|
130
|
+
type: 'text',
|
|
131
|
+
text: `Error al procesar el documento remoto: ${error.message || String(error)}`,
|
|
132
|
+
}],
|
|
133
|
+
isError: true,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
// ─── 3. CONSULTAR DOCUMENTOS LOCALES (MANUALES/GUÍAS) ────────────────
|
|
138
|
+
server.registerTool('consultar_documentos_locales', {
|
|
139
|
+
description: 'Busca y lee información dentro de los manuales, normativas o guías de Compra Ágil almacenados localmente en la carpeta docs/ (soporta formatos .pdf, .txt, .md).',
|
|
140
|
+
inputSchema: {
|
|
141
|
+
query: z.string().optional().describe('Término de búsqueda para filtrar fragmentos del documento (ej: "monto", "criterios"). Si se omite, lista los documentos disponibles.'),
|
|
142
|
+
max_caracteres: z.number().min(500).max(15000).default(3000).optional().describe('Cantidad máxima de texto a retornar de cada coincidencia.'),
|
|
143
|
+
},
|
|
144
|
+
}, async (args) => {
|
|
145
|
+
try {
|
|
146
|
+
if (!fs.existsSync(DOCS_DIR)) {
|
|
147
|
+
fs.mkdirSync(DOCS_DIR, { recursive: true });
|
|
148
|
+
}
|
|
149
|
+
const files = getRelativeFilesRecursively(DOCS_DIR).filter(file => {
|
|
150
|
+
const ext = path.extname(file).toLowerCase();
|
|
151
|
+
const name = path.basename(file).toLowerCase();
|
|
152
|
+
return (ext === '.pdf' || ext === '.txt' || ext === '.md') && name !== 'readme.md';
|
|
153
|
+
});
|
|
154
|
+
if (files.length === 0) {
|
|
155
|
+
return {
|
|
156
|
+
content: [{
|
|
157
|
+
type: 'text',
|
|
158
|
+
text: `La carpeta local "docs/" está vacía. Guarda tus archivos PDF, TXT o MD de Compra Ágil allí para poder consultarlos con esta herramienta.\nRuta de la carpeta: ${DOCS_DIR}`,
|
|
159
|
+
}],
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
// Si no hay query, listar los archivos disponibles
|
|
163
|
+
if (!args.query) {
|
|
164
|
+
const fileList = files.map(file => {
|
|
165
|
+
const stats = fs.statSync(path.join(DOCS_DIR, file));
|
|
166
|
+
return `- ${file} (${(stats.size / 1024).toFixed(1)} KB)`;
|
|
167
|
+
}).join('\n');
|
|
168
|
+
return {
|
|
169
|
+
content: [{
|
|
170
|
+
type: 'text',
|
|
171
|
+
text: `Documentos locales de ayuda disponibles en "docs/":\n\n${fileList}\n\nPara buscar dentro de ellos, ejecuta esta herramienta especificando el parámetro "query".`,
|
|
172
|
+
}],
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
const searchTerm = args.query.toLowerCase();
|
|
176
|
+
const results = [];
|
|
177
|
+
for (const file of files) {
|
|
178
|
+
const filePath = path.join(DOCS_DIR, file);
|
|
179
|
+
const ext = path.extname(file).toLowerCase();
|
|
180
|
+
let fileText = '';
|
|
181
|
+
try {
|
|
182
|
+
if (ext === '.pdf') {
|
|
183
|
+
const buffer = fs.readFileSync(filePath);
|
|
184
|
+
const parser = new PDFParse({ data: buffer });
|
|
185
|
+
const pdfData = await parser.getText();
|
|
186
|
+
fileText = pdfData.text || '';
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
fileText = fs.readFileSync(filePath, 'utf8');
|
|
190
|
+
}
|
|
191
|
+
if (fileText.toLowerCase().includes(searchTerm)) {
|
|
192
|
+
// Buscar fragmentos relevantes
|
|
193
|
+
const lines = fileText.split('\n');
|
|
194
|
+
const fileMatches = [];
|
|
195
|
+
for (let i = 0; i < lines.length; i++) {
|
|
196
|
+
const line = lines[i]?.trim();
|
|
197
|
+
if (line && line.toLowerCase().includes(searchTerm)) {
|
|
198
|
+
const context = [];
|
|
199
|
+
if (i > 0 && lines[i - 1]?.trim())
|
|
200
|
+
context.push(`[Anterior] ${lines[i - 1]?.trim()}`);
|
|
201
|
+
context.push(`[COINCIDENCIA] ${line}`);
|
|
202
|
+
if (i < lines.length - 1 && lines[i + 1]?.trim())
|
|
203
|
+
context.push(`[Siguiente] ${lines[i + 1]?.trim()}`);
|
|
204
|
+
fileMatches.push(context.join('\n'));
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
if (fileMatches.length > 0) {
|
|
208
|
+
const limit = args.max_caracteres || 3000;
|
|
209
|
+
const matchesText = fileMatches.join('\n\n---\n\n');
|
|
210
|
+
const truncated = matchesText.length > limit ? `${matchesText.substring(0, limit)}... [TRUNCADO]` : matchesText;
|
|
211
|
+
results.push(`### Archivo: ${file}\n\n${truncated}`);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
catch (e) {
|
|
216
|
+
results.push(`### Archivo: ${file}\nError al leer o parsear: ${e.message || String(e)}`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (results.length === 0) {
|
|
220
|
+
return {
|
|
221
|
+
content: [{
|
|
222
|
+
type: 'text',
|
|
223
|
+
text: `No se encontraron coincidencias para "${args.query}" en ninguno de los ${files.length} documentos locales en "docs/".`,
|
|
224
|
+
}],
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
return {
|
|
228
|
+
content: [{
|
|
229
|
+
type: 'text',
|
|
230
|
+
text: `Resultados de búsqueda para "${args.query}" en documentos locales:\n\n${results.join('\n\n====================\n\n')}`,
|
|
231
|
+
}],
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
catch (error) {
|
|
235
|
+
return {
|
|
236
|
+
content: [{
|
|
237
|
+
type: 'text',
|
|
238
|
+
text: `Error al consultar documentos locales: ${error.message || String(error)}`,
|
|
239
|
+
}],
|
|
240
|
+
isError: true,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
//# sourceMappingURL=documentos.js.map
|