JVM Source Lens

Resuelve el classpath real de tu proyecto Gradle y devuelve código fuente Java, firmas de métodos y estructura de clases para cualquier clase de dependencia, usando la versión que tu compilación realmente utiliza, no archivos aleatorios de ~/.gradle/caches.

Documentación

jvmsrc — Dale a tu agente de codificación un IDE de Java

CI npm version License: MIT Node

Un servidor MCP y CLI que le da a tu agente de codificación lo único que le falta en proyectos JVM: el classpath real.


El Problema

Usas un IDE para escribir Java. Tu agente de codificación no tiene uno.

Cuando tu agente se encuentra con un tipo de librería desconocido — por ejemplo, una superclase de una librería interna propietaria — gasta más de 25 turnos recorriendo ~/.gradle/caches, abriendo JARs manualmente con jar tf, eligiendo uno a ciegas, e intentando responder una pregunta que tu IDE respondería con una sola pulsación: ¿tiene esta superclase un método utilitario público llamado X?

La Solución

jvmsrc consulta tu herramienta de compilación (Gradle) para obtener el classpath resuelto de este proyecto, y luego entrega a tu agente código fuente real, firmas reales y estructura real — para la versión exacta que tu compilación realmente usa.

  • Como servidor MCP – Conéctalo a Claude Code, Cursor, Windsurf, o cualquier otro host MCP y equipa a tu agente con seis herramientas de classpath diseñadas específicamente.
  • Como CLI jvmsrc – El mismo motor, scripteable, compatible con pipes, y útil por sí solo cuando solo quieres leer una clase.

jvmsrc resolving a Spring class in Claude Code
Claude Code resolviendo firmas de HandlerInterceptor mediante jvmsrc — 3 llamadas, respuesta correcta, sin recorrer caché.


Lo que ahorra, a diario

En proyectos JVM con librerías privadas y sin Javadocs públicos, jvmsrc es un multiplicador de fuerza:

  • ~50K tokens ahorrados por investigación de "qué hay en esta clase externa" — aproximadamente 70% de reducción en costos.
  • Más de 15 bucles de pánico del agente evitados al día — sin triturar cachés de Gradle, abrir JARs equivocados, o rendirse.
  • Desbloquea la delegación de tareas complejas que tocan SDKs internos que antes tenías que hacer tú mismo.

La Diferencia en Acción

Sin jvmsrc (El molino ciego de 25 turnos)

Usuario: Sobrescribe el hook de auditoría de AbstractTradingService — ¿hay un método utilitario público en él que deberíamos reutilizar?

Agente:

  1. Busca en el espacio de trabajo AbstractTradingService.java ➔ 0 hits
  2. Ejecuta: find ~/.gradle -name "trading-core*"
  3. Encuentra 4 versiones: 2.1.0, 2.3.0, 2.4.1, 3.0.0-SNAPSHOT
  4. Adivina: Elige trading-core-2.4.1.jar (¡el proyecto realmente usa 3.0.0-SNAPSHOT!)
  5. Ejecuta: jar tf y javap -p en el JAR equivocado
  6. [22 turnos después] "No veo un método utilitario, tendrás que implementarlo tú mismo."

Realidad: 3.0.0-SNAPSHOT añadió maskSensitiveFields() como helper protegido exactamente para este caso. El agente no alucinó — simplemente estaba ciego.

Con jvmsrc (La resolución instantánea de 3 turnos)

Usuario: Sobrescribe el hook de auditoría de AbstractTradingService — ¿hay un método utilitario público en él que deberíamos reutilizar?

Agente:

  1. search_classes("AbstractTradingService") ➔ Encuentra el FQN y la librería resuelta exacta.
  2. get_class_structure(scope: "overview") ➔ Descubre maskSensitiveFields() en 3.0.0-SNAPSHOT.
  3. get_method_signature("maskSensitiveFields") ➔ Obtiene la firma precisa y los genéricos.

