Content
# cvlac-mcp







Servidor MCP (stdio) para sincronizar tu perfil de **CvLAC** (MinCiencias) con tu portafolio web, usando **TypeScript + Playwright**.
No trae datos de nadie: tus credenciales, tus valores por defecto y tus proyectos curados viven en archivos locales que el repo ignora. Sirve para cualquier persona con una hoja de vida en CvLAC.
Permite:
- leer datos en vivo del CvLAC (`read_cvlac`)
- leer el portafolio (`read_portfolio`)
- calcular diferencias (`diff`): faltantes, a actualizar, parecidos y al día
- aplicar cambios por sección (`update_section`: `add` / `update` / `delete`)
- sincronizar de forma masiva (`sync`, con `dry_run`)
Dos garantías al escribir: **nunca crea un duplicado sin preguntar** (si ya hay algo igual o parecido devuelve `needs_confirmation` en vez de escribir) y **siempre dice qué campo falló** cuando CvLAC rechaza un formulario.
> **Uso responsable.** Esto automatiza un sitio gubernamental con tu propia cuenta. Úsalo con supervisión humana, revisa cada `dry_run` antes de aplicar y no lo dejes corriendo sin mirar.
Qué está verificado, qué falta y las limitaciones conocidas: **[ROADMAP.md](ROADMAP.md)**.
---
## Tabla de contenido
- [Inicio rápido: instalar y configurar el MCP (Linux, Windows, macOS)](#inicio-rápido-instalar-y-configurar-el-mcp-linux-windows-macos)
- [Arquitectura](#arquitectura)
- [Tools MCP disponibles](#tools-mcp-disponibles)
- [Variables de entorno](#variables-de-entorno)
- [Uso local](#uso-local)
- [Flujo recomendado](#flujo-recomendado)
- [Pruebas y build](#pruebas-y-build)
- [Troubleshooting](#troubleshooting)
- [Seguridad y buenas prácticas](#seguridad-y-buenas-prácticas)
- [Estado y roadmap](#estado-y-roadmap)
---
## Inicio rápido: instalar y configurar el MCP (Linux, Windows, macOS)
Esta es la guía oficial de instalación y configuración. Sigue los pasos en orden; cada uno incluye una verificación para no avanzar con un entorno roto.
### Paso 0 - Prerrequisitos (todas las plataformas)
Necesitas **Node.js 20 o superior**, **npm 10+** y **git**.
| Plataforma | Cómo instalar Node 20+ |
|---|---|
| **Linux** (Debian/Ubuntu) | `curl -fsSL https://deb.nodesource.com/setup_20.x \| sudo -E bash - && sudo apt-get install -y nodejs git` |
| **Linux** (cualquier distro, recomendado) | Instalar [nvm](https://github.com/nvm-sh/nvm) y luego `nvm install 20 && nvm use 20` |
| **macOS** | `brew install node@20 git` (con [Homebrew](https://brew.sh)) o nvm |
| **Windows** | `winget install OpenJS.NodeJS.LTS` y `winget install Git.Git` (o instalador desde [nodejs.org](https://nodejs.org)) |
**Verifica** (sirve igual en bash, zsh o PowerShell):
```bash
node --version # debe mostrar v20.x o superior
npm --version # debe mostrar 10.x o superior
git --version
```
### Paso 1 - Clonar el repositorio
**Linux / macOS (bash o zsh):**
```bash
cd ~/dev # o la carpeta que prefieras
git clone https://github.com/stivenson/cvlac-mcp.git
cd cvlac-mcp
```
**Windows (PowerShell):**
```powershell
cd $HOME\dev # crea la carpeta antes si no existe: mkdir $HOME\dev
git clone https://github.com/stivenson/cvlac-mcp.git
cd cvlac-mcp
```
### Paso 2 - Instalar dependencias y compilar
Igual en las tres plataformas:
```bash
npm install
npm run build
```
**Verifica:** debe existir el archivo de entrada compilado `dist/index.js`.
```bash
# Linux / macOS
ls dist/index.js
```
```powershell
# Windows (PowerShell)
Test-Path dist\index.js # debe imprimir True
```
### Paso 3 - Instalar el navegador de Playwright
El servidor automatiza CvLAC con Chromium headless. Descárgalo explícitamente (robusto en cualquier SO):
```bash
npx playwright install chromium
```
En **Linux**, si faltan librerías del sistema, instala también las dependencias nativas:
```bash
npx playwright install-deps chromium # requiere sudo en algunas distros
```
### Paso 4 - Configurar variables de entorno (`.env`)
Copia la plantilla y edita los valores:
**Linux / macOS:**
```bash
cp .env.example .env
```
**Windows (PowerShell):**
```powershell
Copy-Item .env.example .env
```
Edita `.env` con tus datos:
```bash
CVLAC_NOMBRE=TuNombre
CVLAC_CEDULA=TuDocumento
CVLAC_PASSWORD=TuPassword
CVLAC_SESSION_PATH=/ruta/a/tu/.cvlac-session.json
PORTFOLIO_URL=https://tu-usuario.github.io
```
Restringe los permisos del archivo (Linux/macOS):
```bash
chmod 600 .env
```
`CVLAC_SESSION_PATH` por plataforma (ejemplos):
- **Linux:** `/home/TU_USUARIO/.cvlac-session.json`
- **macOS:** `/Users/TU_USUARIO/.cvlac-session.json`
- **Windows:** `C:\\Users\\TU_USUARIO\\.cvlac-session.json`
### Paso 4b - Configurar tus valores por defecto (`cvlac.config.json`)
Varios formularios de CvLAC exigen campos que tu portafolio no tiene (municipio, intensidad horaria, idioma). Se declaran una vez aquí:
```bash
cp cvlac.config.example.json cvlac.config.json
```
```json
{
"portfolioUrl": "https://tu-usuario.github.io",
"ownerNamePattern": "Tu Nombre",
"defaults": {
"municipio": { "nombre": "Bogotá", "codigoDane": "11001" },
"institucionFallback": "Universidad Nacional de Colombia",
"horasSemanales": 1,
"idioma": "ES",
"pais": "CO"
}
}
```
Todo es opcional. **Si un valor falta, el campo se deja vacío y la respuesta trae un warning** — el servidor no inventa datos para tu hoja de vida.
### Paso 4c - Curar proyectos, software y eventos (`data/portfolio-extra.json`)
Estas tres secciones no se pueden leer del portafolio: necesitan metadatos que solo existen en CvLAC (tipo de proyecto, código DANE, códigos de enum). Se mantienen a mano:
```bash
cp data/portfolio-extra.example.json data/portfolio-extra.json
```
El archivo se valida al cargarse; si un ítem está mal formado, el servidor lo reporta y sigue con las demás secciones.
### Paso 5 - Registrar el MCP en Cursor
El servidor corre por **stdio** y su entrypoint real es `dist/index.js`. Añádelo al archivo de configuración MCP de Cursor.
Ubicación del archivo `mcp.json`:
- **Global** — Linux/macOS: `~/.cursor/mcp.json` · Windows: `%USERPROFILE%\.cursor\mcp.json`
- **Por proyecto** — `<proyecto>/.cursor/mcp.json`
Contenido (ajusta la ruta de `args` a tu sistema):
```json
{
"mcpServers": {
"cvlac-mcp": {
"command": "node",
"args": ["/home/TU_USUARIO/dev/cvlac-mcp/dist/index.js"]
}
}
}
```
Ruta de `args` según el SO:
- **Linux:** `"/home/TU_USUARIO/dev/cvlac-mcp/dist/index.js"`
- **macOS:** `"/Users/TU_USUARIO/dev/cvlac-mcp/dist/index.js"`
- **Windows:** `"C:\\Users\\TU_USUARIO\\dev\\cvlac-mcp\\dist\\index.js"` (usa dobles barras invertidas en JSON)
> **Deja las credenciales solo en `.env`.** El servidor lo carga desde su propio directorio, así que no hace falta repetirlas en `mcp.json` — y ese archivo suele estar en tu home sin permisos restringidos, o sincronizado entre máquinas. Si aun así las pones en el bloque `env`, ganan sobre `.env`.
### Paso 6 - Verificar la instalación
1. **Build y tests** en verde:
```bash
npm run build
npm test
```
2. **Arranque del servidor** (sanity check; queda esperando por stdio, ciérralo con `Ctrl+C`):
```bash
node dist/index.js
```
3. **En Cursor:** reinicia/recarga, abre los ajustes de MCP y confirma que `cvlac-mcp` aparece activo (indicador verde) y lista sus tools.
4. **Prueba funcional mínima** desde el chat de Cursor, en este orden:
- `login` (debe autenticar y persistir sesión)
- `read_portfolio` (debe devolver datos del portafolio)
- `diff` (debe reportar `missing` / `upToDate`)
Si los tres responden sin error, el MCP quedó correctamente instalado y configurado.
---
## Arquitectura
```text
src/
├── index.ts # Entry point (dotenv + stdio transport)
├── server.ts # Registro de tools MCP
├── types.ts # Tipos de portfolio/CvLAC/diff/update
├── diff.ts # Motor de comparación (normalize + nameMatches)
├── browser/
│ ├── session.ts # Login, sesión persistente, Playwright context
│ └── navigation.ts # URLs de listas y formularios CvLAC
├── tools/
│ ├── login.ts
│ ├── read-cvlac.ts
│ ├── read-portfolio.ts
│ ├── diff.ts
│ ├── update-section.ts # add/update/delete por sección
│ ├── sync.ts
│ └── screenshot.ts
└── extractors/
├── portfolio.ts
└── cvlac/
formacion.ts experiencia.ts cursos.ts reconocimientos.ts
proyectos.ts software.ts eventos.ts
```
---
## Tools MCP disponibles
- `login`: autentica en CvLAC y persiste sesión.
- `read_cvlac`: lee una sección o todas (`all`) desde CvLAC.
- `read_portfolio`: obtiene y parsea el portafolio.
- `diff`: compara CvLAC vs portafolio y reporta cuatro grupos: `missing`, `toUpdate`, `similar` (parecidos a algo existente) y `upToDate`.
- `update_section`: aplica cambio puntual (`add`, `update`, `delete`). Devuelve `status`, `warnings` por campo y, si detecta un posible duplicado, `needs_confirmation` con los candidatos. `confirm_duplicate:true` fuerza la creación.
- `sync`: ejecuta diff + aplica `missing` y `toUpdate` (con `dry_run` opcional). Los `similar` nunca se aplican solos.
- `screenshot`: captura pantalla del estado actual.
- `inspect_form`: inspecciona campos reales (`input/select/textarea`) de una URL CvLAC.
Secciones soportadas:
`formacion`, `experiencia`, `cursos`, `reconocimientos`, `proyectos`, `software`, `eventos`.
---
## Variables de entorno
Definidas en `.env` (ver [Paso 4](#paso-4---configurar-variables-de-entorno-env)):
| Variable | Descripción |
|---|---|
| `CVLAC_NOMBRE` | Nombre con el que inicias sesión en CvLAC |
| `CVLAC_CEDULA` | Documento de identidad |
| `CVLAC_PASSWORD` | Contraseña de CvLAC |
| `CVLAC_SESSION_PATH` | Ruta donde se guarda `storageState` para reusar sesión |
| `PORTFOLIO_URL` | Portafolio a comparar. También configurable como `portfolioUrl` en `cvlac.config.json` |
Opcionales:
| Variable | Descripción |
|---|---|
| `CVLAC_HEADLESS` | `false` abre el navegador para ver qué hace |
| `CVLAC_LOG_LEVEL` | `debug` \| `info` (default) \| `warn` \| `error` \| `silent`. Los logs van a stderr |
| `CVLAC_LOG_FILE` | Además de stderr, agrega cada línea a este archivo |
| `CVLAC_USER_AGENT` | Reemplaza el user-agent del navegador |
| `CVLAC_CONFIG_PATH` | Ubicación alterna de `cvlac.config.json` |
| `CVLAC_PORTFOLIO_EXTRA_PATH` | Ubicación alterna de `portfolio-extra.json` |
---
## Uso local
### Modo desarrollo (sin compilar)
```bash
npm run dev
```
### Modo producción local (compilado)
```bash
npm run build
npm start
```
---
## Flujo recomendado
1. `login`
2. `sync` con `dry_run: true`
3. Revisar el reporte con una persona: faltantes, a actualizar, **parecidos** y al día
4. Resolver los parecidos uno a uno — `update` sobre el existente, o `add` con `confirm_duplicate:true`
5. Aplicar el resto: `sync` sin `dry_run`, o `update_section` por ítem revisando los `warnings`
6. Verificar con `read_cvlac` de las secciones tocadas, o `screenshot`
Si trabajas con Claude Code, la skill `cvlac-sync` del [workspace cliente](https://github.com/stivenson/cvlac-workspace) encapsula este flujo.
### Diagrama
```mermaid
flowchart LR
portfolio["read_portfolio"] --> diffEngine
cvlacRead["read_cvlac"] --> diffEngine["diff"]
diffEngine --> syncTool["sync (dry_run / apply)"]
syncTool --> updateSection["update_section add/update/delete"]
```
---
## Pruebas y build
```bash
npm test # suite completa: sin red, sin credenciales, sin CvLAC
npm run build
```
Los tests cubren extractores (contra fixtures HTML anonimizados), el motor de diff, los schemas, la carga de configuración, la redacción de secretos en logs y el reporte de `sync`. Los fixtures llevan datos ficticios a propósito: si capturas HTML real para uno nuevo, anonimízalo antes de commitear.
Comandos disponibles:
```bash
npm run dev
npm run test:watch
npm start
```
---
## Troubleshooting
### El MCP usa una versión vieja del código
- Asegúrate de ejecutar `npm run build` tras cambiar `src/`.
- El cliente MCP ejecuta `dist/index.js`, no `src/index.ts`.
### `cvlac-mcp` no aparece en Cursor
- Verifica la ruta absoluta en `args` del `mcp.json` (Paso 5) y que `dist/index.js` exista.
- En Windows, usa dobles barras invertidas (`\\`) en las rutas dentro del JSON.
- Reinicia/recarga Cursor tras editar `mcp.json`.
### Errores de Playwright al iniciar el navegador
- Ejecuta `npx playwright install chromium`.
- En Linux, añade dependencias del sistema con `npx playwright install-deps chromium`.
### Redirección inesperada a login
- La sesión pudo expirar. Ejecuta `login` nuevamente.
- Verifica que `.env` (o el `env` del `mcp.json`) tenga credenciales correctas.
### Cambios no aplican en formularios
- Algunos campos de CvLAC son `readonly` y se setean por JS.
- Usa `inspect_form` y `screenshot` para validar nombres de campo reales.
- Revisa `docs/cvlac-findings.md` como fuente de verdad.
### Falsos faltantes en `diff`
- `nameMatches()` normaliza acentos y sufijos (ej. `(Platzi)`, ` - Aprobado ...`).
- `experiencia` está intencionalmente fuera del diff automático.
---
## Seguridad y buenas prácticas
- No hardcodear credenciales.
- No commitear `.env` ni archivos de sesión/screenshot.
- Correr primero `sync` en `dry_run`.
- Para pruebas de escritura real en CvLAC, usar ítems dummy y luego eliminar.
---
## Estado del proyecto
- Lectura de las 7 secciones verificada contra navegación real.
- `update_section` soporta `add` / `update` / `delete`.
- `dist/` debe regenerarse tras cambios en `src/`.
Para detalles operativos de desarrollo interno, ver `CLAUDE.md`.
---
## Estado y roadmap
Lectura de las 7 secciones, diff, bloqueo de duplicados y escritura `add`/`delete` están verificados contra el CvLAC real. `update` está implementado pero sin probar en vivo.
Detalle completo, limitaciones conocidas y lo que sigue: **[ROADMAP.md](ROADMAP.md)**.
Hallazgos de navegación en vivo (URLs, columnas de tabla, nombres de campos, comportamiento de la sesión): **[docs/cvlac-findings.md](docs/cvlac-findings.md)**.
MCP Config
Below is the configuration for this MCP Server. You can copy it directly to Cursor or other MCP clients.
mcp.json
Connection Info
You Might Also Like
No recommendations available