Skip to main content
Glama
lucadevv

trazabilidad-mcp

by lucadevv

Trazabilidad

Motor de trazabilidad de código full-stack: construye un grafo de hechos de tu app (componentes → handlers → costuras HTTP → queries DB) y lo expone por web, MCP y CLI desde una sola fuente de verdad. Local-first, sin telemetría, el código nunca sale de tu máquina.

Estado: v1 funcional. El motor completo está implementado y verificado: extractor ts-morph, matcher de costuras HTTP, persistencia SQLite con migraciones, detección de doble-fuente, y las tres superficies vivas (CLI trazar, API REST en :8791, web en :5183, servidor MCP) y soporte multi-proyecto: un dueño apunta la herramienta a N repos reales. Las tres leen la MISMA query layer → una sola fuente de verdad.

Onboarding de un comando

Requisitos: Docker + Docker Compose.

git clone <repo> && cd trazabilidad
docker compose -f docker-compose.local.yml up --build -d

Ambos servicios se publican solo en 127.0.0.1 — nunca expuestos a la LAN (decisión de seguridad de la spec §5).

Para frenar todo:

docker compose -f docker-compose.local.yml down

Ciclo de desarrollo (hot-reload)

El compose usa bind-mount + --watch, no bakea el código:

  • apps/api corre con bun --watch → al guardar un .ts, el proceso reinicia solo.

  • apps/web corre vite con watch.usePolling → HMR cruza el FS del contenedor en macOS.

Editás en el host, el cambio se ve sin reconstruir la imagen. Solo necesitás up --build la primera vez (o tras tocar package.json / lockfile, para reinstalar deps).

Si cambiás dependencias: docker compose -f docker-compose.local.yml up --build -d recrea los contenedores y reinstala dentro de ellos.

Configuración de entorno

Convención de tres archivos en env/:

Archivo

Tracked

Contenido

env/local.env

config no-secreta (puertos, NODE_ENV)

env/local.secret.env.example

todas las keys de secretos, sin valores

env/local.secret.env

no (gitignored)

tus valores reales

v1 no tiene secretos reales (local-only, sin auth, sin servicios externos). El .example existe para fijar la convención de cara a v2.

Estructura (monorepo Bun + Turborepo)

packages/
  domain/    tipos puros del grafo (sin deps)
  core/      FactGraphBuilder + ExtractorPort (HEXAGONAL, no importa ts-morph)
  matcher/   SeamMatcher (STRATEGY, confianza descendente)
  db/        schema SQL + migraciones
  query/     query layer COMPARTIDA (fuente única que leen CLI, API y MCP)
apps/
  api/       Hono REST :8791 (bind 127.0.0.1) — /health, /index/status, /journeys, /seams, /findings
  web/       React + Vite + TanStack Router :5183 — canvas del grafo con polling de estado
  mcp/       servidor MCP stdio (SDK 1.29.0) — trace_flow, list_journeys, get_http_seams, index_status, ...
  cli/       `trazar` (index/add/projects/remove/overview/flow/journeys/seams/findings[+suppress/confirm]/serve)
examples/
  demo-login/  fixture de test: login React + Hono con plantados verificables

CLI trazar

Todos los comandos van sobre la misma query layer que la web y el MCP:

trazar index <ruta>                 # indexa un proyecto y construye el grafo de hechos
trazar add <ruta> [--name=X]        # registra un proyecto en el registro (lo verás en la web)
trazar projects                     # lista los proyectos registrados (id, name, ruta, estado)
trazar remove <id>                  # quita un proyecto del registro
trazar overview [<ruta>]            # salud del proyecto (healthScore, capas, findings por severidad)
trazar journeys [<ruta>]            # lista los journeys (entry points de UI) detectados
trazar flow <journey> [--mermaid]   # camino completo botón→DB de un journey (texto o Mermaid)
trazar seams [<ruta>] [--level=L]   # costuras HTTP con confianza y file:line de ambos lados
trazar findings [<ruta>]            # findings de doble-fuente con evidencia y estado
trazar findings suppress <key> [--reason=...]   # suprime un finding (persiste entre re-index)
trazar findings confirm <key>                   # confirma un finding
trazar serve                        # cómo levantar API + web (modo Docker demo o host)

add y index son cosas distintas: add registra la ruta en el catálogo (para verla en la web/MCP por id), index construye el grafo. index no auto-registra (deja un hint copiable); add no indexa. Mirá la sección Multi-proyecto más abajo.

Honestidad por diseño: sin index → comando copiable; stale tras editar sin re-indexar → ⚠; seams no resueltas → declaradas como huecos, nunca ocultadas. Exit codes: 0 ok · 2 uso · 1 error.

El proyecto objetivo de los comandos de lectura sale de: arg explícito > TRAZABILIDAD_PROJECT > cwd.

Instalar trazar en el PATH