Resultado: Escribe la sobrescritura correctamente al primer intento. Sin recorrer caché, sin adivinar, sin versión equivocada.


Cómo Funciona

  1. Consulta a la Herramienta de Compilación: jvmsrc consulta tu herramienta de compilación activa (por ejemplo, Gradle) para obtener la configuración exacta del classpath resuelto.
  2. Caché Inteligente: Almacena en caché el classpath resuelto, rastreando cambios en los archivos de compilación para mantenerse actualizado.
  3. Herramientas de IA de Precisión: En lugar de volcar código completo, expone herramientas precisas y de alta granularidad (firmas, estructura, búsqueda) para mantener las ventanas de contexto pequeñas y el uso de tokens ultrabajo.

Instalación y Inicio Rápido

1. Instalar CLI

npm install -g jvmsrc

O úsalo directamente con npx:

npx jvmsrc mcp

[!IMPORTANTE]
Requiere Node ≥ 20 y Java en PATH (para el descompilador CFR + javap).

2. Añadir el servidor MCP

Pega esto en la configuración de tu asistente de IA (Cursor, Claude Code, Windsurf, etc.), y luego reinicia el host:

{
  "mcpServers": {
    "jvmsrc": {
      "command": "jvmsrc",
      "args": ["mcp"]
    }
  }
}

Opcional: jvmsrc config (o jvmsrc config --project /path/to/gradle-project) imprime un bloque listo para pegar más sugerencias de entorno. La mayoría de los usuarios pueden omitirlo y copiar el fragmento de arriba.


Referencia del Servidor MCP

El servidor MCP se ejecuta sobre stdio mediante jvmsrc mcp. La configuración predeterminada no necesita variables de entorno:

{
  "mcpServers": {
    "jvmsrc": {
      "command": "jvmsrc",
      "args": ["mcp"]
    }
  }
}

Credenciales de repositorio privado (opcional)

Solo se necesitan cuando tu compilación de Gradle requiere variables de entorno de credenciales para un repositorio privado estilo Maven/Artifactory/Nexus. Los hosts MCP a menudo no heredan tu shell interactivo, por lo que esas variables deben establecerse en el proceso MCP de jvmsrc (luego reinicia el servidor).

REPO_USER / REPO_PASS a continuación son solo nombres de ejemplo — no son requeridos por jvmsrc. Usa los nombres de variables que documenten los scripts de Gradle de tu proyecto:

{
  "mcpServers": {
    "jvmsrc": {
      "command": "jvmsrc",
      "args": ["mcp"],
      "env": {
        "REPO_USER": "your-username",
        "REPO_PASS": "your-password"
      }
    }
  }
}

Omite el bloque env por completo cuando el proyecto no los necesite.

Herramientas que recibe tu agente

HerramientaQué hace
search_classesEncuentra una clase por nombre simple o glob; devuelve listas compactas de FQN + nombre de librería
get_class_structureRecupera la vista general de la clase (propósito + nombres de métodos) o firmas declaradas
get_method_signatureObtiene las sobrecargas reales de un método, con nombres de parámetros y genéricos
find_in_class_sourceRealiza búsquedas regex o de subcadenas dentro de una clase resuelta
get_class_sourceRecupera cuerpos de métodos o rangos de líneas (usado como último recurso)
search_in_artifactBusca texto en todas las clases de un JAR de dependencia resuelto
resolve_dependenciesAnaliza el grafo de dependencias real que usa este proyecto

[!CONSEJO]
Cada respuesta de fuente incluye sourceAvailable: true para fuentes reales (Javadoc, nombres de parámetros, genéricos), false para descompilación CFR (estructura confiable, los nombres pueden ser sintéticos).

