jadx-mcp

mcp
Guvenlik Denetimi
Uyari
Health Uyari
  • No license — Repository has no license file
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Low visibility — Only 8 GitHub stars
Code Uyari
  • Code scan incomplete — No supported source files were scanned during light audit
Permissions Gecti
  • Permissions — No dangerous permissions requested

Bu listing icin henuz AI raporu yok.

SUMMARY

MCP (Model Context Protocol) server as a jadx-gui plugin. Lets an AI client (Claude Code, Claude Desktop, or any MCP client) analyze the app currently loaded in jadx-gui.

README.md

jadx-mcp

MCP (Model Context Protocol) server as a jadx-gui plugin. Lets an AI client (Claude Code, Claude Desktop, or any MCP client) analyze the app currently loaded in jadx-gui: list/search classes, fetch decompiled Java or smali, per-method source, manifest components (main activity, application package), resources and strings.xml, cross-references (class/method/field level), and renames (class/method/field/package/variable) for deobfuscation loops.

Native implementation on the official MCP Java SDK - no Python shim, no external process. Server runs inside jadx-gui over streamable HTTP; host and port are configurable in the plugin's settings dialog (127.0.0.1:8090 by default).

Requirements

  • jadx-gui 1.5.6 (plugin API target).
  • jadx-gui running on Java 17+ (the MCP SDK and the plugin jar are Java 17 bytecode). The jadx-gui-x.y.z-with-jre-win bundle ships a recent JRE and works out of the box. If you launch jadx-gui.bat with a system JDK, check java -version first: on an older JVM jadx cannot load the plugin (UnsupportedClassVersionError in the jadx log).
  • To build: JDK 17+ and Gradle (or use the Gradle wrapper).

Launching the right JVM (Windows)

  • jadx-gui.exe (with-JRE bundle) uses its bundled JRE - always Java 17+, use this.
  • jadx-gui.bat uses the system JAVA_HOME. If yours is older than 17, point it at a recent JDK first:
$env:JAVA_HOME = "<custom_dir_location>"
jadx-gui.bat

The plugin is Java 17 bytecode by design: the official MCP Java SDK (2.x) is records-based and requires Java 17+, and mixing bytecode levels caused classloader issues in jadx's plugin loader. Keep jadx-gui on a JVM >= 17.

Build

Prerequisites: JDK 17+ (toolchain pinned to 21, any newer JDK works) and Gradle 9.x on the PATH. jadx-core and slf4j are compileOnly - no jadx install needed to build.

PowerShell:

cd jadx-mcp

# if your default JAVA_HOME is not a JDK 17+, point Gradle at one:
$env:JAVA_HOME = "<custom_dir_location>"

gradle jar      # fat jar -> build/libs/jadx-mcp-0.1.0.jar
gradle smoke    # headless e2e check: loads a real jar into jadx, starts the server on an
                # ephemeral port, runs raw JSON-RPC calls (initialize, tools/list for all
                # 27 tools, status, get_all_classes, get_class_source, get_method_by_name,
                # xrefs, renames, non-APK error paths) and stops it; prints "SMOKE OK"

