jadx-rpc

jadx-rpc

MCP server for analyzing Android APK, DEX, or JAR files via a headless jadx engine, enabling LLM agents to query decompiled code, symbols, call graphs, and more.

Category
访问服务器

README

jadx-rpc

A headless jadx engine for LLM agents. It answers structured questions about an APK, DEX or JAR over a plain command line, one JSON object per call.

$ jadx-rpc callers 'com.example.Payments.sign'
$ jadx-rpc members com.example.Payments
$ jadx-rpc class com.example.Payments --lines 40:120

Despite the name, there is no RPC in it. No daemon, no socket, no port, nothing running between calls. The name follows ghidra-rpc, which established <tool>-rpc as the headless component that lets an agent drive a decompiler. Ghidra needs a live process because its analysis exists only inside a JVM. jadx writes plain files, so this one does not, and a session is just a directory.

Why it exists

jadx has two shapes today and neither suits an autonomous agent. The GUI is built for a human reading code on a screen, and the plugins that expose it to a model need that GUI running. The command line tool is a batch decompiler with no memory between runs, so an agent that asks twenty questions pays the full parsing cost twenty times.

More to the point, jadx can already emit the two things that make Java analysis more than text search, and neither is usable as it stands: the symbol index arrives as a 35 MB single-line JSON file, and the call graph as a list of node and edge ids. No model can read either. Something has to query them. That is what this is.

If you only need to read and grep decompiled source, you do not need this at all. Run jadx -d out app.apk and use your normal tools. See docs/INTEGRATION.md for where that line falls.

How it works

The session is a directory:

~/.local/state/jadx-rpc/<hash>/
  session.json      what was opened and how
  mapping.json      every class, method and field, original and displayed names
  res/              decoded resources, including AndroidManifest.xml
  src/              decompiled Java, written by the optional full export
  callgraph.json    resolved call edges
  cache/            classes decompiled on demand
  renames.mapping   recorded renames in Enigma format

Nothing runs between commands. Two agents can query the same session at once because they are only reading files, and a session survives a reboot.

What it costs

Measured on a 12 MB APK containing 10761 classes, with jadx 1.5.6 on an eight core desktop. Your numbers will scale with the size of the application.

Command Time What it does
open 12 s indexes 19705 classes and 117352 methods, decodes every resource
classes, symbols, members 0.25 s reads the index
entrypoints, manifest, resources 0.25 s reads the decoded resources
class 5 s first time, then instant decompiles one class and caches it
export 175 s, 223 MB decompiles all 10761 classes, plus the call graph
search, strings, callers, callees seconds needs the export

The split is the point. Triage, symbol lookup and reading individual classes are all cheap, and the one expensive operation is opt in and runs in the background.

Install

jadx

jadx-rpc calls the jadx launcher, so install jadx first.

# any platform, from the release zip
curl -LO https://github.com/skylot/jadx/releases/download/v1.5.6/jadx-1.5.6.zip
mkdir -p /opt/jadx && unzip jadx-1.5.6.zip -d /opt/jadx
ln -s /opt/jadx/bin/jadx /opt/jadx/bin/jadx-gui ~/.local/bin/

# or from a package manager
brew install jadx                                  # macOS
sudo pacman -S jadx                                # Arch
flatpak install flathub com.github.skylot.jadx     # Flathub

jadx needs a 64 bit Java 11 or later. The zip ships both jadx and jadx-gui. jadx-rpc only uses jadx, the GUI is there when you want to look at the same target yourself.

jadx --version    # 1.5.1 or newer

If jadx is not on PATH, point JADX_BIN at the launcher.

Feature Minimum jadx
everything except the call graph 1.5.1
callers, callees 1.5.6

The version is detected at open and reported by status. On an older jadx, callers and callees fail naming the version they need and nothing else is affected.

jadx-rpc

uv tool install git+https://github.com/AsherDLL/jadx-rpc

# or
pipx install git+https://github.com/AsherDLL/jadx-rpc

# or with the MCP server included
uv tool install "jadx-rpc[mcp] @ git+https://github.com/AsherDLL/jadx-rpc"

Python 3.10 or later. The base install has no dependencies at all, everything it needs is in the standard library.

jadx-rpc list     # expect {"ok": true, "result": {"sessions": [], "count": 0}}

Output is indented by default. The examples below use --compact, which prints one line, because that is easier to read in a page and easier to pipe.

Use

$ jadx-rpc open app.apk --export
{"ok": true, "result": {"id": "1781c62d0f3b", "classes": 19705, "methods": 117352,
                        "elapsed_s": 12.6, "export": "running"}}

--export starts the full decompile in the background. You do not have to wait for it, the commands below work immediately.

$ jadx-rpc entrypoints
{"ok": true, "result": {"package": "org.fdroid.fdroid", "target_sdk": "30",
                        "components": [...], "exported_count": 10, ...}}

