LAIN-mcp

Servidor MCP en Rust que otorga a los agentes de codificación de IA conciencia arquitectónica: grafo de conocimiento persistente, análisis de radio de explosión, detección de co-cambio mediante git y búsqueda semántica local. Sin claves API, se ejecuta completamente en las instalaciones.

Documentación

LAIN-mcp

LAIN construye un mapa de cómo se conecta todo el código de tu proyecto: qué llama a qué, qué depende de qué, qué archivos tienden a cambiar juntos. Luego permite que tu asistente de codificación con IA haga preguntas sobre ese mapa. Así, en lugar de que la IA solo mire un archivo y adivine, puede preguntar "si cambio esta función, ¿qué más se rompe?" y obtener una respuesta real. Se conecta a cualquier agente de IA que soporte MCP y se ejecuta en segundo plano mientras trabajas.

Screenshot 2026-04-29 at 9 18 15 PM

TL,DR:

# One-line install (interactive - will ask you to configure and add to PATH)
curl -fsSL https://raw.githubusercontent.com/spuentesp/lain/main/install.sh | bash

# After install: reload your shell (or open a new terminal)
source ~/.zshrc   # or ~/.bashrc

# Or non-interactive (skips prompts, auto-adds to PATH)
curl -fsSL https://raw.githubusercontent.com/spuentesp/lain/main/install.sh | \
  bash /dev/stdin --workspace . --transport both --yes

¿Qué es Lain?

Lain es un servidor MCP persistente de inteligencia de código. Construye un grafo de conocimiento consultable de tu base de código — símbolos y sus relaciones extraídos mediante LSP y tree-sitter, aumentados con historial de co-cambios de git y embeddings semánticos opcionales — y expone ese grafo a través de herramientas MCP. El valor frente a enfoques solo-LSP o basados en RAG es el razonamiento estructural entre archivos: radio de impacto para cambios propuestos, trazados de dependencias transitivas, identificación de anclas, correlación de co-cambios y decoración contextual de fallos de compilación para que los agentes puedan razonar sobre los llamadores en lugar de solo la línea que falla. Escrito en Rust, persiste entre sesiones, se mantiene fresco durante la edición mediante un vigilante de archivos que actualiza una capa volátil superpuesta sobre el grafo estático.


Instalación

Instalación rápida (recomendada - interactiva)

curl -fsSL https://raw.githubusercontent.com/spuentesp/lain/main/install.sh | bash

El instalador te preguntará para configurar:

  • Ruta del espacio de trabajo
  • Modo de transporte MCP (stdio, http, o ambos)
  • Puerto HTTP (si se usa http/ambos)
  • Agente objetivo (detecta automáticamente Claude Code, Cursor, Windsurf, Cline)
  • Si descargar el modelo ONNX para búsqueda semántica

Después de confirmar tu configuración, hará lo siguiente:

  1. Descargar e instalar LAIN en ~/.local/lain
  2. Opcionalmente descargar el modelo ONNX (~120MB)
  3. Ejecutar lain init con tu configuración
  4. Añadir LAIN a la configuración de tu agente

Instalación no interactiva (con opciones):

# Install with specific workspace and download ONNX model for semantic search
curl -fsSL https://raw.githubusercontent.com/spuentesp/lain/main/install.sh | \
  bash /dev/stdin --workspace . --transport both --download-model --yes

# Install for specific agent
curl -fsSL https://raw.githubusercontent.com/spuentesp/lain/main/install.sh | \
  bash /dev/stdin --agent cursor --yes

# See all options
curl -fsSL https://raw.githubusercontent.com/spuentesp/lain/main/install.sh | \
  bash /dev/stdin --help

Opciones de instalación:

