Si has llegado buscando jadx-headless-mcp-0.7.1-all.jar, probablemente una herramienta como REA te lo ha pedido y no sabes qué bajar. Esta página lo resuelve: qué es jadx-headless-mcp, qué archivo descargar (y por qué no existe un jadx-headless-mcp-0.7.1.jar suelto), cómo comprobar que es el bueno, qué versión necesitas y cómo usarlo con Claude Code, Claude Desktop o Cursor para analizar una app de Android. Todo lo hemos probado con las versiones 0.7.1 y 0.8.0 y una app libre de F-Droid.
jadx-headless-mcp-0.7.1-all.jar (unos 42,6 MB) de la página de la versión 0.7.1, comprueba que su SHA-256 empieza por 6e5eacf5 y ejecútalo con Java 17 o posterior. Si no lo usas con REA, mejor la 0.8.0, que es más rápida.Qué es jadx-headless-mcp
JADX es el descompilador de Android más conocido: convierte una app (un archivo .apk) en código Java que se puede leer. Normalmente se usa con su ventana gráfica. jadx-headless-mcp toma solo su motor, jadx-core, y lo ofrece como un servidor MCP: un programa que un asistente de IA puede usar como herramienta para abrir la app, buscar clases y leer métodos por su cuenta, sin ventanas. Si no sabes qué es MCP, lo explicamos en qué es MCP y cómo funciona.
- Quién lo hace: está en GitHub, en 1013503897/jadx-headless-mcp, con licencia Apache 2.0. GitHub la muestra como «NOASSERTION» porque el texto del archivo
LICENSEdifiere en unas palabras del oficial, pero es la licencia Apache 2.0, con su aviso de copyright de 2026. - Qué ofrece: 26 herramientas, desde
load_apk(abrir una app) yget_app_info(paquete, versión y permisos) hastaget_class_source(el código de una clase),get_method_by_name(un método) y las referencias cruzadas (get_xrefs_to_method: quién llama a qué). - Cómo se comunica: por la entrada y salida estándar (stdio), que es lo habitual en los servidores MCP locales, o por HTTP con
--transport http. En nuestras pruebas, las versiones 0.7.1 y 0.8.0 hablan la versión 2025-11-25 del protocolo MCP. - Con qué está hecho: en Kotlin, sobre
jadx-core1.5.6 y el SDK oficial de MCP para Kotlin (0.15.0 en la versión 0.7.1).
Qué archivo descargar: -all.jar, .zip o .jar
Cada versión publica exactamente tres archivos, y ninguno se llama jadx-headless-mcp-0.7.1.jar. Por eso esa búsqueda no lleva a ninguna descarga: la dirección de GitHub con ese nombre da error 404.
jadx-headless-mcp-0.7.1-all.jar: el que necesitas. Es un «fat jar»: un solo archivo que trae el programa y todas sus dependencias. Se ejecuta conjava -jary es el que piden REA y la mayoría de instrucciones.jadx-headless-mcp-0.7.1.zip: la distribución por piezas. Trae un lanzador para Linux y macOS y otro para Windows enbin/, y 75 archivos.jarenlib/. Uno de ellos sí se llamajadx-headless-mcp-0.7.1.jar, pero es solo el programa, de 244 KB, sin sus dependencias.jadx-headless-mcp.sha256: la suma de comprobación del-all.jar, para verificar que lo has bajado entero y sin cambios.
Esto es lo que hay dentro del .zip, recortado:
contenido del .zip de la 0.7.1 249,523 jadx-headless-mcp-0.7.1/lib/jadx-headless-mcp-0.7.1.jar
1,360,937 jadx-headless-mcp-0.7.1/lib/kotlin-sdk-core-jvm-0.15.0.jar
2,381,850 jadx-headless-mcp-0.7.1/lib/jadx-core-1.5.6.jar
18,963,189 jadx-headless-mcp-0.7.1/lib/r8-9.1.31.jar
12,111 jadx-headless-mcp-0.7.1/bin/jadx-headless-mcp
3,136 jadx-headless-mcp-0.7.1/bin/jadx-headless-mcp.bat
… y otros 71 archivos .jar en lib/: 75 en totalSi sacas ese jadx-headless-mcp-0.7.1.jar del .zip e intentas ejecutarlo solo, falla, porque le faltan las otras 74 piezas:
java -jar jadx-headless-mcp-0.7.1.jar
salidaError: Unable to initialize main class com.atxx.jhmcp.MainKt Caused by: java.lang.NoClassDefFoundError: kotlin/NoWhenBranchMatchedException
Así que, si alguien te pide «el .jar de jadx-headless-mcp», lo que quiere es casi seguro el -all.jar. El .zip solo tiene sentido si prefieres el lanzador, que además pone por su cuenta algunos ajustes de memoria de Java.
Descargarlo y comprobar la suma
En Linux o macOS:
curl -fLO https://github.com/1013503897/jadx-headless-mcp/releases/download/v0.7.1/jadx-headless-mcp-0.7.1-all.jar curl -fLO https://github.com/1013503897/jadx-headless-mcp/releases/download/v0.7.1/jadx-headless-mcp.sha256 cat jadx-headless-mcp.sha256 sha256sum jadx-headless-mcp-0.7.1-all.jar # en macOS: shasum -a 256 jadx-headless-mcp-0.7.1-all.jar
salida6e5eacf500b64292bfb73c49797c1958f6ee44646e43e868039ae7feb573ff75 jadx-headless-mcp-0.7.1-all.jar 6e5eacf500b64292bfb73c49797c1958f6ee44646e43e868039ae7feb573ff75 jadx-headless-mcp-0.7.1-all.jar
Las dos líneas tienen que ser iguales. Esa suma, 6e5eacf5…, es también la que lleva anotada REA, que rechaza cualquier otro archivo. En Windows, con PowerShell, la suma se calcula con Get-FileHash .\jadx-headless-mcp-0.7.1-all.jar (sale en mayúsculas, pero es la misma).
Para la versión 0.8.0, los nombres cambian igual (v0.8.0/jadx-headless-mcp-0.8.0-all.jar) y su suma es:
jadx-headless-mcp.sha256 de la 0.8.04b9a01c23845c123c217840182d2b5f2c26a7ca20dec3d08810b310fc80a2372 jadx-headless-mcp-0.8.0-all.jar
Qué versión necesitas
- Si lo usas con REA: exactamente la 0.7.1. REA 6.7.0, la última publicada, fija esa versión y su suma en su código, y la versión en desarrollo de REA seguía igual el 22 de octubre de 2026. Como REA compara la suma del archivo, la 0.7.2 o la 0.8.0 no le sirven. Cómo indicárselo a REA (la variable
REA_JADX_MCP_JAR) está en nuestra guía de REA. - Si lo usas solo, con tu asistente: la 0.8.0, del 19 de octubre de 2026. Es la que instala también el plugin oficial para Claude Code.
Qué cambió después de la 0.7.1, según sus notas de versión:
- 0.7.2 (19 de octubre): buscar una clase o pedir su resumen ya no obliga a descompilar la app entera. Lo notamos: con la 0.7.1, la primera búsqueda en Binary Eye tardó 7,4 segundos; con la 0.8.0 fue casi instantánea (0,0 s). A cambio, el primer método que se lee tarda un poco más (1,9 s frente a 0,0 s), porque ahora se descompila cuando se pide.
- 0.8.0 (19 de octubre):
get_class_sourceacepta unoffsetpara leer por partes las clases muy grandes, una cola más justa para las descompilaciones lentas y más pruebas. Las notas anuncian como nueva la herramientaget_main_application_classes_names, pero en nuestras pruebas la 0.7.1 ya la tenía: las dos versiones ofrecen las mismas 26 herramientas.
Requisitos: Java 17 o posterior
Para ejecutar el -all.jar basta con Java 17 o posterior, y el JRE (el Java que solo ejecuta programas) es suficiente. Lo probamos con este:
java -versionopenjdk version "17.0.20.1" 2026-08-18 OpenJDK Runtime Environment Temurin-17.0.20.1+1 (build 17.0.20.1+1) OpenJDK 64-Bit Server VM Temurin-17.0.20.1+1 (build 17.0.20.1+1, mixed mode, sharing)
Con Java 11 no arranca, y el mensaje lo dice a su manera: la «versión 61» de los archivos de clase es Java 17.
con Java 11Error: LinkageError occurred while loading main class com.atxx.jhmcp.MainKt java.lang.UnsupportedClassVersionError: com/atxx/jhmcp/MainKt has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versions up to 55.0
Ojo con REA: ella sí necesita un JDK completo, no solo el JRE, porque compila un pequeño puente al arrancar. Eso es cosa de REA, no de jadx-headless-mcp.
Probarlo sin ningún asistente
Un servidor MCP no tiene ventana: espera mensajes JSON por su entrada estándar y responde por la salida. Para ver que funciona antes de conectarlo a nada, escribimos un cliente mínimo en Python que hace el saludo de MCP y pide la lista de herramientas. En nuestro caso, Java corría en un contenedor de Docker sin red. Este fue el intercambio, recortado (>>> es lo que enviamos y <<<, lo que respondió):
saludo y lista de herramientas, con la 0.7.1>>> {"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2026-07-28","capabilities":{},"clientInfo":{"name":"cliente-decodigo","version":"1.0"}}}
<<< {"id":1,"result":{"protocolVersion":"2025-11-25","capabilities":{"tools":{}},"serverInfo":{"name":"jadx-headless-mcp","version":"0.7.1"}},"jsonrpc":"2.0"}
>>> {"jsonrpc":"2.0","method":"notifications/initialized"}
>>> {"jsonrpc":"2.0","id":2,"method":"tools/list"}
<<< 26 herramientas: status, load_apk, unload_apk, get_app_info, get_android_manifest, get_main_activity_class, list_classes, get_main_application_classes_names, get_class_source, get_class_summary, get_smali_of_class, get_fields_of_class, get_inner_classes, resolve_class, get_methods_of_class, get_method_by_name, get_method_body, get_method_smali, search_method_by_name, search_classes_by_keyword, get_xrefs_to_class, get_xrefs_to_method, get_xrefs_to_field, get_strings, list_resource_files, get_resource_fileFíjate en la versión: le ofrecimos la más reciente del protocolo, la 2026-07-28, y respondió con la 2025-11-25, que es la que habla. La 2026-07-28 cambió la forma de empezar la conversación, y los clientes actuales saben adaptarse a servidores anteriores. Lo contamos en la guía de MCP.
El cliente de prueba completo, en Python
"""Cliente MCP mínimo por stdio para probar jadx-headless-mcp sin ningún cliente de IA.
El servidor (el .jar) corre en un contenedor desechable sin red; este programa solo le escribe y le lee líneas
JSON-RPC por la entrada y la salida estándar. Uso:
python3 -I cliente.py <imagen-java> <dir-del-jar> <nombre-del-jar> <dir-de-la-apk> <guion.json>
El guion es una lista de [método, parámetros] que se envían en orden tras el saludo.
"""
import json, subprocess, sys, time
imagen, dir_jar, jar, dir_apk, guion = sys.argv[1:6]
NOMBRE = f"jadx-mcp-prueba-{int(time.time())}"
cmd = ["docker", "run", "--rm", "-i", "--name", NOMBRE, "--network", "none", "-v", f"{dir_jar}:/opt/jadx:ro", "-v", f"{dir_apk}:/apks:ro",
imagen, "java", "-jar", f"/opt/jadx/{jar}"]
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, bufsize=1)
n = 0
def enviar(metodo, params=None, notificacion=False):
global n
m = {"jsonrpc": "2.0", "method": metodo}
if params is not None: m["params"] = params
if not notificacion:
n += 1; m["id"] = n
linea = json.dumps(m, ensure_ascii=False)
print(">>> " + linea)
p.stdin.write(linea + "\n"); p.stdin.flush()
if notificacion: return None
t0 = time.time()
while True:
r = p.stdout.readline()
if not r: print("!!! el servidor cerró la salida"); print(p.stderr.read()); sys.exit(1)
r = json.loads(r)
if r.get("id") == n:
print(f"<<< ({time.time() - t0:.1f} s) " + json.dumps(r, ensure_ascii=False))
return r
enviar("initialize", {"protocolVersion": sys.argv[6] if len(sys.argv) > 6 else "2025-06-18", "capabilities": {},
"clientInfo": {"name": "cliente-decodigo", "version": "1.0"}})
enviar("notifications/initialized", notificacion=True)
for metodo, params in json.load(open(guion)):
enviar(metodo, params)
p.stdin.close()
try:
p.wait(timeout=10)
except subprocess.TimeoutExpired: # el servidor no siempre sale al cerrar la entrada: se para el contenedor
subprocess.run(["docker", "kill", NOMBRE], capture_output=True)
p.wait(timeout=30)
print("--- fin")Analizar una app: un ejemplo con Binary Eye
Con el servidor en marcha, estas son cuatro llamadas reales sobre Binary Eye 1.75.5, un lector de códigos de barras libre de F-Droid. Es lo mismo que hará tu asistente cuando le pidas, por ejemplo, «averigua qué hace esta app con la cámara».
1. Abrir la app con load_apk (en el contenedor, la APK estaba en /apks):
load_apk {"path": "/apks/BinaryEye.apk"}{
"state": "LOADED",
"apk_path": "/apks/BinaryEye.apk",
"class_count": 2800,
"raw_class_count": 2800,
"resource_count": 930,
"load_duration_ms": 2354,
"decompile_timeout_ms": 90000,
"threads": 4,
"code_cache_size": 64,
"resources": "full"
}2. Ver qué es y qué permisos pide con get_app_info:
get_app_info, recortado{
"package": "de.markusfisch.android.binaryeye",
"version_name": "1.75.5",
"version_code": "180",
"min_sdk": "21",
"target_sdk": "37",
"permissions": [
"android.permission.ACCESS_FINE_LOCATION",
"android.permission.BLUETOOTH",
"android.permission.BLUETOOTH_ADMIN",
"android.permission.BLUETOOTH_CONNECT",
"android.permission.CAMERA",
"…"
]
}3. Buscar una clase con search_classes_by_keyword:
search_classes_by_keyword {"search_term": "CameraActivity"}{
"search_term": "CameraActivity",
"search_in": [
"class"
],
"offset": 0,
"count": 1,
"scanned": 2881,
"max_scan_reached": false,
"items": [
{
"fqn": "de.markusfisch.android.binaryeye.activity.CameraActivity",
"matched_in": [
"class"
]
}
]
}4. Leer un método con get_method_by_name:
get_method_by_name: CameraActivity.onCreate, recortado @Override // defpackage.b6, androidx.activity.a, defpackage.yo, android.app.Activity
public final void onCreate(Bundle bundle) throws IOException {
String type;
ParcelFileDescriptor parcelFileDescriptorOpenFileDescriptor;
super.onCreate(bundle);
int i = Build.VERSION.SDK_INT;
if (i >= 27) {
setShowWhenLocked(true);
} else {
getWindow().addFlags(524288);
}
setContentView(R.layout.activity_camera);
setTitle(R.string.scan_code);
mu.F(this);
…Los nombres raros, como mu.F o zf0.u0, no son un error: la app está ofuscada para ocupar menos, y el asistente tendrá que deducir qué hace cada pieza por el contexto. Para eso sirven las referencias cruzadas.
Registrarlo en Claude Code
Con el archivo en una carpeta fija, por ejemplo ~/herramientas/, basta una orden. La parte que va después de -- es el programa que Claude Code arrancará:
claude mcp add --transport stdio jadx-headless -s user -- java -jar ~/herramientas/jadx-headless-mcp-0.8.0-all.jar claude mcp list
-s userlo deja disponible en todos tus proyectos. Sin esa opción se queda solo en el proyecto actual (el ámbitolocal), y con-s projectse guarda en un.mcp.jsondel proyecto para compartirlo con tu equipo.- En Windows, pon la ruta completa:
claude mcp add --transport stdio jadx-headless -s user -- java -jar C:/herramientas/jadx-headless-mcp-0.8.0-all.jar. - Dentro de una sesión, la orden
/mcpmuestra si el servidor está conectado. Después basta con pedirle a Claude que abra una APK conload_apky le diga lo que quieres saber. - La alternativa sin rutas: el propio proyecto es un plugin de Claude Code. Con
/plugin marketplace add 1013503897/jadx-headless-mcpy/plugin install jadx-headless@jadx-headless-mcp, la primera vez descarga la 0.8.0, comprueba su suma y la guarda. Necesita Java 17 en elPATH.
Claude Desktop, Cursor y otros clientes
Casi todos los clientes MCP aceptan el mismo bloque JSON con mcpServers. Solo cambia el archivo donde va: claude_desktop_config.json en Claude Desktop, .cursor/mcp.json en Cursor o ~/.codeium/windsurf/mcp_config.json en Windsurf.
{
"mcpServers": {
"jadx-headless": {
"command": "java",
"args": ["-jar", "/ruta/completa/jadx-headless-mcp-0.8.0-all.jar"]
}
}
}Si siempre analizas la misma app, puedes añadir "--apk", "/ruta/a/la/app.apk" al final de args para que la abra al arrancar. VS Code con Copilot usa otro formato (servers en lugar de mcpServers); el README del proyecto lo explica.
Opciones que conviene conocer
Se añaden después del nombre del .jar, tanto en la orden de Claude Code como en args. Las más útiles, de --help:
--exclude-packages androidx,kotlin: descarta las bibliotecas comunes para que el asistente no se pierda entre miles de clases que no son de la app.--threads 2: menos procesos de descompilación, menos memoria. Por defecto usa como mucho 4.--resources lite: solo el manifiesto y los textos, para apps con muchos recursos.--decompile-timeout-ms 90000: el tiempo máximo para descompilar una clase (90 segundos por defecto), para que una clase muy ofuscada no bloquee todo.--transport http: lo sirve por HTTP para usarlo desde otro equipo. Por defecto solo escucha en el propio equipo (127.0.0.1, puerto 8080), y es mejor dejarlo así: según su README, ese modo no tiene autenticación, y quien llegue a él puede abrir cualquier APK de esa máquina. Para usarlo a distancia, mejor por un túnel SSH.
Errores típicos
NoClassDefFoundError: kotlin/…al arrancar: estás ejecutando el.jarsin dependencias que viene dentro del.zip. Usa el-all.jar.UnsupportedClassVersionError … class file version 61.0: tu Java es anterior a la 17. Comprueba la versión conjava -versione instala una más nueva.- REA dice que el archivo no es válido: o no es la 0.7.1, o la suma no coincide (una descarga cortada, o la página de GitHub guardada como si fuera el archivo). Vuelve a bajarlo con
curl -fLOy compara la suma. - El cliente dice que el servidor no responde: casi siempre es la ruta del
.jar, o quejavano está en elPATHdel programa (Claude Desktop, por ejemplo, no siempre ve el mismoPATHque tu terminal). Pon la ruta completa dejavaencommand. - Se queda sin memoria con apps grandes: con
java -jarno se aplican los límites de memoria del lanzador del.zip. Añade-Xmx4g(o lo que quieras) antes de-jary usa--exclude-packages.
Si lo que quieres es que un agente haga el análisis de principio a fin, con Ghidra para los programas nativos y este servidor para Android, mira la guía de REA. Y si te interesa cómo funciona por dentro la conexión entre un asistente y sus herramientas, la guía de MCP lo cuenta paso a paso.
Fuentes: el repositorio y las versiones de jadx-headless-mcp (README, LICENSE, notas de la 0.7.2 y de la 0.8.0); la versión que fija REA, en src/android/JadxRelease.ts; la sintaxis de claude mcp add y sus ámbitos, en la documentación de Claude Code. Las pruebas se hicieron el 22 de octubre de 2026 con jadx-headless-mcp 0.7.1 y 0.8.0, Java 17.0.20.1 (Temurin) en un contenedor sin red y Binary Eye 1.75.5 de F-Droid; el cliente de prueba solo envía y lee mensajes JSON-RPC.