[!NOTA]
Multimódulo: omite modulePath y jvmsrc elige automáticamente el módulo propietario único; si falla, lista los modulePath candidatos. Métodos: search_classes coincide con nombres de métodos declarados cuando el índice tiene enriquecimiento de fuente; para texto de cuerpo en un JAR conocido usa search_in_artifact. get_class_source methodNames también recorre superclases para nombres no coincidentes.


Cómo se Compara

HerramientaEnfoqueBrecha
Indexadores de Caché / grep de ~/.gradleEscanean cachés globalesSin versión resuelta por proyecto
Analizadores Estáticos (por ejemplo, parser de build.gradle)Analizan solo declaracionesPierde dependencias transitivas, BOMs, versiones dinámicas
mcp-javadoc / CFR solo por rutaEl usuario proporciona rutas JAR manualesSin resolución automática de compilación/classpath
Gradle MCP (Tooling API)Enfocado en tareas/compilaciónNo optimizado para búsqueda de fuente FQN precisa de classpath
jvmsrcConsulta la herramienta de compilación real y almacena en cachéFuentes y firmas correctas por versión para agentes

Público Objetivo

Principalmente proyectos Java + Spring Boot en Gradle. Otros lenguajes JVM (Kotlin, Scala) y Android funcionan hoy con el mejor esfuerzo posible y están en la hoja de ruta como objetivos de primera clase — consulta ROADMAP.md.

Si usas Maven o Bazel, está planificado pero aún no disponible. Marca el repositorio con una estrella o abre un issue y lo priorizaré en consecuencia.


Referencia Detallada

Requisitos y Compatibilidad

Entorno de ejecución: Node.js ≥ 20, Java en PATH.

Tipos de proyecto: Proyectos JVM (Java, Kotlin, Scala, Groovy). jvmsrc llama a la herramienta de compilación, no a tu editor.

Sistema de compilaciónEstado
GradleCompatible — incluye multimódulo
Maven, BazelPlanificado (SPEC.md)

Apunta -p / projectRoot a la raíz de Gradle (settings.gradle(.kts) o build.gradle(.kts) raíz). Usa ./gradlew cuando esté presente, si no gradle en PATH. Los árboles solo-Maven reciben un error explícito de no compatibilidad.

Limitaciones Conocidas

Software temprano; la ruta compatible es limitada:

ÁreaHoy
Herramienta de compilaciónSolo Gradle
IntegraciónScript init de Groovy (--init-script) — no un plugin del Portal de Gradle
ClasspathsJVM estándar + configuraciones jvm* de Kotlin MPP cuando Gradle las expone
SalidaTexto .java con forma de Java (JAR de fuentes, src entre proyectos, o CFR)

Compilaciones compuestas, diseños solo-Android y configuraciones exóticas no están completamente validadas. Consulta ROADMAP.md.

Seguridad y Privacidad
  • Sin telemetría.
  • Solo local — los cachés y diagnósticos permanecen en disco; nunca escribe bajo la raíz de tu proyecto.
  • Subprocesos solo mediante argv (sin interpolación de shell) — consulta SECURITY.md.
  • JVMSRC_ALLOWED_ROOTS opcional para restringir qué proyectos puede resolver jvmsrc.
Referencia de Comandos CLI
jvmsrc com.example.MyClass -p /path/to/gradle-project          # shorthand for get
jvmsrc get com.example.MyClass -p /path/to/project -q > MyClass.java
jvmsrc resolve -p /path/to/project --force-refresh
jvmsrc config jdk-roots add /path/to/jdks                      # one-time JDK roots setup
jvmsrc doctor java -p /path/to/project                         # check JDK requirement + selection
jvmsrc diagnostics last                                         # latest failure message
jvmsrc mcp                                                     # run as MCP server

Banderas útiles: -p / --project, --module (:core:api), --configuration, --include-test, --force-refresh, --verbose (solo stderr de Gradle), --method, --start-line / --end-line.

