Skip to main content
Glama
AnderMC66

peru-gob-mcp

README.md
# peru-gob-mcp

Servidor MCP enfocado en contratacion publica y seguimiento legislativo del
Peru. MVP con dos pilares:

1. **Contrataciones Abiertas (OSCE)** - busqueda de procesos de contratacion
   publica (estandar OCDS) y un tool de deteccion de anomalias: postor unico,
   montos muy por encima de la mediana de su categoria, y concentracion de
   proveedor.
2. **Proyectos de Ley (Congreso)** - busqueda y seguimiento de proyectos de
   ley, y descarga de sus PDFs.
3. **Busqueda semantica (vectorial)** - sobre ambos dominios: encuentra
   contrataciones o proyectos de ley por significado (embeddings + ChromaDB),
   no solo por coincidencia exacta de texto. Ver seccion dedicada abajo.

## Estado de verificacion de los endpoints (leer antes de usar)

- **Congreso - listado y busqueda: confirmado end-to-end en vivo** (endpoint
  real, formato del body, y nombres de campo, no solo el dominio):
  - El listado real es `POST {base}/proyecto-ley/lista-con-filtro` con body
    `{"perParId": <int>}` (id de periodo parlamentario, ej. 2021 para
    "2021-2026"; 0 = periodo activo sin filtrar). **No pagina del lado del
    servidor** - una sola llamada sin filtro devuelve los ~15,000 proyectos
    del periodo activo, asi que este cliente pagina y filtra por `keyword`
    del lado del cliente (ver docstring de `CongresoClient.buscar_proyectos`).
  - **El dominio bloquea (403, WAF) peticiones sin un `User-Agent` de
    navegador** - ya viene resuelto en el codigo, pero es la causa mas
    probable si alguna vez ves 403 en vez de 404 en cualquier fuente.
  - Campos reales confirmados en las respuestas de listado: `proyectoLey`
    (numero, ej. "14861/2025-GR"), `titulo`, `fecPresentacion`. El listado
    **no** trae `sumilla` ni el id de archivo PDF (`proyectoArchivoId`).
  - Verificado corriendo `indexar_proyectos_ley` real: 50/50 documentos
    indexados sin errores, y `buscar_proyectos_ley_semantico("informalidad
    laboral")` devolvio resultados relevantes (proyectos sobre trabajo
    forzoso, remuneraciones, etc.) sin que esas palabras exactas aparecieran
    en los titulos.
  - **Congreso - detalle: NO confirmado**, a pesar de intentarlo en
    profundidad. `obtener_proyecto_ley` usa `GET
    {base}/proyecto-ley/{numero}?codigo={periodo}` como mejor esfuerzo, pero
    devolvio "success" con data vacia en todas las combinaciones reales de
    numero/periodo probadas. Inspeccionando el bundle JS del portal, el
    unico punto donde se llama a un metodo con esa forma de URL en realidad
    pasaba (perParId, codigo-de-congresista) como argumentos - es decir, es
    posible que ni siquiera sea un endpoint de "detalle por numero de
    proyecto". **No confies en `obtener_proyecto_ley`** hasta verificarlo
    mejor - usa `buscar_proyectos_ley` para obtener titulo/estado/fecha de
    un proyecto conocido en su lugar. Por la misma razon, no hay forma
    confirmada hoy de obtener un `archivo_id` real para
    `descargar_pdf_proyecto_ley`.
- **OSCE**: el dominio `contratacionesabiertas.osce.gob.pe` y la publicacion
  de datos en formato OCDS estan confirmados por documentacion oficial
  (gob.pe, OECD-OPSI), pero **no se pudo verificar en vivo** - el dominio no
  resuelve DNS desde ningun entorno usado durante el desarrollo (navegador y
  HTTP directo). La ruta exacta de busqueda (`/releases` por defecto) sigue
  siendo un supuesto razonable, no confirmado.

Las rutas son configurables por variable de entorno sin tocar codigo (ver
`.env.example`). **Si usas `buscar_contrataciones` y te da 404:** corre el
tool `verificar_conectividad`, abri el portal en un navegador normal, mira
la pestana Network al hacer una busqueda, y ajusta `OSCE_RELEASES_PATH` /
`OSCE_RELEASE_DETAIL_PATH` en tu `.env` (Congreso ya deberia funcionar tal
cual esta).

## Instalacion

```bash
python -m venv .venv
.venv\Scripts\activate        # Windows
pip install -e .
cp .env.example .env          # y ajustar si hace falta
```

El install es notablemente mas pesado que un servidor MCP tipico por las
dependencias transitivas de `chromadb` (onnxruntime, numpy, sqlite
embebido). No requiere PyTorch ni GPU.

## Ejecutar en modo desarrollo

```bash
mcp dev src/peru_gob_mcp/server.py
```

## Configurar en Claude Desktop / Claude Code

Agregar a la configuracion de servidores MCP:

```json
{
  "mcpServers": {
    "peru-gob-mcp": {
      "command": "python",
      "args": ["-m", "peru_gob_mcp.server"],
      "cwd": "C:/source/NONAME-MCP"
    }
  }
}
```

## Tools disponibles

