mcp-despliegue-local
by JMG3ND
README.md
# mcp-despliegue-local
Agente de diagnóstico de **solo lectura** para servicios Node/Nitro que corren bajo
**pm2 en un servidor Windows on-premise**. Se expone como servidor MCP por HTTP, así que
un asistente de IA puede contestar, sin que nadie entre por escritorio remoto:
1. ¿Qué build corre ahí, y desde cuándo?
2. ¿Está vivo?
3. ¿Qué dice el log?
4. ¿Qué configuración tiene cargada?
5. **¿El proceso vivo arrancó con la configuración que hoy está en disco, o con una anterior?**
La quinta es la que justifica el proyecto. pm2 conserva el entorno con el que arrancó cada
proceso, y `pm2 restart` **no lo recarga y no lo dice**. El síntoma es «cambié el archivo y no
pasa nada» y cuesta media hora cada vez. El agente compara por huella el archivo en disco
contra el entorno del proceso vivo y responde directamente si divergen.
## Qué NO es
- **No despliega.** No construye, no copia, no reinicia, no escribe. Ni una sola ruta de
escritura existe en la tabla de enrutado — no está desactivada por bandera, no existe.
El despliegue está diseñado por escrito en [`docs/V1-DESPLIEGUE.md`](docs/V1-DESPLIEGUE.md)
y deliberadamente no implementado.
- **No es un monitor.** No agrega, no alerta, no guarda serie temporal. Contesta preguntas
cuando se las hacen.
- **No adivina.** No prueba `/health` ni `/healthz` a ver si suena. Cada servicio declara cómo
se sondea, o declara que no se sondea.
- **No exige nada a los servicios vigilados.** Ni una línea de código, ni un endpoint de versión,
ni una variable nueva. Todo se infiere desde el disco.
## Por qué existe
En un servidor de planta nadie sabe qué versión corre. Los servicios de este tipo declaran
`version: "0.0.0"` en su `package.json`, no exponen commit ni fecha de build, y no tienen
endpoint de versión. Preguntar «¿está actualizado?» no tiene respuesta, y la que se da es
un recuerdo.
El agente responde con **evidencia etiquetada**: cada dato de build viene con su origen y su
nivel de confianza, y esa etiqueta nunca sube de tono al resumirse. Una herramienta de
diagnóstico que exagera lo que sabe es una que miente. Los límites están escritos, uno a uno,
en [`docs/DIAGNOSTICO.md`](docs/DIAGNOSTICO.md) — es el documento que más importa de este repo.
## Arranque en 10 minutos
Requiere Node ≥ 22.19 y pm2 en la máquina vigilada.
```bash
git clone <este-repo> C:\agentes\mcp-despliegue-local
cd C:\agentes\mcp-despliegue-local
npm install
```
1. **Descriptor.** Copia `ejemplos/servicios.ejemplo.mjs` a tu repo privado (nunca a este) y
describe tus servicios. Empieza por uno solo, con `sonda: { tipo: 'ninguna' }`.
Esquema completo en [`docs/DESCRIPTORES.md`](docs/DESCRIPTORES.md).
2. **Entorno.** `cp env.ejemplo .env` y rellena:
```
DESPLIEGUE_LOCAL_TOKEN=<32 caracteres o más, generado al azar>
DESPLIEGUE_LOCAL_DESCRIPTORES=D:\servicios\configuracion\servicios.mjs
```
Genera el token con `node -p "require('crypto').randomBytes(32).toString('hex')"`.
Con menos de 32 caracteres el agente **sale con código 1** y te dice por qué.
3. **Arranca bajo pm2.**
```bash
pm2 start ecosystem.config.cjs
pm2 save
```
4. **Verifica sin un modelo delante.** `/salud` no pide token y no devuelve datos:
```bash
curl http://127.0.0.1:7717/salud
```
```json
{ "ok": true, "contrato": 1, "version": "0.1.0", "arrancadoEn": "2026-09-08T09:12:44.001Z",
"expuesto": false, "descriptores": { "cargados": 4, "invalidos": 0, "avisos": 1 } }
```
5. **Registra el MCP** en el consumidor. No hace falta OAuth ni un puente stdio: el agente
**es** el servidor MCP por Streamable HTTP y `.mcp.json` admite cabeceras estáticas con
expansión de variables de entorno.
```json
{ "mcpServers": { "planta": {
"type": "http",
"url": "https://agente.example.com/mcp",
"headers": { "Authorization": "Bearer ${TOKEN_DESPLIEGUE_LOCAL}" }
} } }
```
Con `headers` puesto, un 401 se reporta como fallo de conexión y **no** dispara el flujo OAuth.
El runbook completo — proxy inverso, servicio de arranque, verificación paso a paso — está en
[`docs/INSTALACION.md`](docs/INSTALACION.md).
## Salida de ejemplo
`estado_de_los_servicios` es la primera llamada de cualquier diagnóstico y casi siempre la
única que hace falta:
```
4 servicios descritos, 3 en línea.
inventario en línea 3 d 4 h build 2026-09-04 (sello.json, confianza alta)
sonda http /contrato → 200 en 41 ms. Alcance: http.
etiquetas en línea 3 d 4 h build 2026-09-04 (nitro.json, confianza media)
sonda http /api/etiqueta → 400 en 18 ms, esperado. Alcance: proceso:
contesta, pero esto no prueba que emita etiquetas.
telemetria en línea 41 min build 2026-09-08 (mtime de entrada, confianza BAJA —
probablemente la fecha del copiado, no la del build).
sonda websocket → 101. Alcance: proceso.
AVISO: el archivo de configuración en disco no es el que el proceso
tiene cargado. Divergen: NIVEL_LOG, INTERVALO_MS. Remedio:
pm2 startOrRestart, no pm2 restart.
pedidos detenido — build 2026-08-27 (nitro.json, confianza media)
Sin sonda por decisión del descriptor: solo tiene endpoints de negocio
que exigen base viva, así que un 200 no probaría nada.
Señales en disco: datos/cola.jsonl, 0 bytes, sin cambios desde hace 6 d.
```
Nada de eso es JSON crudo por accidente: toda salida de una herramienta MCP es prosa en
español ya traducida a una acción.
## Las cinco herramientas MCP
| Herramienta | Qué responde |
|---|---|
| `estado_de_los_servicios` | Pase de lista. La primera llamada, y casi siempre la única |
| `detalle_de_servicio` | Expediente de uno: build con su evidencia, proceso pm2, rutas, señales, protegidos |
| `configuracion_de_servicio` | Qué configuración tiene cargada, y si el proceso arrancó con esa o con otra |
| `bitacora_de_servicio` | Últimas N líneas del log (def. 50, tope duro 500, filtro aplicado en el servidor) |
| `estado_del_agente` | Distingue «el agente no corre» de «el agente corre pero no sabe que ese servicio existe» |
## Documentación
| Documento | Para quién |
|---|---|
| [`docs/ARQUITECTURA.md`](docs/ARQUITECTURA.md) | Quien va a leer o escribir el código |
| [`docs/DESCRIPTORES.md`](docs/DESCRIPTORES.md) | Quien describe sus servicios. Esquema campo a campo |
| [`docs/INSTALACION.md`](docs/INSTALACION.md) | Quien lo instala en el servidor. Runbook |
| [`docs/DIAGNOSTICO.md`](docs/DIAGNOSTICO.md) | Quien lee las respuestas. **Los límites de lo que el agente sabe** |
| [`docs/SEGURIDAD.md`](docs/SEGURIDAD.md) | Quien tiene que aprobar poner esto en una red industrial |
| [`docs/V1-DESPLIEGUE.md`](docs/V1-DESPLIEGUE.md) | Quien implemente el despliegue. Diseñado, no construido |
| [`CLAUDE.md`](CLAUDE.md) | Quien edite este repo, humano o asistente |
## Estado
**v0 implementado.** Los dieciséis módulos de `src/` están escritos, con 115 tests unitarios
y una prueba de aceptación de 41 comprobaciones que corre contra pm2 de verdad y un servicio
de juguete.
```bash
npm test # 115 tests unitarios
npm run utiles:aceptacion # 41 comprobaciones contra pm2 real (monta y borra su banco)
npm run verificar # higiene pública con historial + tests. Antes de publicar
```
La prueba que decide si esto sirve está en `utiles/prueba-de-aceptacion.mjs`: cambia una
variable, hace `pm2 restart` —el comando equivocado— y comprueba que el agente **detecta la
divergencia**; luego `pm2 startOrRestart` y comprueba que desaparece.
El despliegue (v1) sigue **diseñado por escrito y sin implementar**, en
[`docs/V1-DESPLIEGUE.md`](docs/V1-DESPLIEGUE.md).
## Licencia
MIT. Ver [`LICENSE`](LICENSE).
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues