ctxai

Un servidor MCP consciente de versiones que previene alucinaciones en la codificación de IA al validar sugerencias contra tus paquetes realmente instalados.

Documentación

ctxai

ctxai es un servidor Model Context Protocol (MCP) que hace que los asistentes de codificación con IA sean conscientes de las versiones. Lee tus paquetes instalados reales, inyecta ese contexto en el LLM y valida cada sugerencia de código contra tu entorno real, detectando importaciones alucinadas, llamadas a métodos inexistentes y paquetes fantasma peligrosos antes de que lleguen a tu editor.


El problema que resuelve

Los asistentes de codificación con IA alucinan de tres maneras específicas que son difíciles de detectar:

  1. Alucinaciones de paquetes — sugerir import helmet from 'helmet' cuando helmet no está en tu package.json
  2. Alucinaciones de métodos — llamar a prisma.user.findFirstOrThrow() cuando estás en Prisma v3, donde ese método aún no existe
  3. Paquetes fantasma — inventar nombres de paquetes como express-mongoose o react-query-utils que no existen en npm, que los actores de amenazas pueden registrar como typosquats

Los tres parecen código válido. Los tres fallan en tiempo de ejecución, o peor, instalan malware. ctxai los detecta en el momento de la sugerencia.


Cómo funciona

ctxai expone cuatro herramientas MCP que un cliente LLM (Claude Desktop, Cursor, Kiro, etc.) llama automáticamente:

get_project_context   →  scan project       →  return version fingerprint
validate_suggestion   →  check code         →  return hallucination warnings
check_package_safety  →  check new packages →  return safety issues
get_package_docs      →  fetch registry     →  return real API info

Herramienta 1 — get_project_context

Escanea la raíz de tu proyecto y devuelve una huella estructurada de cada paquete instalado y su versión exacta:

node: express@4.18.2
node: @prisma/client@3.15.2
python: fastapi@0.100.0
python: requests@2.31.0

Esta huella se inyecta en el contexto del LLM antes de cada respuesta, limitándolo a sugerir solo APIs que existen en tus versiones instaladas. Los resultados se almacenan en caché durante 5 minutos para que las llamadas repetidas dentro de una sesión sean instantáneas.

Herramienta 2 — validate_suggestion

Toma el código generado por IA y la huella de la Herramienta 1, y luego ejecuta tres capas de validación:

CapaQué compruebaTipo de advertencia
1¿Está cada paquete importado en tus dependencias?MISSING_PACKAGE
2¿Existe cada llamada a método en tu versión instalada?HALLUCINATED_METHOD
3¿Cuál es la alternativa real más cercana?Sugerencia en la advertencia

Devuelve una salida legible por humanos con el identificador exacto del problema, la gravedad y un comando de instalación corregido o una sugerencia de método.

Ejemplo de salida:

⚠️  Found 1 issue in the suggested code:

🔴 [Missing package] 'helmet' is not listed in your project dependencies.
   → Run 'npm install helmet' to add it, or check if the package name has changed.

The code above cannot run as-is. Fix the missing packages before using it.

Herramienta 3 — check_package_safety

Comprueba cada paquete nuevo que la IA sugiere instalar contra tres capas de seguridad:

CapaQué compruebaTipo de problema
1¿Existe este paquete en npm / PyPI?PHANTOM_PACKAGE
2¿Es sospechosamente similar a un paquete popular?LIKELY_TYPOSQUAT / LIKELY_CONFLATION
3¿Es completamente nuevo, no tiene repositorio o tiene muy pocas versiones?LOW_TRUST_PACKAGE

Los paquetes que ya están en tu huella se omiten: ya has tomado esa decisión de confianza.

Ejemplo de salida:

🚨 Found 1 critical issue across 1 new package.

📦 expres
   🚨 [Likely typosquat] 'expres' exists on the registry but is suspiciously
      similar to 'express' (edit distance: 1). This is a known typosquatting pattern.
      → Verify you meant 'express'. If you intentionally want 'expres', inspect
        its source code and maintainers before installing.

🛑 Do NOT install the flagged packages without manual verification.

Herramienta 4 — get_package_docs

Obtiene metadatos en vivo de npm o PyPI para una versión específica de un paquete. Lo usa el LLM para autocorregirse después de detectar una alucinación: encuentra el nombre de método correcto para la versión que realmente tienes instalada.


Arquitectura

ctxai/
├── src/
│   ├── index.ts                      # MCP server — registers all 4 tools
│   ├── formatters.ts                 # Converts typed results → readable MCP strings
│   ├── tools/
│   │   ├── getProjectContext.ts      # Tool 1: scan project + build fingerprint
│   │   ├── validateSuggestion.ts     # Tool 2: 3-layer hallucination validator
│   │   └── getPackageDocs.ts         # Tool 4: live registry metadata
│   ├── utils/
│   │   ├── checkPackageSafety.ts     # Tool 3: phantom/typosquat/trust checker
│   │   ├── registryClient.ts         # Typed npm + PyPI registry clients
│   │   ├── typosquatDetector.ts      # Levenshtein-based typosquat detection
│   │   ├── fuzzy.ts                  # Closest-match suggestions
│   │   ├── npmRegistry.ts            # npm metadata client (used by getPackageDocs)
│   │   └── pypiRegistry.ts           # PyPI metadata client (used by getPackageDocs)
│   ├── parser/
│   │   ├── responseParser.ts         # Extracts imports + method calls from code
│   │   └── fingerprintBuilder.ts     # Formats detected packages into fingerprint
│   ├── detectors/
│   │   ├── index.ts                  # Orchestrates Node + Python detection
│   │   ├── node.ts                   # Reads package.json + TypeScript API surface
│   │   └── python.ts                 # Reads requirements.txt + Python API surface
│   └── cache/
│       └── sessionCache.ts           # In-memory TTL cache (5 min)
└── benchmark/
    ├── run.ts                        # Benchmark runner with hallucination metrics
    └── prompts/                      # 28 test cases (JSON)

Instalación

Requisitos previos

  • Node.js 18+
  • TypeScript 5+
  • Python 3 (opcional, para validación de proyectos Python)

Compilación

cd ctxai
npm install
npm run build

Ejecutar

npm start
# or in dev mode (no build step)
npm run dev

El servidor se comunica a través de stdio, que es el transporte estándar de MCP.


Configuración del cliente MCP

Kiro

Añade a .kiro/settings/mcp.json en tu espacio de trabajo:

{
  "mcpServers": {
    "ctxai": {
      "command": "node",
      "args": ["/absolute/path/to/ctxai/build/index.js"],
      "disabled": false,
      "autoApprove": [
        "get_project_context",
        "validate_suggestion",
        "check_package_safety",
        "get_package_docs"
      ]
    }
  }
}

Usuarios de Windows + fnm/nvm: node puede no resolverse cuando Kiro inicia el servidor fuera de tu sesión de shell. Usa la ruta completa a node.exe en su lugar:

"command": "C:\\Users\\YOU\\AppData\\Roaming\\fnm\\node-versions\\v20.0.0\\installation\\node.exe"

Encuentra tu ruta con: Get-Command node | Select-Object -ExpandProperty Source (PowerShell)

Claude Desktop

Edita ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) o %APPDATA%\Claude\claude_desktop_config.json (Windows):

{
  "mcpServers": {
    "ctxai": {
      "command": "node",
      "args": ["/absolute/path/to/ctxai/build/index.js"]
    }
  }
}

Cursor / VS Code (Cline)

Edita tu cline_mcp_settings.json:

{
  "mcpServers": {
    "ctxai": {
      "command": "node",
      "args": ["/absolute/path/to/ctxai/build/index.js"],
      "disabled": false,
      "alwaysAllow": []
    }
  }
}

Después de añadir la configuración, recarga/reconecta los servidores MCP desde la paleta de comandos. Deberías ver ctxai con 4 herramientas listadas.


Probando la integración

1. Prueba de humo: ¿arranca el servidor?

npm run build
node build/index.js
# Expected: ctxai MCP server v0.1.0 running on stdio

2. Llamadas manuales a herramientas vía stdio

Prueba cada herramienta enviando JSON directamente al servidor:

Herramienta 1 — escanea tu proyecto:

echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_project_context","arguments":{"path":"/your/project/path"}}}' \
  | node build/index.js

Herramienta 2 — detecta un paquete faltante:

echo '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"validate_suggestion","arguments":{"code":"import helmet from \"helmet\";","contextFingerprint":"node: express@4.18.2"}}}' \
  | node build/index.js
# Expected: 🔴 [Missing package] 'helmet' is not listed in your project dependencies.

Herramienta 3 — detecta un typosquat:

echo '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"check_package_safety","arguments":{"code":"import expres from \"expres\";","contextFingerprint":"node: express@4.18.2"}}}' \
  | node build/index.js
# Expected: 🚨 [Likely typosquat] 'expres' is suspiciously similar to 'express'

Herramienta 4 — obtén documentación en vivo:

echo '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"get_package_docs","arguments":{"packageName":"express","version":"4.18.2","registry":"npm"}}}' \
  | node build/index.js

3. Ejecuta el benchmark

npm run benchmark

Salida esperada:

════════════════════════════════════════════════════════════
  HALLUCINATION REDUCTION METRICS
════════════════════════════════════════════════════════════

  Benchmark accuracy     100.0%  (28/28 tests match expected)

  Detection rate         100.0%
  False positives            0
  Precision              100.0%
  F1 Score               100.0%

Benchmark

ctxai incluye 28 casos de prueba que cubren todos los escenarios de validación. Los resultados incluyen métricas de reducción de alucinaciones: tasa de detección, precisión y puntuación F1, para que puedas medir el impacto de cualquier cambio.

Qué cubre el benchmark

CategoríaPromptsQué se prueba
Camino feliz11Código válido contra huella correcta: cero falsos positivos
Paquetes Node6Importaciones npm faltantes, simples y múltiples
Paquetes Python5Paquetes pip faltantes, normalización de guiones/guiones bajos, corrección de nombre pip
Alucinación de métodos2Métodos que no existen en la versión instalada (vía superficie API simulada)
Multi-paquete2Pruebas de estrés con 3–5 paquetes alucinados a la vez
Casos límite2Huella vacía, bloques de prosa+código

Añadir un caso de prueba

Crea un archivo JSON en benchmark/prompts/:

{
  "name": "My Test Case",
  "projectFingerprint": "node: express@4.18.2",
  "aiGeneratedCode": "import helmet from 'helmet';\nconst app = require('express')();",
  "expectedViolations": 1
}

Para pruebas de alucinación de métodos, inyecta una superficie API simulada para que la prueba no requiera node_modules real:

{
  "name": "Prisma - Method Hallucination",
  "projectFingerprint": "node: @prisma/client@3.15.2",
  "aiGeneratedCode": "const prisma = new PrismaClient();\nawait prisma.user.findFirstOrThrow({ where: { id: 1 } });",
  "apiSurfaceOverrides": {
    "@prisma/client": ["findFirst", "findMany", "create", "update", "delete"]
  },
  "expectedViolations": 1,
  "_note": "findFirstOrThrow was added in Prisma v4 — should be caught on v3"
}

Campos:

CampoRequeridoDescripción
nameNombre de prueba legible por humanos
projectFingerprintPaquetes instalados simulados (source: name@version por línea)
aiGeneratedCodeEl código generado por IA a validar
expectedViolationsNúmero exacto de advertencias esperadas
apiSurfaceOverridesSuperficie API simulada para comprobaciones de métodos (omite node_modules)
_noteDocumentación interna, ignorada por el ejecutor

Tipos de advertencias y problemas

validate_suggestion advertencias