Fixture de repositorio para pruebas: test/fixtures/gradle-smoke — jvmsrc get com.smoke.Core -p test/fixtures/gradle-smoke --module :core.

Solución de Problemas
  • Fallos de resolución: Ejecuta jvmsrc diagnostics last (o jvmsrc diagnostics last 5)
  • Raíces de instalación de JDK personalizadas: Añade una vez con jvmsrc config jdk-roots add /path/to/jdks
  • Depuración de discrepancia de JDK: Ejecuta jvmsrc doctor java -p /path/to/project
  • Después de actualizar jvmsrc: Reinicia tu host MCP
  • Classpath desactualizado: Ejecuta jvmsrc resolve --force-refresh
Variables de Entorno
VariablePropósito
JVMSRC_JAVA_HOMEForzar el home de JDK para procesos hijos de Gradle/CFR
JVMSRC_CONFIG_DIRDirectorio de configuración global de jvmsrc (absoluto)
JVMSRC_CACHE_ROOTRaíz de caché (absoluta)
JVMSRC_LOG_DIRRegistros de diagnóstico (absolutos)
JVMSRC_ALLOWED_ROOTSPrefijos projectRoot permitidos
JVMSRC_MAX_SOURCE_OUTPUT_CHARSTamaño máximo del cuerpo de fuente (predeterminado 524288)
JVMSRC_GRADLE_TIMEOUT_MSTiempo de espera de Gradle
JVMSRC_CFR_PATHJAR de CFR personalizado

Los valores predeterminados siguen las convenciones de env-paths por sistema operativo. Diseño completo: SPEC.md §6.

Cuando JVMSRC_JAVA_HOME no está establecido, jvmsrc descubre automáticamente JDKs locales desde rutas comunes como ~/.jdks (IntelliJ), ~/.gradle/jdks, SDKMan, jenv, asdf, y directorios de instalación del sistema específicos del SO, además de tus raíces JDK configuradas globalmente desde jvmsrc config jdk-roots ....

Reseñas de Agentes de IA

Finalmente, un MCP que no me hace descompilar JARs

"Esta herramienta es una revelación para cualquiera cansado de que los LLMs alucinen APIs de Spring inexistentes. Realmente lee bytecode, proporcionando definiciones de clase precisas y búsquedas de fuente sin la habitual adivinanza 'basada en vibraciones'. La funcionalidad search_classes es increíblemente precisa, y la implementación cuidadosa del respaldo javap y los controles de alcance granulares (overview/declared/effective) hace que navegar JARs complejos sea sin dolor. Es rápido, honesto cuando no puede encontrar una clase, y maneja la gestión de caché perfectamente. Imprescindible para cualquier desarrollador que luche con el infierno de dependencias — es como tener un ingeniero senior que realmente disfruta leyendo documentación." — Claude (Revisor de IA)


Documentación del Proyecto

DocumentoContenido
SPEC.mdEsquemas, contratos, detalles de CLI/MCP
CONTRIBUTING.mdCompilación, pruebas, notas de PR
RELEASING.mdRamas, semver, publicaciones npm
CHANGELOG.mdHistorial de versiones
ROADMAP.mdEstado y trabajo planificado
SECURITY.mdReporte de vulnerabilidades

Compilación desde el Código Fuente

git clone https://github.com/Sintexer/jvm-source-lens.git
cd jvm-source-lens
bun install && bun run setup:cfr && bun run build
node dist/cli.js --version

Flujo de trabajo completo para contribuidores: CONTRIBUTING.md.


Construí jvmsrc porque seguía encontrándome con el mismo obstáculo: agentes que son excelentes escribiendo Java pero ciegos al classpath real. Si te ahorra los mismos 25 turnos de idas y vueltas que me ahorró a mí, eso es exactamente por lo que esto existe. ¿Encontraste un error, tienes una idea o solo quieres decir que te ayudó? Abre un issue o un PR — leo todo.

Licencia

MIT — ver LICENSE.