El bin del CLI apunta a apps/cli/src/index.ts, que ya tiene shebang #!/usr/bin/env bun. bun link NO sirve acá: en un monorepo de workspaces solo registra el paquete para enlazarlo en otro proyecto (bun link @trazabilidad/cli), no instala el binario trazar en el PATH (verificado: tras bun link, which trazar → not found). Dos formas que sí funcionan:

Opción A — symlink al bin dir de bun (recomendada; ~/.bun/bin ya está en tu PATH si usás bun):

chmod +x apps/cli/src/index.ts
ln -sf "$(pwd)/apps/cli/src/index.ts" ~/.bun/bin/trazar
trazar journeys examples/demo-login    # ✓ funciona por el shebang

Opción B — alias/función en tu shell (si no querés tocar ~/.bun/bin):

# en ~/.zshrc o ~/.bashrc (ajustá la ruta absoluta del repo):
trazar() { bun "/ruta/al/repo/trazabilidad/apps/cli/src/index.ts" "$@"; }

Sin instalar nada, el CLI siempre corre con bun apps/cli/src/index.ts <comando> desde la raíz del repo (lo que usan los ejemplos de este README).

Multi-proyecto

Trazabilidad apunta a N proyectos desde un solo dueño. El catálogo de rutas vive en ~/.trazabilidad/projects.json (config, separado de la .db de cada proyecto). Cada superficie —web, MCP, CLI— resuelve el proyecto de forma independiente; cuando no se especifica, cae al default (env TRAZABILIDAD_PROJECT), así el demo dockerizado y los tests no se rompen.

Dos modos de arranque

Modo

Comando

Qué ve

Para qué

Demo (Docker)

docker compose -f docker-compose.local.yml up --build -d

solo el fixture montado en /repo

onboarding de un comando, conocer la herramienta

Host (bun)

bun run api:host + bun run web:host

tus repos reales (cualquier path absoluto del host)

trabajar sobre tu código de verdad

La API en Docker está encajonada al volumen montado; para apuntar a tus repos reales usá el modo host (la API corre con bun directo en loopback y ve todo el filesystem). Ambos publican solo en 127.0.0.1.

Registrar y listar proyectos (CLI)

# 1) registrar una o más rutas reales (idempotente; imprime el id estable)
trazar add ~/code/mi-api          # → ✓ registrado "mi-api" — id mi-api-3f9a2c
trazar add ~/code/mi-web --name="Front"

# 2) listar el registro con estado (id, name, ruta, ✓/✗ index, ⚠ si la ruta no existe)
trazar projects

# 3) construir el grafo de cada uno (index ≠ add; corré index aparte)
trazar index ~/code/mi-api

# 4) quitar uno del registro (no borra la .db ni el código)
trazar remove mi-api-3f9a2c

El id es estable y se deriva del path absoluto (slug(basename)-hash6), no del basename: dos repos api en carpetas distintas obtienen ids distintos, sin colisión.

El registro es CLI-only. No hay POST /add ni POST /index en la API: registrar e indexar se hacen por el CLI en el host (decisión v1 — la API es de solo lectura sobre el grafo). La web y el MCP leen el catálogo, pero quien lo escribe es trazar add / trazar remove.

Selector en la web

En modo host (bun run web:host), el sidebar muestra un dropdown que lista GET /projects. El proyecto activo vive en la URL como segmento (/p/<id>/overview, deep-linkeable). Al elegir otro proyecto, todas las vistas (overview/journeys/seams/findings/status) se re-scopean a ese proyecto. Si un proyecto está sin indexar o su ruta ya no existe, aparece con un punto rojo y un estado honesto. Sin proyectos registrados → estado vacío con CTAs copiables (trazar add / trazar index).

El param project del MCP

Cada tool del MCP acepta un project opcional (el id del registro). Con project=<id> responde sobre ese proyecto; sin el param, sobre el default (TRAZABILIDAD_PROJECT). La tool list_projects devuelve el catálogo para que el agente descubra los ids.

// un agente consulta dos proyectos en la MISMA sesión, sin reconectar:
{ "tool": "overview",      "arguments": { "project": "mi-api-3f9a2c" } }
{ "tool": "list_journeys", "arguments": { "project": "mi-web-b71e04" } }
{ "tool": "overview",      "arguments": {} }   // ← default (back-compat)

Las tres superficies pueden operar sobre proyectos distintos a la vez sin interferir: son procesos independientes que leen .dbs distintas, y cada uno cae al default cuando no se especifica.

Flujo completo con el demo

bun install

# 1) indexar el fixture → 22 nodos, 14 aristas, 3 seams (1 finding de doble-fuente)
bun apps/cli/src/index.ts index examples/demo-login

# 2) ver los journeys de UI detectados (onSubmit, signOut)
bun apps/cli/src/index.ts journeys examples/demo-login

# 3) trazar el journey de login botón→DB (con el puente honesto del extractor)
bun apps/cli/src/index.ts flow onSubmit examples/demo-login

