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.
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:
- Descargar e instalar LAIN en
~/.local/lain - Opcionalmente descargar el modelo ONNX (~120MB)
- Ejecutar
lain initcon tu configuración - 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ón | Descripción | Predeterminado |
|---|---|---|
--workspace PATH | Ruta del espacio de trabajo para LAIN | . |
--transport MODE | Transporte MCP: stdio, http, ambos | stdio |
--port PORT | Puerto HTTP para el servidor MCP | 9999 |
--agent AGENT | Agente objetivo: auto, claude, cursor, windsurf, cline | auto |
--embedding-model PATH | Ruta al modelo de embeddings ONNX | - |
--download-model | Descargar modelo ONNX predeterminado (all-MiniLM-L6-v2.onnx, ~120MB) | - |
-y, --yes | Omitir 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 funcionesget_blast_radius— Todo lo afectado por un cambiotrace_dependency— De qué depende un símbologet_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— Encontrarmain(), manejadores de rutas, inicialización de aplicacionesget_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/Pythonrun_tests— Pruebas con enriquecimiento de erroresrun_clippy— cargo clippy con contexto
Gestión de proyectos
lain projects add <name> <path>— registrar un proyectolain projects list— mostrar proyectos registradoslain projects forget <name>— eliminar un proyectolain projects current— mostrar el proyecto activolain use <name>— establecer el proyecto activo (para quelainsin--workspacelo 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/Pythonrun_tests— Pruebas con enriquecimiento de erroresrun_clippy— cargo clippy con contexto
Requisitos
| Requisito | Detalles |
|---|---|
| Rust | 1.75 o más reciente |
| Git | Requerido para análisis de co-cambios |
| Modelo ONNX | Opcional — 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
| Modo | Comando | Caso de uso |
|---|---|---|
stdio | --transport stdio | Claude Code, clientes MCP |
http | --transport http --port 9999 | Panel de diagnóstico web |
both | --transport both --port 9999 | Ambos: 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:
opencode—OpenCodeAdapterescribeopencode.json(proyecto) o~/.config/opencode/opencode.json(usuario) con la forma verificada de comando de matrizmcp.<name>.{ type: "local", command: ["lain", ...], enabled: true, timeout: 30000 }, e incluyeAGENTS.mdpara el ámbito del proyecto. - Nuevo agente de primera clase:
copilot(GitHub Copilot en VS Code) —CopilotAdapterescribe.vscode/mcp.json(proyecto) o~/.copilot/mcp-config.json(usuario) con la forma verificadaservers.<name>.{ command: "lain", args: [...] }(commandde cadena +argsde matriz, distinta de OpenCode), e incluye.github/copilot-instructions.md. La filavscode_copilotrota preexistente se migró acopilot. --scope {project|user}enInit: por proyecto (predeterminado, viaja con el repositorio) o global de usuario. Actualmente respetado porinit_opencodeyinit_copilot; otros agentes lo ignoran.--workspace autoresuelve la raíz de git desde el directorio de trabajo actual del subproceso MCP mediantegit2::Repository::discover("."). Funciona con Claude Code, OpenCode y VS Code de fábrica; Kimi incluye un envoltorio/proc/$PPID/cwdporque 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.jsonmedianteclaude mcp add(el bloquemcpServersanterior en~/.claude/settings.jsonse ignoraba silenciosamente); los comandos de adaptador son nombres resolubles por PATH sin ruta completa en todos los casos;entry.mcp_section/entry.mcp_namese 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--yeses falso;LAIN.mdde Claude ampliado.
v0.4.2
lain init --agent kimiinstala~/.kimi-code/plugins/managed/lain/conkimi.plugin.json+skills/lain/SKILL.md+ registra eninstalled.json(fuente=local-path).lain init --agent geminiahora escribeGEMINI.md(nombre de archivo canónico según la documentación de gemini-cli). ElLAIN.mdanterior se ignoraba silenciosamente.
Más allá de las características principales mencionadas, las versiones recientes añadieron:
- Puntuación semántica híbrida:
semantic_searchahora combina similitud de coseno con superposición de tokens con raíces (la consulta "running" coincide con símbolos llamadosindex,indexed,indexes, etc.) - Extractos del cuerpo en las respuestas: tanto
semantic_searchcomoexplain_symbolahora 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_symbolmuestra 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.tomltienenlp_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-v2puede reclasificar los candidatos top-K del codificador bi. Desactivado por predeterminado; actívalo concross_encoder_top_k = 20. - Persistencia de embeddings volátiles: los embeddings de consultas en frío se escriben de vuelta en
graph.binpara 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/usegestiona múltiples repositorios para que no tengas que escribir--workspacecada 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étrica | con_lain | sin_lain |
|---|---|---|
| Tasa de aprobación | 5/5 (100%) | 5/5 (100%) |
| Duración mediana | 39.3s | 54.1s |
| Tokens de entrada medianos | 35,488 | 41,731 |
Observaciones clave:
- Ambas condiciones aprobaron al 100% — la corrección del error funcionó en ambas condiciones, con variación por ejecución.
with_lainusó 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