内容
# 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](https://java.sdk.modelcontextprotocol.io/latest/) - 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:
```powershell
$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:
```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`:
```json
{
"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.
4. Stop with the **Stop** button in the same dialog (server also stops on jadx exit).
### Smoke test (no client)
PowerShell:
```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.
连接信息
猜你喜欢
暂无推荐服务器