OpciónDescripciónPredeterminado
--workspace PATHRuta del espacio de trabajo para LAIN.
--transport MODETransporte MCP: stdio, http, ambosstdio
--port PORTPuerto HTTP para el servidor MCP9999
--agent AGENTAgente objetivo: auto, claude, cursor, windsurf, clineauto
--embedding-model PATHRuta al modelo de embeddings ONNX-
--download-modelDescargar modelo ONNX predeterminado (all-MiniLM-L6-v2.onnx, ~120MB)-
-y, --yesOmitir todas las indicaciones de confirmación-

Después de la instalación:

# Reload your shell (the installer adds to ~/.zshrc or ~/.bashrc automatically)
source ~/.zshrc   # or ~/.bashrc, then open a new terminal

# Verify installation
lain --version

# Query the graph
lain query "find Function | limit 5"

Homebrew

brew tap spuentesp/lain https://github.com/spuentesp/lain
brew install lain

# Initialize
lain init

Binario precompilado

Descarga la última versión para tu plataforma desde GitHub releases, luego:

# Make executable
chmod +x lain

# Run directly
./lain --workspace /path/to/your/project --transport stdio

Compilar desde el código fuente

# Clone the repo
git clone https://github.com/spuentesp/lain.git
cd lain

# Build (requires Rust 1.75+)
cargo build --release

# Binary will be at ./target/release/lain

Inicio rápido

1. Instalar LAIN

curl -fsSL https://raw.githubusercontent.com/spuentesp/lain/main/install.sh | bash

2. Inicializar para Claude Code (u otros agentes)

# Auto-detect agent (Claude Code, Cursor, Windsurf, Cline)
lain init

# Or specify agent explicitly
lain init --agent claude

Para instalación por agente en Kimi, Claude, Cursor, Continue, Windsurf, Cline, Codex, OMP y Gemini, consulta docs/agent-installation.md.

Para configuración multi-instancia (un owner más N sidecars en el mismo espacio de trabajo), consulta docs/agent-installation.md#sidecar-mode.

3. Ejecutar

# Standard mode (for Claude Code)
lain --workspace /path/to/project --transport stdio

# With HTTP diagnostics (web UI at http://localhost:9999)
lain --workspace /path/to/project --transport both --port 9999

# With semantic search (requires ONNX model)
lain --workspace /path/to/project --embedding-model ~/.local/lain/models/all-MiniLM-L6-v2.onnx

4. (opcional) Gestionar múltiples proyectos

Si trabajas en varios repositorios, regístralos para que lain funcione sin --workspace:

lain projects add lain    ~/code/lain           # registers under basename
lain projects add other  ~/code/other-thing   # arbitrary name
lain projects list                              # see registered projects
lain use lain                                   # mark as active

# Now `lain query "..."` and `lain init` use the active project
# without typing the path each time.

lain init registra automáticamente el proyecto bajo el nombre base de su directorio, por lo que el primer uso es sin fricción.

5. (opcional) Agrupar repositorios en espacios de trabajo

Para el modo federación, declara grupos nombrados de repositorios en workspaces.yaml y carga solo el subconjunto que te interesa. Los espacios de trabajo se pueden cambiar al reiniciar el servidor; el cambio con recarga en caliente no está soportado (intencional — consulta la especificación para conocer la justificación).

# Declare a workspace (one-time)
lain workspaces create backend-team --members auth-svc,billing-svc,db-client

# Activate it (writes ~/.config/lain/active_workspace)
lain workspaces use backend-team

# Run the server scoped to that workspace
lain server --config repos.yaml --workspace auto --transport http --port 9999

Consulta docs/FEDERATION.md#workspaces para la guía completa y las nuevas herramientas MCP (list_workspaces, get_active_workspace, get_workspace, get_workspace_graph).

4. Verificar

# Check health and LSP status
curl -s -X POST http://localhost:9999/mcp -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"get_health","arguments":{}},"id":1}'

# Query the graph directly
lain query "find Function | limit 5"

Modo federación