interface ValidationWarning {
  type: "MISSING_PACKAGE" | "HALLUCINATED_METHOD" | "UNKNOWN_PACKAGE";
  severity: "error" | "warning" | "info";
  message: string;           // Human-readable description
  suggestion: string;        // Correct install command or method name
  offender: string;          // The exact identifier that triggered the warning
  packageName?: string;      // Package context (HALLUCINATED_METHOD only)
  installedVersion?: string; // Installed version (HALLUCINATED_METHOD only)
}

check_package_safety problemas

interface SafetyIssue {
  type: "PHANTOM_PACKAGE" | "LIKELY_TYPOSQUAT" | "LIKELY_CONFLATION"
      | "LOW_TRUST_PACKAGE" | "SECURITY_HOLD";
  severity: "critical" | "warning" | "info";
  packageName: string;
  ecosystem: "node" | "python";
  message: string;
  suggestion: string;
  meta?: {
    similarTo?: string;      // The popular package it resembles
    editDistance?: number;   // Levenshtein distance to the popular package
    ageInDays?: number;      // How old the package is
    versionCount?: number;   // How many versions it has
    hasRepository?: boolean; // Whether it has a repo link
  }
}

Idiomas y ecosistemas compatibles

IdiomaArchivo de paqueteRegistroValidación de métodos
JavaScript / TypeScriptpackage.jsonnpmVía definiciones de tipos de .d.ts
Pythonrequirements.txt, pyproject.tomlPyPIVía introspección de dir()

Mapeo de importación de Python a nombre pip

ctxai sabe que los nombres de importación de Python a menudo difieren de los nombres de paquetes pip y genera comandos de instalación correctos:

Importaciónpip install
from rest_framework import ...pip install djangorestframework
from PIL import Imagepip install Pillow
import cv2pip install opencv-python
from sklearn import ...pip install scikit-learn
import jwtpip install PyJWT
import yamlpip install PyYAML
from bs4 import ...pip install beautifulsoup4

Hay más de 80 mapeos integrados. Consulta src/tools/validateSuggestion.tsPYTHON_IMPORT_TO_PIP para la lista completa.


Decisiones de diseño

¿Por qué cuatro herramientas en lugar de una? Cada herramienta tiene una condición de activación distinta. get_project_context se ejecuta una vez por sesión. validate_suggestion se ejecuta en cada respuesta de código. check_package_safety se ejecuta solo cuando se sugieren nuevos paquetes. get_package_docs se ejecuta bajo demanda para autocorrección. Dividirlas permite que el LLM llame solo lo que necesita.

¿Por qué MCP? MCP es el estándar emergente para dar a los LLM acceso estructurado a herramientas locales. Cualquier cliente compatible con MCP obtiene ctxai sin integraciones personalizadas.

¿Por qué una cadena de huella en lugar de JSON? El formato de huella (node: express@4.18.2) es compacto, legible por humanos y eficiente en tokens. Encaja en el contexto del LLM sin desperdiciar tokens en sintaxis JSON.

¿Por qué no usar simplemente los datos de entrenamiento del LLM? Los datos de entrenamiento están congelados en una fecha de corte y no saben qué está instalado en tu proyecto. ctxai lee tu node_modules y requirements.txt reales en tiempo de ejecución.

¿Por qué preferir falsos negativos sobre falsos positivos? Si ctxai no puede determinar si un método existe (sin definiciones de tipos, sin stubs), permanece en silencio en lugar de advertir. Una alucinación no detectada es menos disruptiva que una falsa alarma en código válido.


Contribuciones

El benchmark es el mejor lugar para empezar. Si encuentras un caso donde ctxai produce un falso positivo o no detecta una alucinación:

  1. Añade un JSON de prompt a benchmark/prompts/ que reproduzca el problema
  2. Establece expectedViolations a lo que debería ser el comportamiento correcto
  3. Ejecuta npm run benchmark — si falla, el error está confirmado
  4. Corrige el validador y verifica que el benchmark esté en verde

Licencia

MIT