| Tool | Descripcion |
|---|---|
| `buscar_contrataciones` | Busca procesos de contratacion publica (OCDS) por texto, entidad y fechas |
| `obtener_contratacion` | Detalle completo de un proceso por OCID |
| `detectar_anomalias_contratacion` | Tamizaje: postor unico, sobreprecios (z-score vs mediana de categoria), concentracion de proveedor |
| `buscar_proyectos_ley` | Busca proyectos de ley por texto, periodo o comision |
| `obtener_proyecto_ley` | Detalle de un proyecto de ley - **endpoint no confirmado, ver arriba** |
| `descargar_pdf_proyecto_ley` | Descarga el PDF de un proyecto de ley (base64) |
| `verificar_conectividad` | Diagnostico: prueba si OSCE y Congreso son alcanzables con la config actual |
| `indexar_contrataciones` | Indexa contrataciones OSCE (chunking + embeddings) en la base vectorial local |
| `buscar_contrataciones_semantico` | Busca contrataciones por significado sobre lo indexado |
| `indexar_proyectos_ley` | Indexa proyectos de ley (titulo+sumilla+PDF) en la base vectorial local |
| `buscar_proyectos_ley_semantico` | Busca proyectos de ley por significado sobre lo indexado |

`detectar_anomalias_contratacion` es un tamizaje estadistico, no una
acusacion - cada hallazgo debe verificarse caso por caso antes de sacar
conclusiones.

## Busqueda semantica

Los tools `buscar_*_semantico` NO buscan sobre todo OSCE/Congreso en vivo:
buscan sobre lo que ya indexaste con `indexar_contrataciones` /
`indexar_proyectos_ley`. Flujo tipico:

```
indexar_proyectos_ley(periodo="2021-2026", max_paginas=3)
buscar_proyectos_ley_semantico("informalidad laboral")
```

Detalles de implementacion:
- **Vector store**: ChromaDB, embebido, persiste en `VECTOR_DB_PATH`
  (default `./data/chroma`). Sin servidor que levantar.
- **Embeddings**: `fastembed` (ONNX Runtime), 100% offline/CPU, sin API key.
  Modelo default `jinaai/jina-embeddings-v2-base-es` (~0.64GB) - se descarga
  una sola vez en el primer uso a `EMBEDDING_CACHE_DIR` y queda cacheado.
  Configurable via `.env` (ver alternativas mas livianas/pesadas ahi).
- **Idempotencia**: reindexar el mismo documento (mismo `ocid`/`numero`)
  actualiza sus chunks en vez de duplicarlos - seguro llamar `indexar_*`
  repetidamente.
- **Filtros**: `entidad`/`comision`/`periodo` en los tools `_semantico` son
  coincidencia EXACTA (a diferencia de los tools de palabra clave, que hacen
  substring match del lado del servidor de OSCE/Congreso).
- El listado de proyectos de ley no trae el id de archivo PDF
  (`proyectoArchivoId`) ni la sumilla - confirmado en vivo. Por eso
  `indexar_proyectos_ley` va a reportar `tiene_texto_pdf: false` en casi
  todos los casos hoy, e indexa solo el titulo. El endpoint de detalle que
  en teoria traeria esos datos no esta confirmado (ver seccion de arriba),
  asi que incorporar sumilla/PDF al indexado queda bloqueado hasta
  encontrar el endpoint real (ver Roadmap).
- `keyword` en `buscar_proyectos_ley` (el tool de palabra clave, no el
  semantico) filtra del lado del cliente sobre `titulo` unicamente, porque
  el endpoint real del Congreso ignora un campo de texto libre en el filtro
  (confirmado en vivo probando con valores desconocidos en el body).

## Tests

```bash
pytest tests/ -v
```

La logica pura (anomalias, chunking, extraccion de PDF, construccion de
documentos indexables) y la orquestacion de los services de busqueda
semantica (paginacion, idempotencia, manejo de errores) estan cubiertas con
tests que no requieren red ni descargar el modelo de embeddings real (se
usan fakes de `EmbeddingProvider`/`VectorStore` en `tests/fakes.py`). Lo que
no se puede testear sin red (rutas HTTP reales de OSCE/Congreso, el modelo
de embeddings real) queda fuera del alcance automatico de este MVP.

## Roadmap / ideas no incluidas en este MVP

- Encontrar el endpoint real de detalle de un proyecto de ley (el supuesto
  actual, `/proyecto-ley/{numero}?codigo=...`, no esta confirmado - ver
  seccion de arriba). Una vez confirmado, `indexar_proyectos_ley` deberia
  consultarlo por cada item para incorporar sumilla y PDF al texto indexado.
- Confirmar en vivo las rutas de OSCE (no accesible desde este entorno) y
  descubrir los campos reales de filtro por comision/texto en el DTO de
  Congreso (`FiltroProyecLeyDto` - hoy solo `perParId` esta confirmado).
- Radar de ejecucion presupuestal (MEF - Consulta Amigable)
- Resolucion de series BCRP en lenguaje natural + comparativas con Banco
  Mundial/FMI
- Panel de disparidad regional (INEI)
- RAG sobre Reporte de Inflacion (BCRP) y Marco Macroeconomico Multianual (MEF)