Retirar el servidor MCP y fijar todas las dependencias del API
MCP: se retira por completo (endpoint, paquete api/app/mcp/ y dependencia). Tres razones, en orden de peso: - Nadie lo usa. - Llevaba roto desde antes de este trabajo. Con credencial valida devolvia 500: el handler construia un StreamableHTTPServerTransport nuevo por peticion, sin manejo de sesion. Lo que estaba expuesto a internet era la puerta abierta de un cuarto averiado. - Su SDK sin fijar tumbo el API entero en produccion al saltar a 2.0.0. Retirarlo es una mitigacion mas fuerte que autenticarlo, que fue lo que hizo el commit anterior. Recuperable con `git show edb500f5:api/app/mcp/server.py`. Se limpia tambien la ruta "/mcp" que el endpoint raiz seguia anunciando, y las menciones a MCP del docstring y la descripcion de Swagger. Dependencias: once de las doce eran rangos `>=` sin techo, o sea que cada reconstruccion era una tirada de dados contra PyPI. `pydantic>=2.0` habria aceptado pydantic 3 con la misma alegria con la que `mcp>=1.0.0` acepto 2.0.0. Ahora todas van fijadas a la version exacta que corre sana en produccion, capturada con pip freeze del contenedor healthy. El lado Next.js ya era reproducible via package-lock.json; por eso el web nunca se cayo durante el incidente y el api si. Docs actualizados: AGENTS.md, README.md, api/COTIZADOR_API_SKILL.md y el spec, que ademas registra en su seccion 0 las tres desviaciones de Fase 0 respecto a lo disenado (el Despliegue B cancelado, la retirada del MCP y la deriva de dependencia). Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 5
parent
edb500f517
commit
20f535d485
@@ -8,11 +8,60 @@
|
||||
> el análisis destapó) y Fase 1 (script local que valida si la IA escribe documentos utilizables).
|
||||
> Fases 2-4 quedan fuera y tendrán su propio ciclo.
|
||||
>
|
||||
> **Fecha:** 2026-07-28 · **Estado:** aprobado para planeación
|
||||
> **Fecha:** 2026-07-28 · **Estado:** Fase 0 desplegada en producción · Fase 1 pendiente
|
||||
> **Base verificada:** commit `26e6d3a9`
|
||||
|
||||
---
|
||||
|
||||
## 0. Registro de ejecución — Fase 0 (2026-07-28)
|
||||
|
||||
Fase 0 está en producción. Tres cosas salieron distinto de lo diseñado y este documento
|
||||
quedaría mintiendo si no se dijeran.
|
||||
|
||||
### 0.1 El movimiento de datos (Despliegue B) se canceló, no se pospuso
|
||||
|
||||
El §4.3 describe un `UPDATE` que mueve `observaciones` → `observacionesInternas`. **No se
|
||||
va a ejecutar nunca.** Al inspeccionar producción antes de migrar, la única fila con
|
||||
`observaciones` no vacías resultó ser `UJ2606AG777` (estado `aprobada`), y su texto son
|
||||
condiciones de pago dirigidas al cliente en segunda persona: *"llevamos una bitácora de
|
||||
horas con acceso para ti; a fin de mes te enviamos el reporte… solo pagas las horas
|
||||
efectivamente trabajadas."*
|
||||
|
||||
Aplicar el `UPDATE` conservador habría ocultado condiciones ya acordadas de un documento
|
||||
emitido. Esa fila ya estaba clasificada correctamente. La migración quedó reducida a
|
||||
`ADD COLUMN IF NOT EXISTS`: cero filas modificadas. Verificado tras el despliegue —
|
||||
conteos `2/3/59/5/2` idénticos al respaldo y cero filas en `observacionesInternas`.
|
||||
|
||||
**Lección para el futuro: mirar el dato real antes de diseñar su migración.** El diseño
|
||||
"conservador" era el equivocado para estos datos.
|
||||
|
||||
### 0.2 El servidor MCP se retiró en vez de asegurarse
|
||||
|
||||
El §4.1 diseñaba Fase 0-A como *"aplicar `require_auth` + lista blanca de columnas"*. Eso
|
||||
se implementó y se verificó en producción (401 sin credencial). Después se descubrió que,
|
||||
**con credencial válida, el endpoint devolvía 500**: el código construía un
|
||||
`StreamableHTTPServerTransport` por petición sin manejo de sesión. Llevaba roto desde antes
|
||||
de este trabajo — lo que estaba expuesto era la puerta abierta de un cuarto averiado.
|
||||
|
||||
Dado que nadie lo usaba, se retiró por completo (endpoint, paquete `api/app/mcp/` y la
|
||||
dependencia). Es una mitigación más fuerte que autenticarlo. Recuperable con
|
||||
`git show edb500f5:api/app/mcp/server.py`.
|
||||
|
||||
### 0.3 Una dependencia sin fijar tumbó el API 50 minutos
|
||||
|
||||
`api/requirements.txt` tenía `mcp>=1.0.0`. La primera reconstrucción en dos semanas tomó
|
||||
`mcp` 2.0.0, que eliminó `Server.list_tools()`. El import lanzó `AttributeError` al
|
||||
arrancar y el contenedor quedó en crash-loop.
|
||||
|
||||
Lo agravó que `main.py` capturara solo `ImportError` alrededor del montaje del MCP: un
|
||||
`AttributeError` se escapó y tumbó también el REST, por un componente opcional.
|
||||
|
||||
Once de las doce dependencias eran rangos `>=` sin techo. **Todas se fijaron a versión
|
||||
exacta** — las que corrían sanas en producción. El `web` (Next.js) nunca estuvo caído:
|
||||
tiene `package-lock.json` y es reproducible.
|
||||
|
||||
---
|
||||
|
||||
## 1. Por qué el alcance es este
|
||||
|
||||
El documento de negocio describe ocho subsistemas. Construirlos de una vez significa un mes de
|
||||
@@ -122,6 +171,10 @@ Cuatro bloques. A y B son prerrequisitos de C.
|
||||
|
||||
### 4.1 Fase 0-A · Cerrar el MCP
|
||||
|
||||
> **Superado por §0.2.** Esto se implementó tal cual y se verificó (401 sin credencial),
|
||||
> pero después el servidor MCP se retiró por completo. Se conserva el diseño original
|
||||
> porque documenta el agujero que existía y por qué importaba.
|
||||
|
||||
1. Aplicar `require_auth` (`api/app/auth.py:45`) al endpoint `POST /mcp` en `api/main.py:107`.
|
||||
2. Sustituir el `SELECT c.*` de `_obtener_cotizacion` (`api/app/mcp/server.py:250`) por una lista
|
||||
blanca de columnas explícita, con el mismo criterio que el REST ya aplica vía
|
||||
@@ -168,7 +221,10 @@ ninguno.
|
||||
declara `observacionesInternas` — la garantía es estructural, no disciplinaria.
|
||||
- Ningún exportador recibe el campo interno.
|
||||
|
||||
**Despliegue B — movimiento de datos.** Solo cuando A lleve días estable:
|
||||
**Despliegue B — movimiento de datos. CANCELADO, ver §0.1.** El `UPDATE` de abajo no se
|
||||
ejecutó ni se va a ejecutar: la única fila afectada contenía texto dirigido al cliente y ya
|
||||
estaba donde debía. Se conserva por si algún día aparece una instalación con datos mal
|
||||
clasificados.
|
||||
|
||||
```sql
|
||||
UPDATE "Cotizacion"
|
||||
@@ -425,7 +481,8 @@ exige normalizar saltos de línea.
|
||||
|
||||
**Fase 0** — verificable de inmediato:
|
||||
|
||||
- `POST /mcp` sin credencial devuelve 401; con credencial, `obtener_cotizacion` no expone el campo interno.
|
||||
- El endpoint `/mcp` ya no existe (§0.2). Se cumplió antes con 401 verificado; la retirada lo supera.
|
||||
- `api/requirements.txt` fija versiones exactas y el API arranca sin el paquete `mcp` (§0.3).
|
||||
- El total del PDF y el del Excel coinciden dígito por dígito en cotizaciones reales.
|
||||
- Una cotización con `incluirIva: false` no muestra IVA en ningún exportador.
|
||||
- Las notas internas no aparecen en ningún archivo exportable.
|
||||
|
||||
Reference in New Issue
Block a user