$ jadx-rpc symbols 'crypt|token|secret'
{"ok": true, "result": {"scope": "app", "app_package_prefix": "org.fdroid",
                        "matched": 0, "matched_all_scopes": 2030,
                        "hidden_by_scope": 2030, ...}}

That result is the reason scoping exists. All 2030 hits were in bundled libraries and none in the application's own code, so unscoped the honest answer "this app does not do that itself" is buried under 2030 that say otherwise. --scope all widens, and nothing is ever hidden without being counted.

$ jadx-rpc members org.fdroid.fdroid.FDroidApp
$ jadx-rpc class org.fdroid.fdroid.FDroidApp --lines 1:80

Once jadx-rpc status reports the export ready:

$ jadx-rpc search 'javax\.crypto' --context 2
$ jadx-rpc strings '^https://'
$ jadx-rpc callers 'org.fdroid.fdroid.FDroidApp.onCreate'

Renaming obfuscated symbols, recorded now and applied in one pass later:

$ jadx-rpc rename class com.a.b.c com.example.PaymentHandler
$ jadx-rpc rename method 'com.a.b.c.d(Ljava/lang/String;)V' verifySignature
$ jadx-rpc renames
$ jadx-rpc reload

AGENTS.md has the full command reference, the cost of each command and a triage order that works. It is written to be read by a model, so point your agent at it. docs/INTEGRATION.md is the engineer-facing version: what the engine requires, what it guarantees, and how to map it onto a tool table.

Wiring it to an LLM

Three ways into the same functions. Pick whichever fits your stack.

Shell agents

Claude Code, Codex, Cursor, pi and anything else that can run a command. There is nothing to configure, the tool prints JSON. Give the agent the reference:

Read AGENTS.md in jadx-rpc, then triage app.apk and report every exported
component that reaches a crypto call.

MCP

claude mcp add jadx-rpc -- jadx-rpc mcp

or in a client configuration file:

{
  "mcpServers": {
    "jadx-rpc": {
      "command": "jadx-rpc",
      "args": ["mcp"],
      "env": {"JADX_RPC_TARGET": "/abs/path/to/app.apk"}
    }
  }
}

Twenty tools, one per command. jadx-rpc mcp --list-tools prints them without starting a server, and works on the base install. Serving needs the extra, pip install "jadx-rpc[mcp]".

Python, for ADK, LangChain and friends

Every command is an importable function that returns a dict and raises JadxRpcError on failure, so a framework can register it directly with no subprocess and no MCP hop.

from google.adk.agents import LlmAgent
import jadx_rpc

jadx_rpc.open_target("/abs/path/to/app.apk", export=True)

agent = LlmAgent(
    name="apk_triage",
    model="gemini-2.0-flash",
    instruction=open("AGENTS.md").read(),
    tools=[
        jadx_rpc.entrypoints,
        jadx_rpc.classes,
        jadx_rpc.symbols,
        jadx_rpc.members,
        jadx_rpc.decompile_class,
        jadx_rpc.search,
        jadx_rpc.callers,
    ],
)

The docstrings and type hints are the tool schemas, so nothing needs describing twice.

Environment

Variable Effect
JADX_BIN path to the jadx launcher, when it is not on PATH
JADX_RPC_TARGET session every command acts on, a path or a session id
JADX_RPC_STATE_DIR where sessions live, for sandboxes and CI

With exactly one session open, JADX_RPC_TARGET is optional. With several open and none named, commands fail and list the candidates rather than guessing.

Limits worth knowing

  • open needs scratch space of roughly 25 times the input size, transiently. The index pass writes one JSON file per class beside the index it keeps, and jadx has no flag to suppress them. It refuses to start rather than fill the disk, and --index-tmp DIR points the scratch at a larger volume.
  • Scoping uses the manifest package cut to two segments, so com.acme.app scopes to com.acme and catches sibling packages the same vendor owns. An app that ships its own code under an unrelated top-level package will see it counted as library code; --scope all is the escape, and hidden_by_scope is the signal.
  • Field renames need a JVM descriptor, which the index does not carry. Build it from the declaration in the decompiled source. Class and method renames need nothing extra, members prints the exact string to pass back.
  • jadx fails to decompile a small fraction of classes in most real applications. That is jadx behaving normally and the rest of the output is unaffected.
  • Only local files are read. jadx-rpc does not fetch, upload or phone anywhere.

Development

git clone https://github.com/AsherDLL/jadx-rpc && cd jadx-rpc
uv venv && uv pip install -e . pytest
uv run pytest

The suite builds its own test jar with javac and runs real jadx against it, so it needs no network and no Android SDK. Tests skip cleanly when jadx or javac is missing.

License

GPL-3.0-or-later. See LICENSE.

jadx itself is a separate project under Apache-2.0. jadx-rpc runs it as an external program and does not include or link any of its code.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选