# 4) ver el finding estrella: doble fuente de verdad de `user`
bun apps/cli/src/index.ts findings examples/demo-login

# 5) levantar API + web (consumen la MISMA verdad que el CLI)
TRAZABILIDAD_PROJECT="$(pwd)/examples/demo-login" bun apps/api/src/index.ts   # :8791
cd apps/web && bun run dev                                                    # :5183

Si editás un .tsx del demo sin re-indexar, todas las superficies (CLI, /index/status, /health, web) reportan stale con ⚠ — la verdad sigue siendo honesta hasta que vuelvas a trazar index.

Conectar el MCP a Claude Code / Claude Desktop / Cursor

El servidor MCP (apps/mcp) expone el grafo de hechos por stdio (trace_flow, list_journeys, get_http_seams, index_status, find_data_providers, list_findings, overview y list_projects) leyendo la MISMA query layer que el CLI y la API. Cada tool acepta un project opcional (el id del registro) para apuntar a un proyecto puntual; sin ese param usa la env TRAZABILIDAD_PROJECT (back-compat). Ver la sección Multi-proyecto arriba. El MCP solo LEE — indexá antes con trazar index <ruta>.

Claude Code — un comando (verificá tu sintaxis con claude mcp add --help):

claude mcp add trazabilidad \
  -e TRAZABILIDAD_PROJECT="$(pwd)/examples/demo-login" \
  -- bun "$(pwd)/apps/mcp/src/index.ts"

Comprobá la conexión con claude mcp get trazabilidad (debe decir Status: ✓ Connected). Quitalo con claude mcp remove trazabilidad. Usá -s project para escribirlo en un .mcp.json versionable del repo, o -s user para que esté disponible en todos tus proyectos.

JSON equivalente (.mcp.json en la raíz del repo, o el bloque mcpServers de la config de Claude Desktop / Cursor). Usá rutas absolutas${PWD} lo expande Claude Code; otros clientes pueden no hacerlo, poné la ruta completa:

{
  "mcpServers": {
    "trazabilidad": {
      "type": "stdio",
      "command": "bun",
      "args": ["/ruta/absoluta/al/repo/apps/mcp/src/index.ts"],
      "env": {
        "TRAZABILIDAD_PROJECT": "/ruta/absoluta/al/repo/examples/demo-login"
      }
    }
  }
}

El fixture: examples/demo-login

App de login completa (React + Hono) que es el contrato de test del producto. Planta a propósito tres situaciones que los lotes 2 y 5 deben detectar (marcadas con // FIXTURE:):

  1. Doble fuente de verdad de user: Dashboard.tsx lo lee de AuthContext, Profile.tsx lo lee directo de localStorage. → Finding double-source (LOTE 5).

  2. Fetch dinámico (fetchProfile, URL template en runtime) → seam no-resuelta visible (LOTE 2).

  3. Fetch literal fetch('/api/auth/login') → costura literal con el handler Hono (LOTE 2).

Typecheck del fixture:

bun install
bun run --filter '@trazabilidad/example-demo-login' typecheck

Limitaciones conocidas v1

Trazabilidad declara sus huecos en vez de ocultarlos. Lo que v1 todavía NO cubre:

  • sessionStorage y claves dinámicas no se detectan como fuente de estado. El extractor reconoce localStorage con clave literal y el Context explícito; una doble-fuente sobre sessionStorage (o localStorage con una clave armada en runtime) no genera finding y find_data_providers devuelve 0 proveedores. Cobertura ampliable en v2.

  • finding_key vs renames. La identidad de un finding (para que la supresión persista entre re-index) se deriva del contenido del hecho; si renombrás el símbolo/archivo involucrado, la key cambia y una supresión previa no se reasocia automáticamente al finding "equivalente".

  • Puente del flujo botón→DB es heurístico. Cuando el extractor no puede unir dos tramos con certeza (p. ej. una URL armada en runtime), declara la costura como no-resuelta (hueco visible) en lugar de inventar una arista — preferimos un hueco honesto a una conexión falsa.

  • La API es de SOLO LECTURA sobre el grafo + supresión/confirmación de findings. El indexado se dispara únicamente por CLI (trazar index); no hay POST /index en v1 (cola + progreso es backlog v2).

  • DB local single-project, single-writer. La base SQLite usa journal_mode=DELETE (no WAL): se comparte host↔contenedor por bind-mount sobre VirtioFS, donde el -shm de WAL no es coherente y causaba "disk I/O error" intermitentes y estados divergentes. DELETE serializa escritor↔lectores, aceptable para un dev local; no es una DB pensada para concurrencia multi-cliente.

  • Sin auth ni multi-tenant. Local-first, bind 127.0.0.1, sin telemetría; multi-usuario/remoto es la visión SaaS de v2, no v1.

F
license - not found
-
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/lucadevv/trazabilidad'

If you have feedback or need assistance with the MCP directory API, please join our Discord server