Integración LSP (Language Server Protocol)¶
Versión: 1.0 Última actualización: 2026-01-26
Introducción¶
La integración LSP permite a mcp-scan comunicarse con servidores de lenguaje como Pyright (Python), typescript-language-server (TypeScript/JavaScript) y gopls (Go). Esto proporciona:
- Análisis type-aware: Detección basada en tipos reales, no solo patrones
- Call graphs precisos: Construcción de grafos de llamadas usando información del servidor
- Resolución de símbolos: Seguimiento preciso de definiciones y referencias
- Detección de tipos peligrosos: Identificación de
Any,object,unknown
Arquitectura¶
┌─────────────────────────────────────────────────────────────────┐
│ mcp-scan │
│ ┌─────────────────────────────────────────────────────────────┐│
│ │ LSP Manager ││
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ││
│ │ │ Python │ │ TypeScript │ │ Go │ ││
│ │ │ Client │ │ Client │ │ Client │ ││
│ │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ ││
│ └─────────┼───────────────┼───────────────┼───────────────────┘│
└────────────┼───────────────┼───────────────┼────────────────────┘
│ │ │
JSON-RPC │ JSON-RPC │ JSON-RPC │
(stdio) │ (stdio) │ (stdio) │
│ │ │
┌────────▼────────┐ ┌────▼─────┐ ┌───────▼───────┐
│ Pyright │ │ tsserver │ │ gopls │
│ (subprocess) │ │(subproc) │ │ (subprocess) │
└─────────────────┘ └──────────┘ └───────────────┘
Protocolo de Comunicación¶
LSP usa JSON-RPC 2.0 sobre stdio:
- Requests: Cliente envía método + params, servidor responde
- Notifications: Cliente envía sin esperar respuesta
- Headers:
Content-Length: N\r\n\r\n{json}
Requisitos de Instalación¶
Servidores de Lenguaje Soportados¶
| Lenguaje | Servidor | Comando |
|---|---|---|
| Python | Pyright | pyright-langserver --stdio |
| TypeScript | typescript-language-server | typescript-language-server --stdio |
| JavaScript | typescript-language-server | typescript-language-server --stdio |
| Go | gopls | gopls serve |
Instalación de Servidores¶
Python (Pyright)¶
Nota: Pyright requiere Node.js 14+.
TypeScript/JavaScript¶
# Instalar typescript-language-server y typescript
npm install -g typescript typescript-language-server
# Verificar instalación
typescript-language-server --version
Go (gopls)¶
# Instalar gopls
go install golang.org/x/tools/gopls@latest
# Verificar que está en PATH
# Si ~/go/bin no está en PATH, añadirlo:
export PATH=$PATH:~/go/bin
# Verificar instalación
gopls version
Ubicaciones de Búsqueda¶
mcp-scan busca servidores en estas ubicaciones:
$PATHdel sistema~/go/bin(binarios de Go)~/.local/bin/usr/local/bin/opt/homebrew/bin(macOS ARM)~/.npm-global/bin~/node_modules/.bin
Uso desde CLI¶
Habilitar LSP¶
# Escaneo con LSP habilitado
mcp-scan scan --lsp ./mi-servidor-mcp
# Escaneo con modo debug LSP
LSP_DEBUG=1 mcp-scan scan --lsp ./mi-servidor-mcp
Configuración YAML¶
Output de Progreso¶
[*] Scanning ./mi-servidor-mcp...
[*] LSP: enabled
[*] Discovered 5 files
[*] Running pattern analysis...
[+] Scan completed in 2.3s
[+] Found 3 findings (2 high, 1 medium)
Debug Mode¶
Con LSP_DEBUG=1:
[LSP] Found 5 symbols, 4 functions in server.py
[LSP] Analyzing tool get_company_data at server.py:31:4
[LSP] type: (function) def get_company_data(data_type: str) -> str
[LSP] call graph: get_company_data -> 1 callees
Capacidades del Motor LSP¶
Operaciones Soportadas¶
| Operación | Método LSP | Uso |
|---|---|---|
| Hover | textDocument/hover |
Obtener tipos y documentación |
| Definition | textDocument/definition |
Ir a definición |
| References | textDocument/references |
Encontrar todas las referencias |
| Document Symbols | textDocument/documentSymbol |
Listar símbolos del archivo |
| Call Hierarchy | textDocument/prepareCallHierarchy |
Preparar jerarquía de llamadas |
| Incoming Calls | callHierarchy/incomingCalls |
Quién llama a una función |
| Outgoing Calls | callHierarchy/outgoingCalls |
A quién llama una función |
Flujo de Detección¶
1. Identificar Tool Handler
│
▼
2. Abrir documento en servidor LSP
│
▼
3. Obtener símbolos del documento (GetDocumentSymbols)
│
▼
4. Encontrar función handler por nombre
│
▼
5. Obtener tipo con hover en SelectionRange
│
▼
6. Verificar tipos peligrosos (Any, object, unknown)
│
▼
7. Construir call graph desde handler
│
▼
8. Buscar sinks peligrosos en el grafo
│
▼
9. Generar findings con contexto de tipo
│
▼
10. Cerrar documento
Reglas de Detección LSP¶
LSP-TYPE-001: Patrón de Tipo Peligroso¶
Severidad: Medium Confianza: Medium
Detecta cuando un tool handler tiene un tipo peligroso como Any, object o unknown.
# DETECTADO: parámetro con tipo Any
from typing import Any
@mcp.tool()
async def process_data(data: Any): # LSP-TYPE-001
# data puede ser cualquier cosa
eval(str(data))
Tipos peligrosos:
| Tipo | Lenguaje | Riesgo |
|---|---|---|
Any |
Python | Sin verificación de tipos |
object |
Python/TS | Genérico, sin restricciones |
unknown |
TypeScript | Tipo inseguro |
any |
TypeScript | Sin verificación de tipos |
LSP-TYPE-002: Parámetro con Tipo Loose¶
Severidad: Low Confianza: Medium
Detecta parámetros en el schema del tool con tipos loose.
@mcp.tool(
schema={
"properties": {
"data": {"type": "object"} # LSP-TYPE-002
}
}
)
async def process(data):
pass
LSP-SINK-001: Input de Tool Alcanza Sink Peligroso¶
Severidad: High Confianza: Medium
Detecta cuando un tool handler puede alcanzar un sink peligroso a través del call graph.
@mcp.tool()
async def execute_command(cmd: str):
# LSP construye call graph y encuentra camino a os.system
helper(cmd)
def helper(command):
run_shell(command)
def run_shell(cmd):
os.system(cmd) # LSP-SINK-001: Sink peligroso alcanzado
Sinks peligrosos rastreados:
| Sink | Tipo | Lenguaje |
|---|---|---|
os.system |
Ejecución de comandos | Python |
subprocess.run |
Ejecución de comandos | Python |
subprocess.Popen |
Ejecución de comandos | Python |
eval |
Evaluación de código | Python/JS |
exec |
Ejecución de código | Python |
open |
Acceso a ficheros | Python |
sqlite3.execute |
Ejecución SQL | Python |
cursor.execute |
Ejecución SQL | Python |
requests.get |
Petición HTTP | Python |
urllib.request |
Petición HTTP | Python |
child_process.exec |
Ejecución de comandos | Node.js |
child_process.spawn |
Ejecución de comandos | Node.js |
Construcción del Call Graph¶
Algoritmo¶
1. PrepareCallHierarchy en posición del handler
│
▼
2. Crear nodo raíz con información del símbolo
│
▼
3. Para cada profundidad hasta maxDepth:
│
├── GetOutgoingCalls del nodo actual
│ │
│ ▼
├── Para cada llamada:
│ │
│ ├── Crear nodo para el callee
│ │
│ ├── Añadir edge con call sites
│ │
│ └── Recursión si no visitado
│
└── Marcar nodo como visitado
Profundidad de Análisis¶
| Profundidad | Caso de Uso |
|---|---|
| 1-2 | Verificaciones rápidas, solo llamadas directas |
| 3-5 | Análisis estándar, cubre mayoría de vulnerabilidades |
| 5-10 | Análisis profundo, cadenas de llamadas complejas |
| 10+ | Análisis exhaustivo, impacto en rendimiento |
Default: mcp-scan usa profundidad 5.
Rendimiento¶
Tiempos de Arranque¶
| Servidor | Arranque en frío | Con caché |
|---|---|---|
| Pyright | 2-5s | <100ms |
| tsserver | 1-3s | <100ms |
| gopls | 1-2s | <100ms |
Uso de Memoria¶
| Servidor | Memoria base | Por 1000 ficheros |
|---|---|---|
| Pyright | ~150MB | +50MB |
| tsserver | ~200MB | +80MB |
| gopls | ~100MB | +30MB |
Optimizaciones¶
- Caché de clientes: El manager mantiene clientes activos entre análisis
- Documento abierto una vez: Se abre al inicio y se cierra al final
- Visitation tracking: El call graph no revisita nodos ya visitados
Integración con Otros Motores¶
Con Motor de Patrones¶
LSP complementa las reglas de patrones proporcionando contexto de tipos:
Pattern Engine LSP Detector
│ │
│ Detecta llamada │ Verifica tipo
│ a subprocess.run │ del argumento
│ │
└──────────┬───────────┘
│
▼
Finding combinado:
- Pattern: MCP-A001
- LSP: tipo str verificado
- Confianza: ALTA
Con Motor de Taint¶
LSP mejora la precisión del taint analysis:
Taint Engine LSP
│ │
│ Detecta flujo │ Obtiene tipos
│ source → sink │ en cada paso
│ │
│ Puede perder tipo │ Confirma que
│ en propagación │ tipo se mantiene
│ │
└───────────┬──────────────┘
│
▼
Traza con tipos:
[str] → [str] → [str] → sink
Limitaciones¶
Limitaciones Actuales¶
| Limitación | Impacto | Mitigación |
|---|---|---|
| Requiere servidor instalado | No funciona sin servidor | Mensaje claro de error |
| Arranque lento | Primera ejecución lenta | Caché de clientes |
| Proyectos grandes | Alto uso de memoria | Limitar ficheros analizados |
| Código dinámico | No puede seguir getattr |
Fallback a pattern matching |
| Cross-file limitado | Depende del servidor | gopls tiene mejor soporte |
Casos No Soportados¶
# LSP no puede seguir esto:
func = getattr(module, "dangerous_" + user_input)
func()
# LSP no puede analizar eval:
code = f"subprocess.run('{cmd}')"
eval(code)
# Metaprogramación:
class Meta(type):
def __new__(cls, name, bases, dct):
dct['run'] = lambda self, x: os.system(x)
return super().__new__(cls, name, bases, dct)
Troubleshooting¶
Problemas Comunes¶
Problema: El servidor no arranca
Solución: Instalar el servidor globalmente:Problema: No se encuentra gopls
Solución: Asegurar que ~/go/bin está en PATH:Problema: No se obtiene información de tipos
Solución: Verificar que el proyecto tiene configuración válida (pyproject.toml, tsconfig.json, go.mod).Problema: Análisis lento
Solución:
1. Reducir profundidad del call graph
2. Limitar ficheros analizados
3. Usar --mode fast
Verificar Instalación¶
# Python
pyright-langserver --version
# TypeScript
typescript-language-server --version
# Go
gopls version
# Ejecutar con debug para ver qué servidores se encuentran
LSP_DEBUG=1 mcp-scan scan --lsp ./proyecto
Referencias¶
- LSP Specification
- Pyright
- typescript-language-server
- gopls
- Motor de Patrones
- Análisis de Taint
- Clases de Vulnerabilidad
Esta documentación es para analistas de seguridad. Para uso general, consultar guia-usuario/.