Skip to content

ADR-0010: graph-service como MCP centralizado

  • Status: Accepted
  • Date: 2026-03-26
  • Deciders: DeAcero Agentic Team

Context

El pipeline de arqueología requiere un grafo de dependencias del sistema legacy para:

  1. El software-archeologist — mapear quién llama a quién, qué tablas lee/escribe cada SP
  2. El characterization-tester — detectar side effects no reversibles (edges WRITES hacia colas de email, tablas de integración externa, SAP) para clasificar escenarios como UNTESTABLE
  3. Futuros agentes (cornerstone-builder, bdd-writer) — entender el impacto de cambios

El artefacto que produce este grafo es graph_builder — un pipeline Python de 6 fases que procesa los fuentes SQL de SQL Server y produce:

  • graph.json — nodos (SPs, tablas, jobs) con edges (CALLS, READS, WRITES, DELETE, MERGE, RUNS_ON_SCHEDULE, USES_LINKED_SERVER, DEPENDS_ON)
  • tables.json — catálogo de tablas con metadata (esquema, servidor)
  • cross_server_refs.json — referencias a servidores vinculados
  • ignored.md — artefactos ignorados con razón

Problema: modelo actual (implícito)

En el modelo actual, cada proyecto que necesita el grafo debe: 1. Clonar o copiar graph_builder localmente 2. Ejecutarlo contra los fuentes del sistema legacy (potencialmente 13M líneas) 3. Mantener su propia copia de graph.json — posiblemente desactualizada 4. Asumir el costo de cómputo completo en cada proyecto

Esto es exactamente el problema que SQUIT resolvió para la búsqueda semántica SQL: construir una vez, servir a todos vía MCP.


Decision

Crear graph-service como un servidor MCP centralizado, análogo al patrón SQUIT:

[graph_builder pipeline]  →  pre-computed graph store
                                     ↓
                          [graph-service MCP server]
                                     ↓
         ┌───────────────────────────┼───────────────────────┐
         ↓                           ↓                       ↓
software-archeologist     characterization-tester     otros agentes

Responsabilidades del graph-service

Construcción (offline, centralizada): - Acepta un directorio de fuentes SQL o un snapshot del repositorio legacy - Ejecuta el pipeline graph_builder (6 fases) y almacena los grafos resultantes - Versiona los grafos por fecha de snapshot o hash del fuente - Soporta reconstrucción incremental por servidor/base de datos

Servicio (online, vía MCP):

Expone las siguientes herramientas MCP:

Herramienta Descripción
get_callers(sp_name) Retorna todos los SPs que llaman a sp_name
get_callees(sp_name) Retorna todos los SPs que sp_name llama
get_reads(sp_name) Tablas que sp_name lee (SELECT, JOIN)
get_writes(sp_name) Tablas que sp_name escribe (INSERT, UPDATE, DELETE, MERGE)
get_side_effects(sp_name) Edges hacia sistemas externos: email queues, linked servers, SAP
get_entry_points(db_name) SPs sin callers — puntos de entrada a la lógica de negocio
get_cross_server_refs(sp_name) Referencias a servidores vinculados desde sp_name
get_schedule(job_name) Schedules de SQL Agent jobs asociados a un SP
query_graph(cypher_or_sql) Query abierto contra el grafo (para exploración avanzada)

Degradación graceful

Si graph-service MCP no está disponible: - Los agentes leen graph.json local si existe en el proyecto - Si tampoco existe graph.json, el software-archeologist ejecuta graph_builder localmente y guarda el output en output/graph/ - El characterization-tester marca como UNTESTABLE todos los escenarios donde no puede determinar side effects (protocolo conservador)

Implementación técnica

graph-service/
├── server.py           ← FastMCP server (expone las herramientas MCP)
├── graph_builder/      ← el pipeline existente (graph_builder.zip) integrado como librería
│   ├── main.py
│   ├── catalog.py
│   ├── sql_parser.py
│   ├── enrichment.py
│   └── output_writer.py
├── store/
│   └── graphs/         ← grafos pre-computados por proyecto/snapshot
└── README.md

El servidor se despliega como contenedor Docker en infraestructura compartida de DeAcero. La dirección del servidor se configura en el proyecto generado vía .env:

GRAPH_SERVICE_URL=http://graph-service.internal:8080


Flujo en el pipeline

[SQL Server source files]
        ↓
  graph_builder (run once, by infra team)
        ↓
  graph-service store
        ↓  (MCP tools)
software-archeologist ──→ "qué tablas escribe sp_generar_factura?"
characterization-tester ──→ "¿tiene side effects no reversibles sp_enviar_notificacion?"
bdd-writer ──→ "cuáles son los entry points de [FACTURACION]?"

Consecuencias

Positivo

  • Grafo construido una sola vez para toda la organización — no por proyecto
  • Todos los agentes acceden a la misma versión del grafo (consistencia)
  • El characterization-tester puede clasificar UNTESTABLE con certeza en lugar de asumir
  • Reduce el tiempo de bootstrap de nuevos proyectos de arqueología
  • Centraliza el costo computacional del análisis de 5.7M objetos SQL

Negativo

  • Requiere infraestructura adicional (contenedor, almacenamiento persistente)
  • El grafo puede quedar desactualizado si los fuentes legacy cambian sin re-procesamiento
  • Agrega una dependencia de red — proyectos offline no pueden usarlo directamente (mitigado por la degradación graceful a graph.json local)

Dependencias

  • graph_builder (existente, en graph_builder.zip) — integrado como librería interna
  • FastMCP (Python) — para el servidor MCP
  • Docker — para el deployment centralizado
  • characterization-tester (ADR-0012) — consumidor primario de get_side_effects
  • software-archeologist skill — consumidor de get_callers, get_entry_points

Alternativas consideradas

Bundlear graph_builder en cada proyecto: Viable para proyectos aislados pero crea N copias desincronizadas del grafo. A medida que el sistema legacy evoluciona, mantener N grafos actualizados es inviable. Descartado.

Usar Neo4j como store del grafo: Ofrece queries Cypher más expresivos pero agrega una dependencia operacional significativa. Para el volumen actual (5.7M objetos, ~306 instancias SQL Server) un grafo en memoria o SQLite es suficiente. Puede revisarse si el volumen crece.

Graph-as-a-file (graph.json en el repo): Funciona bien para proyectos pequeños y como fallback. No escala a múltiples proyectos con grafos compartidos ni permite consultas ad-hoc. Se mantiene como fallback, no como solución principal.