Para preguntas estructurales a nivel de organización — "¿quién más usa esta función?", "¿qué depende de este servicio?" — ejecuta lain server --config repos.yaml para indexar N repositorios y responder consultas entre repositorios. El modo federación expone seis herramientas MCP (list_repos, get_repo_info, get_federation_health, search_org, get_cross_repo_blast_radius y get_cross_repo_blast_radius_for_repo) que responden preguntas que abarcan repositorios. Consulta docs/FEDERATION.md para la guía completa y docs/REPOS_YAML.md para el esquema de configuración.


Características clave

  • Modo federación — indexa N repositorios y responde preguntas estructurales a nivel de organización entre ellos

Lenguaje de consulta (query_graph)

Matriz de operaciones basada en JSON para recorridos flexibles del grafo:

{
  "ops": [
    { "op": "find", "type": "Function" },
    { "op": "connect", "edge": "Calls", "depth": { "min": 1, "max": 3 } },
    { "op": "filter", "label": "test" },
    { "op": "semantic_filter", "like": "error handling", "threshold": 0.35 },
    { "op": "limit", "count": 10 }
  ]
}

Operaciones disponibles: find, connect, filter, semantic_filter, group, sort, limit

Inteligencia de dependencias

  • get_call_chain — Ruta más corta entre dos funciones
  • get_blast_radius — Todo lo afectado por un cambio
  • trace_dependency — De qué depende un símbolo
  • get_coupling_radar — Archivos que cambian juntos

Análisis arquitectónico

  • find_anchors — Símbolos más llamados y más estables (pilares arquitectónicos)
  • list_entry_points — Encontrar main(), manejadores de rutas, inicialización de aplicaciones
  • get_context_depth — Qué tan lejos de un punto de entrada (capas de abstracción)
  • explore_architecture — Árbol de alto nivel de módulos y archivos

Búsqueda

  • semantic_search — Encuentra código por significado, no solo por nombres. Usa embeddings ONNX locales con puntuación híbrida (similitud de coseno + superposición de tokens con raíces) y muestra extractos del cuerpo en la respuesta. BGE-small-en-v1.5 es el modelo recomendado (mejor que MiniLM para corpus técnicos); usa un prefijo de consulta para habilitar la recuperación asimétrica estilo BGE.

Salud del código

  • find_dead_code — Código potencialmente inalcanzable (filtra valores predeterminados de traits, nombres comunes)
  • suggest_refactor_targets — Nodos con alto acoplamiento y baja estabilidad

Integración de compilación

Lain enriquece los fallos de compilación con contexto arquitectónico:

  • run_build — Compilar con análisis de errores de herramientas Rust/Go/JS/Python
  • run_tests — Pruebas con enriquecimiento de errores
  • run_clippy — cargo clippy con contexto

Gestión de proyectos

  • lain projects add <name> <path> — registrar un proyecto
  • lain projects list — mostrar proyectos registrados
  • lain projects forget <name> — eliminar un proyecto
  • lain projects current — mostrar el proyecto activo
  • lain use <name> — establecer el proyecto activo (para que lain sin --workspace lo use)

Salud del código

  • find_dead_code — Código potencialmente inalcanzable (filtra valores predeterminados de traits, nombres comunes)
  • suggest_refactor_targets — Nodos con alto acoplamiento y baja estabilidad

Integración de compilación

Lain enriquece los fallos de compilación con contexto arquitectónico:

  • run_build — Compilar con análisis de errores de herramientas Rust/Go/JS/Python
  • run_tests — Pruebas con enriquecimiento de errores
  • run_clippy — cargo clippy con contexto

Requisitos

RequisitoDetalles
Rust1.75 o más reciente
GitRequerido para análisis de co-cambios
Modelo ONNXOpcional — para búsqueda semántica

Opcional: Búsqueda semántica

Para que semantic_search funcione, necesitas un modelo de embeddings ONNX. La forma más fácil de configurarlo es usando el script de instalación proporcionado:

./scripts/install.sh

Alternativamente, puedes configurarlo manualmente:

# Create model directory
mkdir -p .lain/models

