Skip to main content
Glama
NitrogenT7

jadx-mcp-multisession

by NitrogenT7
README.md
# jadx-mcp-multisession

**JADX-MCP 改良版:多会话管理 + 插件版本兼容 + 错误降级**

基于 [zinja-coder/jadx-mcp-server](https://github.com/zinja-coder/jadx-mcp-server) v3.3.5(Apache-2.0)深度改良,让 AI(如 Kimi Code CLI)能像使用 IDA-MCP 一样**自主管理多个 jadx-gui 窗口**:无窗口时自动拉起、多窗口间切换、按需关闭,并对上游插件在 Windows 上的多个缺陷做了兼容与降级处理。

```
┌─────────────┐   MCP(stdio/http)   ┌───────────────────┐   HTTP    ┌──────────────┐
│ AI 客户端     │ ─────────────────► │ jadx-mcp-server    │ ────────► │ jadx-gui 实例 │
│ (Kimi Code)  │ ◄───────────────── │ (Python FastMCP)  │ ◄──────── │  (每窗口一个, │
└─────────────┘                     └───────────────────┘           │   独立端口)   │
        会话管理工具: jadx_open_session / jadx_list_sessions /        └──────────────┘
        jadx_switch_session / jadx_close_session / jadx_get_session_info
```

---

## ✨ 核心特性

| 特性 | 说明 |
|---|---|
| 🪟 **多会话管理** | AI 可自行启动 / 列出 / 切换 / 关闭 jadx-gui 窗口(对齐 IDA-MCP 模式) |
| 🚀 **自动拉起** | jadx-gui 未打开时,`jadx_open_session(apk)` 自动启动独立窗口并加载 APK |
| 🔌 **插件版本兼容** | 自动适配 jadx-ai-mcp 插件 3.3.x(legacy 参数名)/ 6.x(新参数名),并探测缺失端点 |
| 🛡️ **错误降级** | `get_main_activity_class` 对非标准 LAUNCHER 应用本地解析 Manifest 降级;`get_strings` 尽力降级并输出诊断 |
| 🔄 **向后兼容** | 不带 `--jadx-sessions-dir` 启动时行为与上游 v3.3.5 完全一致 |
| 🔍 **能力探测** | 会话启动后自动检测插件参数风格与端点覆盖,异常插件明确告警 |

## 📦 目录结构

```
jadx-mcp-multisession/
├── jadx_mcp_server.py              # MCP server 入口(29 个上游工具 + 5 个会话工具)
├── requirements.txt                # Python 依赖(fastmcp>=3.0.2, httpx, requests)
├── LICENSE                         # Apache-2.0(上游同款)
├── MULTI_SESSION.md                # 多会话改造细节与实测问题修复记录
├── AGENTS.md                       # 开发者/后续 AI 的项目文档(先读这个)
├── src/
│   ├── session_manager.py          # [新增] 会话注册表/端口分配/进程管理/能力探测
│   ├── session_tools.py            # [新增] 5 个 jadx_* MCP 工具的 async 包装
│   ├── PaginationUtils.py          # 分页框架(上游)
│   ├── banner.py                   # 启动横幅(上游)
│   └── server/
│       ├── config.py               # [改造] active 会话路由 + 参数风格自适应
│       └── tools/                  # class/search/resource/refactor/debug/xrefs 工具
├── session-prefs-factory/          # [新增] Java Preferences 文件化实现(多实例端口隔离)
│   ├── src/com/jadxmcp/session/FilePrefsFactory.java
│   └── build.sh                    # 构建脚本(需要 JDK,产出 lib/file-prefs-factory.jar)
├── lib/
│   └── file-prefs-factory.jar      # [新增] 构建产物(Preferences 文件化,端口隔离关键)
└── tests/                          # 集成测试脚本(HTTP stream 模式 + stdio 模式)
```

## 🚀 快速开始

### 前置依赖

| 组件 | 说明 |
|---|---|
| jadx-gui 1.5.3+ | 含 JRE 的发行包,目录含 `jre/` 与 `lib/jadx-gui-1.5.3-all.jar` |
| jadx-ai-mcp 插件 6.x | 放任意 `plugins/` 目录(自动探测),6.x 参数与端点最全 |
| Python 3.10+ & uv | server 运行环境 |
| JDK(可选) | 仅重新构建 `file-prefs-factory.jar` 时需要 |

### 1. 准备环境

```bash
# 构建 Preferences 文件化 jar(仓库已带构建产物,可跳过)
bash session-prefs-factory/build.sh
# 输出: <jadx根>/lib/file-prefs-factory.jar

# 安装 Python 依赖
uv sync   # 或 pip install -r requirements.txt
```

### 2. 配置 kimi-code(mcp.json)

```json
"jadx": {
  "command": "uv",
  "args": [
    "--directory", "D:\\jadx\\jadx-mcp-server",
    "run", "jadx_mcp_server.py",
    "--jadx-host", "127.0.0.1",
    "--jadx-port", "8650",
    "--jadx-sessions-dir", "D:\\jadx\\jadx-sessions"
  ],
  "startupTimeoutMs": 60000,
  "toolTimeoutMs": 180000
}
```

> `--jadx-sessions-dir` 是会话模式开关:**设置即启用多会话**,去掉即完全回到旧版单实例行为。
> `--jadx-home` 默认取 server 目录的父目录(即 jadx 根);`--jadx-plugin-jar` 可显式指定插件 jar。

### 3. 使用

```
AI: 打开这个 APK 分析一下            → jadx_open_session(apk_path)
AI: 现在分析另一个 APK               → jadx_open_session(另一个apk)   (新窗口)
AI: 切回刚才那个窗口                 → jadx_switch_session(session_id)
AI: 有哪些窗口开着?                  → jadx_list_sessions()
AI: 关掉 3 号窗口                     → jadx_close_session(session_id)
```

## 🔧 MCP 工具清单

### 会话管理(新增)

| 工具 | 参数 | 说明 |
|---|---|---|
| `jadx_open_session` | `apk_path: str`, `port: int=0` | 启动新会话并打开 APK;port=0 自动分配空闲端口(8650 起) |
| `jadx_list_sessions` | `include_external: bool=False` | 列出会话+存活状态;可探测手动打开的外部实例 |
| `jadx_switch_session` | `session_id: str` | 切换 active,所有分析工具随后作用于该窗口 |
| `jadx_close_session` | `session_id: str` | 关闭会话(taskkill),active 自动转移 |
| `jadx_get_session_info` | — | 查看当前 active 会话(含 APK/端口/PID/存活) |

### 分析工具(上游 29 个,路由自动跟随 active 会话)

类/方法:`get_class_source` `get_methods_of_class` `get_fields_of_class` `get_smali_of_class` `get_method_by_name` `get_main_activity_class` `get_all_classes` 等
搜索:`search_classes_by_keyword` `search_method_by_name`
资源:`get_android_manifest` `get_manifest_component` `get_strings` `get_resource_file` `get_all_resource_file_names`
引用:`get_xrefs_to_class` `get_xrefs_to_method` `get_xrefs_to_field`
重命名:`rename_class` `rename_method` `rename_field` `rename_package` `rename_variable`
调试:`debug_get_stack_frames` `debug_get_threads` `debug_get_variables`

## 🧪 测试

```bash
# 1. 启动 server(HTTP stream 模式,便于 curl/脚本测试)
uv run jadx_mcp_server.py --http --port 9000 --jadx-sessions-dir <会话目录>

# 2. 跑集成测试(需先有测试 APK;脚本内可改路径)
uv run python tests/test_multi_session.py <apk路径>     # 会话开/列/切/关
uv run python tests/test_feedback_fix.py                 # 参数/端点/降级全量验证
uv run python tests/test_stdio_client.py                 # stdio 模式冒烟(kimi-code 同款链路)
```

测试样本:`com.hihonor.id.apk`(荣耀账号 86MB/24k 类)、`com.heytap.speechassist.apk`(OPPO)

## ⚠️ 已知限制(上游插件缺陷)

| 限制 | 表现 | 对策 |
|---|---|---|
| Windows 上 `get_strings` 对字符串在 resources.arsc 内的 APK 不可用 | 插件按正斜杠精确匹配 arsc 资源名,Windows 实际为反斜杠 → 404 | server 尽力降级(分页遍历+读取+校验),失败返回诊断信息与替代方案(如 jadx CLI 反编译资源) |
| `get-resource-file` 对 arsc 内部资源存在截胡 bug | 遍历到 resources.arsc 时可能返回错误的第一个子文件 | server 侧 basename 校验拦截错误数据 |
| `get_xrefs_to_method` 等业务性 404/400 | "Method not found" / "Debugger not attached" | 属正常业务响应,非缺陷 |

## 📜 许可与致谢

- 上游 server 与插件均为 **Apache-2.0**,本项目继承该许可(保留 LICENSE 与上游版权声明)
- 上游作者:zinja-coder(https://github.com/zinja-coder/jadx-mcp-server)
- 改良内容:多会话管理、FilePrefsFactory 端口隔离、插件参数/端点兼容、main-activity 与 strings 降级、能力探测