What the jar contains:

  • Own classes (jadxmcp/*), compiled with --release 17.
  • MCP Java SDK 2.0.1 + Jackson 3 + Reactor + embedded Jetty 12 (ee11, servlet 6.1), unpacked into one fat jar (no shadow plugin; signatures and module-info.class stripped). Jetty instead of Tomcat because the jadx with-JRE bundle ships a stripped jlink runtime without java.management, which Tomcat requires.
  • META-INF/services/jadx.api.plugins.JadxPlugin — the ServiceLoader entry jadx picks up.
  • Transitive org.slf4j:slf4j-api is excluded so jadx's own slf4j binding wins.

Build layout:

src/main/java/jadxmcp/        JadxMcpPlugin (entry), McpServerManager (Jetty + MCP lifecycle),
                              JadxTools (all MCP tools), Settings (host+port persistence)
src/main/resources/META-INF/services/jadx.api.plugins.JadxPlugin
src/test/java/jadxmcp/        SmokeTest (run by gradle smoke)

Gradle details worth knowing if you touch the build:

  • gradle clean jar smoke for a from-scratch verify.
  • Toolchain comes from java.toolchain in build.gradle.kts — Gradle auto-downloads JDK 21 if JAVA_HOME doesn't provide it; setting JAVA_HOME just makes it instant.
  • To bump versions: val jadxVersion (plugin API target) and the mcp / jetty-ee11-servlet coordinates in build.gradle.kts. requiredJadxVersion in JadxMcpPlugin must match the jadx line you target.
  • gradle smokeLimited runs the same smoke test restricted to the jadx with-JRE module set (no java.management, no jdk.unsupported) — use it after any dependency change to make sure the server still loads in the stripped runtime.

Install

jadx plugins --install-jar jadx-mcp-0.1.0.jar

or copy the jar to ~/.jadx/plugins/ and restart jadx-gui. If an older version is installed, delete it first (same plugin id, duplicate jars in the plugins dir).

Use

  1. jadx-gui → open an APK/DEX/JAR.
  2. Menu Plugins → jadx-mcp: Settings... opens the single settings dialog:
    • Host (default 127.0.0.1) and Port (default 8090) — saved to ~/.jadx/jadx-mcp.properties on Start.
    • Start starts (or restarts with new host/port) the server; Stop stops it; the status line shows the running URL. No need to close the dialog: status updates live.
    • Warning: binding a non-loopback host (e.g. 0.0.0.0 or a LAN IP) exposes the server to the network — there is no authentication.
  3. Register with your MCP client (URL from the status line).

Claude Code (one-shot, no config editing):

claude mcp add --transport http jadx-mcp http://localhost:8090/mcp

With a non-default host/port, use the URL from the status dialog. Scope flag as needed: --scope project writes .mcp.json in the repo, default is user-local.

Claude Desktop - edit claude_desktop_config.json (Settings → Developer → Edit Config) and add under mcpServers:

{
  "mcpServers": {
    "jadx-mcp": {
      "type": "http",
      "url": "http://localhost:8090/mcp"
    }
  }
}

Restart Claude Desktop after editing. Both clients speak streamable HTTP, which is what the plugin serves.

  1. Stop with the Stop button in the same dialog (server also stops on jadx exit).

Smoke test (no client)

PowerShell:

$h = @{ Accept = "application/json, text/event-stream" }
$b = '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"smoke","version":"0"}}}'
$r = Invoke-WebRequest -Method Post http://localhost:8090/mcp -ContentType "application/json" -Headers $h -Body $b
$r.Headers["mcp-session-id"]   # session id -> server works

Tools

27 tools, all validated against a JSON schema by the SDK. Paginated tools take optional offset/limit (default 50, max 500).

Tool Notes
status app loaded, class/package/resource counts, manifest package
Classes
get_all_classes paginated, optional package prefix filter
search_classes class name contains, case-insensitive
get_class_source decompiled Java source (original or alias name)
get_smali_of_class DEX disassembly
search_classes_by_keyword full-text over decompiled code (class:line:source matches), paginated; expensive on large apps
fetch_current_class class the analyst is viewing in jadx-gui (node under caret), with source
Methods / fields
get_method_by_name single method source; signature fragment disambiguates overloads
search_method_by_name method name contains across all classes, paginated
get_methods_of_class methods with flags, signatures, return types
get_fields_of_class fields with flags and types
Manifest (APK)
get_android_manifest decoded AndroidManifest.xml
get_manifest_component one component type (activity, activity-alias, service, receiver, provider), optional name filter
get_main_activity_class MAIN/LAUNCHER activity, with source
get_main_application_classes_names class names in the manifest application package, paginated
get_main_application_classes_code their full sources, paginated (default 10 per page — token heavy)
Resources
get_strings decoded res/values/strings.xml
get_all_resource_file_names paginated, optional path filter
get_resource_file decoded content of one resource
Renames (mutate the jadx project)
rename_class short new name, GUI refresh included
rename_method signature fragment disambiguates overloads
rename_field
rename_package full new package name, cascades to all classes in it
rename_variable local var in a method; session-local (not persisted to saved jadx metadata)
Xrefs
xrefs_to_class all references to the class, paginated
xrefs_to_method references + override-related methods, paginated
xrefs_to_field methods accessing the field, paginated

Domain errors (class not found, no app loaded, binary resource, ambiguous overload) come back as isError tool results so the LLM can self-correct.

Security

  • Binds 127.0.0.1 by default; Origin/Host allowlist is built from the configured host.
  • Origin/Host header validation (http://localhost:* / localhost:*) to block DNS-rebinding and cross-origin requests from web pages.
  • No auth: keep it on localhost. Do not port-forward.

Known limits

  • No get_selected_text — the jadx plugin API (1.5.6 JadxGuiContext) exposes the node under the caret, not the raw text selection. fetch_current_class is the closest equivalent.
  • No debug_get_* tools (stack frames, threads, variables) — the plugin API has no debugger access. Use the jadx-gui debugger UI directly.
  • rename_variable is session-local: the new name shows in reloaded code but is not written to saved jadx metadata (.jadx files), unlike the class/method/field/package renames which go through the standard deobfuscation alias system.
  • Comments and headless (jadx-cli) operation are not implemented.

Yorumlar (0)

Sonuc bulunamadi