# Option A: bge-small-en-v1.5 (recommended — better MTEB scores, 384d, ~120MB)
curl -L https://huggingface.co/BAAI/bge-small-en-v1.5/resolve/main/onnx/model.onnx \
  -o .lain/models/model.onnx
curl -L https://huggingface.co/BAAI/bge-small-en-v1.5/resolve/main/tokenizer.json \
  -o .lain/models/tokenizer.json

# Option B: all-MiniLM-L6-v2 (smaller, 384d, ~80MB)
curl -L https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2/resolve/main/onnx/model.onnx \
  -o .lain/models/model.onnx
curl -L https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2/resolve/main/tokenizer.json \
  -o .lain/models/tokenizer.json

Establece la ruta del modelo:

export LAIN_EMBEDDING_MODEL=$PWD/.lain/models/model.onnx
# or
./lain --embedding-model ./.lain/models/model.onnx ...

Para recuperación asimétrica estilo BGE (mejor para consultas cortas), establece el prefijo de consulta en .lain/tuning.toml:

query_prefix = "Represent this sentence for searching relevant passages: "

Ajusta el uso de hilos de CPU (predeterminado: detección automática, min(núcleos, 4)):

[ingestion]
nlp_max_threads = 0  # 0 = auto, or set to a number

Sin el modelo, semantic_search devuelve "no disponible" pero todas las demás funciones funcionan.


Modos de transporte MCP

ModoComandoCaso de uso
stdio--transport stdioClaude Code, clientes MCP
http--transport http --port 9999Panel de diagnóstico web
both--transport both --port 9999Ambos: stdio + diagnóstico

Solución de problemas

¿Servidores LSP no listos?

# Install missing language servers
curl -X POST http://localhost:9999/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"install_language_server","arguments":{"language":"rust"}},"id":2}'

¿Grafo desactualizado?

# Sync to current git HEAD
curl -X POST http://localhost:9999/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"sync_state","arguments":{}},"id":3}'

Ver todas las herramientas disponibles:

curl -s -X POST http://localhost:9999/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"get_agent_strategy","arguments":{}},"id":4}'

Mejoras recientes (0.4.x y 0.5.0)

v0.5.0

  • Nuevo agente de primera clase: opencodeOpenCodeAdapter escribe opencode.json (proyecto) o ~/.config/opencode/opencode.json (usuario) con la forma verificada de comando de matriz mcp.<name>.{ type: "local", command: ["lain", ...], enabled: true, timeout: 30000 }, e incluye AGENTS.md para el ámbito del proyecto.
  • Nuevo agente de primera clase: copilot (GitHub Copilot en VS Code) — CopilotAdapter escribe .vscode/mcp.json (proyecto) o ~/.copilot/mcp-config.json (usuario) con la forma verificada servers.<name>.{ command: "lain", args: [...] } (command de cadena + args de matriz, distinta de OpenCode), e incluye .github/copilot-instructions.md. La fila vscode_copilot rota preexistente se migró a copilot.
  • --scope {project|user} en Init: por proyecto (predeterminado, viaja con el repositorio) o global de usuario. Actualmente respetado por init_opencode y init_copilot; otros agentes lo ignoran.
  • --workspace auto resuelve la raíz de git desde el directorio de trabajo actual del subproceso MCP mediante git2::Repository::discover("."). Funciona con Claude Code, OpenCode y VS Code de fábrica; Kimi incluye un envoltorio /proc/$PPID/cwd porque su gestor de complementos fija el directorio de trabajo actual del subproceso.
  • Correcciones de errores desde 0.4.2: Claude Code MCP ahora escribe en ~/.claude.json mediante claude mcp add (el bloque mcpServers anterior en ~/.claude/settings.json se ignoraba silenciosamente); los comandos de adaptador son nombres resolubles por PATH sin ruta completa en todos los casos; entry.mcp_section / entry.mcp_name se usan en instalar/leer/eliminar (sin literales codificados); el vigilante de archivos tolera subdirectorios inaccesibles; tiempos de espera de LSP; omisión del documento de conciencia cuando --yes es falso; LAIN.md de Claude ampliado.

