内容
# recaf-mcp
[English](README.md) | [简体中文](README-ZH.md)
`recaf-mcp` 通过模型上下文协议(MCP)公开无头 Recaf 分析和补丁功能。Python 标准输入/输出桥接器管理隔离的 Recaf JVM;Java 插件执行实际分析。
```text
MCP 客户端 ── 标准输入/输出 ──> Python 桥接器 ── 身份验证的本地环回 HTTP ──> Recaf 工作进程
每个目标一个 JVM
```
桥接器使用您安装的 Recaf 通用 JAR 以无头模式运行。不需要 Recaf 源代码检查、修改后的 Recaf 构建或已发布的 Python 包。
## 功能
| 领域 | 功能 |
| --- | --- |
| 浏览 | 工作区摘要、类、存档文件、Android 清单/资源 |
| 反编译 | 将一个类或所有选定的类导出到 ZIP;CFR、Procyon、Vineflower 或另一个已安装的 Recaf 反编译器 |
| 搜索 | 字符串、JVM/DEX 指令、反编译源代码、成员声明/引用、调用图 |
| 重命名 | 类、方法和字段;导入/导出七种 Recaf 映射格式 |
| 修补 JVM | 编译替换 Java 源代码、运行安全的 Recaf 转换、编辑确切的方法指令 |
| 分析 APK/DEX | Android 类、解码的二进制 XML、DEX 字符串/指令/成员/调用、重建的单类 DEX |
| 自动化 | 编译和运行版本匹配的 Recaf Java 脚本进行自定义去混淆 |
| 管理会话 | 多个隔离的工作进程、保存/重新打开、空闲自动保存、取消、清理和恢复 |
所有 26 个工具都在打开目标之前进行广告,因此客户端不需要动态工具列表支持。下面显示完整的工具目录。
## 要求
- 用于检查的 Gradle 工具链和工作进程的 JDK 25。插件发出与 Java 22 兼容的字节码;`patch_class` 需要带有 `javac` 的 JDK,而不是 JRE。
- Recaf 4 通用可执行 JAR,捆绑了 Recaf 的运行时依赖项。
- Python 3.11 或更新版本。
- [`uv`](https://docs.astral.sh/uv/) 用于锁定桥接器环境。
## 安装
### 从发布版本安装(推荐)
不需要源代码检查或本地构建。从最新的 GitHub 发布版本中下载 [`recaf-mcp-plugin-1.0.0.jar`](https://github.com/Naptila/recaf-mcp/releases/download/v1.0.0/recaf-mcp-plugin-1.0.0.jar) 资产,并将其复制到 Recaf 的插件目录中:
| 平台 | Recaf 插件目录 |
| --- | --- |
| Linux | `~/.config/Recaf/plugins` |
| macOS | `~/Library/Application Support/Recaf/plugins` |
| Windows | `%APPDATA%\Recaf\plugins` |
直接从同一个发布版本中安装跨平台桥接器轮子:
```bash
uv tool install https://github.com/Naptila/recaf-mcp/releases/download/v1.0.0/recaf_mcp_bridge-1.0.0-py3-none-any.whl
```
这安装了 `recaf-mcp-bridge` 命令,而不将项目发布到 PyPI。
### 从源代码构建
要构建插件并从检出中安装桥接器:
```bash
cd /absolute/path/to/recaf-mcp/recaf-mcp-plugin
./gradlew clean build
mkdir -p ~/.config/Recaf/plugins
cp build/libs/recaf-mcp-plugin-1.0.0.jar ~/.config/Recaf/plugins/
cd ..
uv tool install ./recaf-mcp-bridge
```
安装任一方法后,请将 `RECAF_JAR` 设置为下载的通用可执行 JAR:
```text
RECAF_JAR=/absolute/path/to/recaf.jar
```
客户端中立的标准输入/输出命令是:
```bash
RECAF_JAR="$RECAF_JAR" recaf-mcp-bridge --stdio
```
标准输出仅为 MCP 协议数据。请通过 MCP 客户端而不是直接在交互式终端中运行命令;诊断信息会输出到标准错误。
## 客户端设置
| 客户端 | 设置 |
| --- | --- |
| Codex CLI | `codex mcp add recaf-mcp --env RECAF_JAR="$RECAF_JAR" -- recaf-mcp-bridge --stdio` |
| Claude Code | `claude mcp add --scope user recaf-mcp -e RECAF_JAR="$RECAF_JAR" -- recaf-mcp-bridge --stdio` |
| Antigravity / 其他 JSON 客户端 | 使用以下配置 |
```json
{
"mcpServers": {
"recaf-mcp": {
"command": "recaf-mcp-bridge",
"args": ["--stdio"],
"env": {
"RECAF_JAR": "/absolute/path/to/recaf.jar"
}
}
}
}
```
连接后,调用 `recaf_list`;空的 `sessions` 数组确认目录发现和标准输入/输出路由正常工作。允许 120 秒进行首次启动,340 秒进行正常长时间操作,或 1840 秒进行 `export_sources`。如果客户端找不到命令,请使用 `command -v recaf-mcp-bridge` 报告的绝对路径。
## 首次分析会话
| 步骤 | 调用 | 结果 |
| ---: | --- | --- |
| 1 | `recaf_list()` | 验证桥接器 |
| 2 | `recaf_open(input_path="/absolute/target.jar")` | 返回不透明的 `database` ID |
| 3 | `workspace_info(database=...)` | 总结加载的目标 |
| 4 | `list_classes(database=...)` 或另一个分析工具 | 开始分析 |
| 5 | `recaf_save(database=..., output_path=...)` | 写入修改后的 JAR |
| 6 | `recaf_close(database=..., save=false)` | 关闭而不保存 |
所有生命周期路径必须为绝对路径。将返回的 `database` 传递给每个工作进程工具。`recaf_close` 默认保存 JAR 更改;使用 `save=false` 放弃更改,并始终将其用于 APK 会话。
## 配置
MCP 客户端通常只需要 `RECAF_JAR`。桥接器在 Recaf 的标准插件目录中找到一个 `recaf-mcp-plugin*.jar`,然后将其复制到每个工作进程的私有目录中,以便其他已安装的插件和正常的 Recaf 配置永远不会被加载。在正常的 Recaf GUI 启动过程中,没有 MCP 令牌存在,因此已安装的插件保持休眠状态。
| 变量 | 默认值 | 目的 |
| --- | --- | --- |
| `RECAF_JAR` | 必需 | Recaf 通用可执行 JAR 的绝对路径 |
| `RECAF_PLUGIN_JAR` | 自动发现 | 可选的精确插件 JAR 重写 |
| `RECAF_PLUGIN_DIR` | Recaf 的标准目录 | 可选的插件发现目录 |
| `RECAF_JAVA_COMMAND` | `java` | 用于工作进程的 JDK 可执行文件 |
| `RECAF_MAX_SESSIONS` | `2` | 并发待处理/就绪工作进程上限,1-32 |
| `RECAF_WORKER_MAX_HEAP_MB` | `1024` | 每个工作进程的最大堆,至少 128 MiB |
| `RECAF_IDLE_TTL_SEC` | `600` | 默认自动保存/关闭空闲时间;`0` 禁用它 |
| `RECAF_RESPONSE_PROFILE` | `compact` | `compact` 避免重复的 JSON 文本;`legacy` 恢复它 |
| `RECAF_LAUNCH_TIMEOUT_SEC` | `60` | 工作进程启动准备就绪的截止时间 |
| `RECAF_SESSION_ROOT` | 系统临时目录 | 所有者专属的实时会话目录 |
| `RECAF_RECOVERY_DIR` | XDG 状态 | 所有者专属的故障关闭恢复注册表 |
每个工作进程都会生成 Bearer 令牌和本地环回端口。不要将令牌放入客户端配置或命令参数中。
默认的 `compact` 响应配置文件仅更改标准文本视图;类型化的 `structuredContent`、工具行为、结果字段、分页和错误语义保持不变。当 MCP 客户端仅向模型公开文本内容时,请使用 `legacy`。
## 工具
生命周期工具不需要 `database`。所有其他工具都使用 `recaf_open` 返回的 ID。
### 会话
| 工具 | 目的 | 关键行为 |
| --- | --- | --- |
| `recaf_open` | 打开 JAR 或 APK | 绝对输入路径;返回 `database` |
| `recaf_list` | 列出打开的会话 | 安全的安装烟雾测试 |
| `set_idle_ttl` | 更改空闲超时 | `0` 禁用空闲自动保存/关闭 |
| `recaf_save` | 导出修改后的 JAR | 原子输出;APK/DEX 保存不受支持 |
| `recaf_close` | 关闭会话 | 默认保存 JAR;使用 `save=false` 放弃 |
### 浏览和反编译
| 工具 | 目的 | 关键选项/输出 |
| --- | --- | --- |
| `workspace_info` | 总结目标 | JVM、Android/DEX 和文件计数 |
| `list_classes` | 列出类 | `scope`、`dex_name`、`filter`、分页 |
| `list_files` | 列出非类存档条目 | 清单、资源、配置、原生库 |
| `read_file` | 读取存档条目 | 文本、解码的 Android XML 或原始 Base64 |
| `decompile_class` | 反编译一个类 | 运行时 `decompiler`、JVM/Android 范围、分页源 |
| `export_sources` | 将选定的类导出到 ZIP | `scope`、`filter`、`regex`、`decompiler`、`overwrite` |
| `get_class_bytecode` | 读取类字节码 | 原始 JVM classfile 或重建的单类 DEX |
### 搜索和导航
| 工具 | 目的 | 最佳用途 |
| --- | --- | --- |
| `search_strings` | 搜索常量和 DEX 字符串 | 字面或部分正则表达式 |
| `search_instructions` | 搜索 JVM/DEX 指令 | 快速的整个存档搜索;无需反编译 |
| `search_code` | 搜索反编译的源代码 | 使用 `filter` 缩小范围;显式选择超过 200 个类 |
| `search_members` | 查找字段/方法声明和引用 | 所有者/名称/描述符、类型、结果类型 |
| `call_graph` | 查找调用者和被调用者 | 方向、深度、JVM/Android 范围 |
### 重命名和修补
| 工具 | 目的 | 关键行为 |
| --- | --- | --- |
| `rename_symbol` | 重命名类、方法或字段 | 描述符感知;JVM 或内存中的 Android |
| `apply_mappings` | 导入映射 | Enigma、Jadx、Proguard、Simple、SRG、Tiny v1/v2 |
| `export_mappings` | 导出累积的映射 | 分页的 UTF-8 文本,带有计数和 SHA-256 |
| `transform_workspace` | 运行审查的 Recaf 转换 | 仅限 JVM;支持 `dry_run` |
| `patch_class` | 编译替换 Java 源代码 | 仅限 JVM;默认保留 classfile 目标 |
| `get_method_assembly` | 读取确切的方法指令 | 可编辑的 JVM Jasm;只读 Android DEX 文本 |
| `patch_instructions` | 组装修改后的 JVM 方法 | 完整的程序集和之前的 SHA-256;支持 `dry_run` |
### 自定义 Recaf 脚本
| 工具 | 目的 | 关键行为 |
| --- | --- | --- |
| `get_recaf_script_help` | 获取版本匹配的示例 | 工作区、ASM、服务、去混淆 |
| `run_recaf_script` | 编译或运行 Recaf Java 代码 | 默认仅编译;执行需要显式确认 |
### 常见行为
| 主题 | 行为 |
| --- | --- |
| 匹配 | 默认情况下,搜索文本是区分大小写的子字符串;`regex=true` 启用部分 Java 正则表达式 |
| 范围 | `jvm` 是默认范围;Android 感知工具接受 `android`,扫描/导出工具也接受 `all` |
| 分页 | 类/文件列表默认为 20;搜索/图表默认为 10;大型文本/字节内容为 32 Ki 单位 |
| 反编译器 | `tools/list` 发布已安装的名称和默认值;测试的 Recaf JAR 暴露 CFR、Fallback、Procyon 和 Vineflower |
| 条件读取 | 五个大型读取工具接受 `if_sha256`;仅在保留先前的完整主体时使用它 |
| 丢失上下文 | 如果模型不再具有该主体,请省略 `if_sha256` 并重试以检索它 |
| 响应 | `compact` 返回一个结构化结果;`legacy` 还会将完整结果镜像到文本中 |
条件读取工具是 `read_file`、`decompile_class`、`export_mappings`、`get_class_bytecode` 和 `get_method_assembly`。匹配的哈希值返回 `unchanged=true` 而不包含主体。服务器无法检测到调用者的缓存主体是否被 LLM 上下文压缩丢弃。
### JVM 和 Android 支持
| 操作 | JAR/JVM | APK/DEX |
| --- | :---: | :---: |
| 浏览、搜索、调用图 | 是 | 是 |
| 反编译类/导出源代码 ZIP | 是 | 是,通过 Android 到 JVM 转换 |
| 读取字节码 | 原始 classfile | 重建的单类 DEX |
| 重命名/应用映射 | 永久保存后 JAR | 仅内存会话 |
| 修补源代码或指令 | 是 | 否 |
| 转换工作区 | 是 | 否 |
| 保存/重建存档 | 是 | 否 |
### 重要边界
| 主题 | 规则 |
| --- | --- |
| JAR 变更 | 保留在内存中,直到 `recaf_save` 或保存 `recaf_close` |
| APK 会话 | 仅限分析和内存映射;使用 `save=false` 关闭 |
| `read_file` | 仅读取打开的存档中的确切条目,绝不会读取任意主机路径 |
| `export_sources` | 需要绝对输出路径并以原子方式安装验证的 ZIP |
| Recaf 脚本 | 具有完全的工作进程文件系统/网络/进程访问权限,不具备事务性 |
| 大型源代码搜索 | 优先使用 `search_instructions`;`search_code` 需要缩小范围或 `allow_large_scan=true`(超过 200 个类) |
有关确切的模式、限制和恢复行为,请参阅 [桥接器 README](recaf-mcp-bridge/README.md)。有关插件打包和工作进程协议详细信息,请参阅 [插件 README](recaf-mcp-plugin/README.md)。
## 测试
```bash
cd /absolute/path/to/recaf-mcp/recaf-mcp-plugin
./gradlew clean build
cd /absolute/path/to/recaf-mcp/recaf-mcp-bridge
uv sync --frozen
uv run pytest -q
```
可选的真实测试套件还会启动已安装的 Recaf 工作进程,并测试打开、分析、突变、分页检索、保存、重新打开、取消清理、空闲关闭、信号清理和身份验证恢复。
## 故障排除
- **客户端报告 MCP 启动失败:** 确认 `recaf-mcp-bridge` 在客户端的 `PATH` 上,确认 `RECAF_JAR` 指向更大的通用可执行 JAR,确认只安装了一个 MCP 插件,并允许本地环回套接字。
- **初始工具发现超时:** 首次目录请求启动了一个短暂的模式工作进程。将客户端启动超时提高到 120 秒。
- **MCP 客户端中的大量源代码导出超时:** 工作进程允许最多 1800 秒,因此将客户端的工具超时设置为至少 1840 秒,或缩小 `filter`/`scope`。取消或失败的导出永远不会安装部分目标 ZIP。
- **`patch_class` 报告没有编译器:** 将 `RECAF_JAVA_COMMAND` 指向 JDK,而不是 JRE。
- **`patch_class` 拒绝旧 classfile:** 默认的 `preserve` 策略绝不会在不改变运行时兼容性的情况下静默更改。仅当将发出 classfile 提升到当前 javac 最小值是可以接受时,请使用 `target_version_policy="minimum_supported"` 重试, 结果报告两个版本和是否发生升级。
- **意外的 Recaf 插件/配置:** 绝不针对用户的正常 Recaf 数据目录启动。桥接器始终创建一个私有目录;使用桥接器而不是手动启动工作进程进行正常操作。
- **协议解析错误:** 确保客户端不将桥接器的标准错误输出合并到标准输出。
## 许可证
该项目根据 [MIT 许可证](LICENSE) 授权。