v0.4.2

  • lain init --agent kimi instala ~/.kimi-code/plugins/managed/lain/ con kimi.plugin.json + skills/lain/SKILL.md + registra en installed.json (fuente=local-path).
  • lain init --agent gemini ahora escribe GEMINI.md (nombre de archivo canónico según la documentación de gemini-cli). El LAIN.md anterior se ignoraba silenciosamente.

Más allá de las características principales mencionadas, las versiones recientes añadieron:

  • Puntuación semántica híbrida: semantic_search ahora combina similitud de coseno con superposición de tokens con raíces (la consulta "running" coincide con símbolos llamados index, indexed, indexes, etc.)
  • Extractos del cuerpo en las respuestas: tanto semantic_search como explain_symbol ahora muestran el código real, no solo metadatos. Un desarrollador que pregunta "¿qué es esto?" ve la implementación.
  • Sección de grafo de llamadas: explain_symbol muestra llamadores y llamados junto al extracto de código fuente.
  • Normalización de percentiles de anclas: las puntuaciones de anclas ahora están limitadas a [0, 100] mediante min-max dentro del conjunto de candidatos, por lo que la fórmula de clasificación de búsqueda es consistente entre reindexaciones y crecimiento del corpus.
  • API de inferencia por lotes: NlpEmbedder::embed_batch() está disponible para modelos más grandes / GPU donde el procesamiento por lotes ayuda (no se usa en CPU para bge-small ya que el costo por llamada domina).
  • Número de hilos ONNX configurable: .lain/tuning.toml tiene nlp_max_threads (0 = detección automática, o establece explícitamente). Aumentar de 1 a 4-8 hilos da consultas en frío 4-5× más rápidas.
  • Reclasificador de codificador cruzado (opt-in): cross-encoder/ms-marco-MiniLM-L6-v2 puede reclasificar los candidatos top-K del codificador bi. Desactivado por predeterminado; actívalo con cross_encoder_top_k = 20.
  • Persistencia de embeddings volátiles: los embeddings de consultas en frío se escriben de vuelta en graph.bin para que los inicios de proceso posteriores no vuelvan a generar embeddings de los mismos nodos. La latencia de consultas en frío en un corpus de 1500 nodos baja de 29 s a ~5–10 s.
  • Registro de proyectos: lain projects add/list/forget/current/use gestiona múltiples repositorios para que no tengas que escribir --workspace cada vez.

Resultados de pruebas A/B

Se ejecutó una prueba A/B simple en asciinema_fix_pty_bug (un fork pequeño que hice de https://github.com/asciinema/asciinema.git) en 5 pasadas, 4 veces usando un script. Se informan los números medianos.

Métricacon_lainsin_lain
Tasa de aprobación5/5 (100%)5/5 (100%)
Duración mediana39.3s54.1s
Tokens de entrada medianos35,48841,731

Observaciones clave:

  • Ambas condiciones aprobaron al 100% — la corrección del error funcionó en ambas condiciones, con variación por ejecución.
  • with_lain usó menos tokens de entrada (~35k vs ~42k mediana), una diferencia de ~7k tokens por ejecución.

Sobre el error: La prueba que falla (pty::tests::spawn_extra_env en macOS) se origina de handle_child() estableciendo variables de entorno mediante env::set_var() antes de execvp(). La interpretación del shell de echo -n $VAR varía entre plataformas — a veces -n se trata como un argumento literal. La corrección: usar printf "%s" "$ASCIINEMA_TEST_FOO" en su lugar, portátil en todos los sistemas tipo Unix.

Esta fue una prueba que hice para comparación A/B — no una evaluación rigurosa.


Licencia

MIT — Copyright (c) 2026 spuentesp