🚀 Recaf MCP 插件
该插件可让 AI 助手通过 模型上下文协议 (MCP) 控制 Recaf 4.x,实现反编译、搜索、分析、编辑字节码、编译 Java 代码、汇编/反汇编 JASM、比较类、修补工作区以及直接从 AI 工作流程中导出 Java 字节码等功能。
中文文档
🚀 快速开始
工作原理
该插件采用双进程架构,将 AI 助手与 Recaf 强大的字节码分析引擎连接起来:
┌─────────────────┐ STDIO / JSON-RPC ┌─────────────────┐ HTTP :9847 ┌─────────────────┐
│ AI 助手 │ ◄──────────────────────► │ MCP 服务器 │ ◄────────────────► │ Recaf 插件 │
│ (Claude Code, │ │ (独立 JAR) │ │ (桥接服务器) │
│ Cursor 等) │ └─────────────────┘ └────────┬────────┘
└─────────────────┘ │
┌────────┴────────┐
│ Recaf 4.x │
│ (分析引擎) │
└─────────────────┘
- Recaf 插件(桥接服务器):在 Recaf 进程内运行。通过 CDI (Jakarta) 注入 Recaf 服务,并将其作为 HTTP 端点暴露在
localhost:9847 上。
- MCP 服务器:由 AI 客户端启动的独立胖 JAR。通过 STDIO JSON-RPC 与 AI 通信,并通过 HTTP 将工具调用转发到桥接服务器。
这种分离是必要的,因为 Recaf 作为一个 JavaFX 桌面应用程序运行,有自己的模块系统,而 MCP 需要一个基于 STDIO 的进程,AI 客户端可以生成和管理该进程。
✨ 主要特性
可用的 MCP 工具(共 25 个)
工作区管理
| 工具 |
描述 |
关键参数 |
open_jar |
打开一个 JAR、APK 或类文件进行分析 |
path — 绝对文件路径。返回 workspaceId。 |
close_workspace |
关闭当前或指定的工作区 |
workspaceId(可选) — 按 ID 关闭 |
switch_workspace |
切换到之前打开的工作区 |
workspaceId — open_jar 返回的 ID |
list_workspaces |
列出所有已注册的工作区 |
— |
list_classes |
列出带有偏移量/限制分页的类 |
filter、offset、limit |
get_class_info |
获取类的详细信息:字段、方法、接口 |
className |
class_outline |
轻量级类结构(无代码,速度快) |
className |
read_file |
读取非类文件(例如 MANIFEST.MF、配置文件) |
path、maxChars |
class_delete |
从工作区中删除一个类 |
className |
分析
| 工具 |
描述 |
关键参数 |
decompile_class |
将类反编译为 Java 源代码 |
className |
search_code |
搜索字符串、引用或声明 |
query、type、maxResults |
get_call_graph |
获取方法调用图(调用者和被调用者) |
className、methodName、depth |
get_inheritance |
获取继承层次结构(父类/子类) |
className、direction |
diff_classes |
比较两个类或类与源代码 |
className1、className2 或 source |
method_bytecode |
查看方法字节码指令(操作码、操作数、异常处理、局部变量) |
className、methodName、methodDesc |
编译与汇编
| 工具 |
描述 |
关键参数 |
compile_java |
编译 Java 源代码并应用到工作区 |
className、source、targetVersion、debug |
disassemble_class |
将类反汇编为 JASM 文本 |
className、maxChars |
assemble_class |
汇编 JASM 源代码并应用到工作区 |
className、source |
method_disassemble |
将单个方法反汇编为 JASM 文本 |
className、methodName、methodDesc、maxChars |
修改
| 工具 |
描述 |
关键参数 |
rename_symbol |
重命名类/字段/方法(更新所有引用) |
type、oldName、newName、className |
edit_bytecode |
添加/删除/修改方法和字段 |
className、operation + 特定操作的参数 |
patch |
创建或应用工作区更改补丁 |
action(创建/应用)、patchJson |
导出
| 工具 |
描述 |
关键参数 |
export_mappings |
将重命名映射导出到文件 |
format、outputPath |
export_jar |
将工作区导出为 JAR 文件 |
outputPath |
export_source |
将反编译的源代码导出到目录 |
outputDir、className(可选) |
MCP 资源
| URI |
描述 |
recaf://workspace |
当前工作区信息(JSON 格式) |
recaf://classes |
当前工作区的完整类列表(JSON 格式) |
📦 安装指南
前提条件
- JDK 22+:Recaf 4.x 所需。确保 PATH 中的
java 指向 JDK 22 或更高版本。
- Recaf 4.x:此插件基于快照
d07958a5c7 构建。构建系统将自动下载它。
构建
git clone https://github.com/your-repo/recaf-mcp-plugin.git
cd recaf-mcp-plugin
./gradlew build
这将生成两个 JAR 文件:
| 文件 |
用途 |
build/libs/recaf-mcp-plugin-1.2.0.jar |
Recaf 插件(在 Recaf 内加载,运行桥接服务器) |
build/mcp/recaf-mcp-server-1.2.0.jar |
MCP 服务器(独立胖 JAR,由 AI 客户端启动) |
设置与使用
步骤 1:使用插件启动 Recaf
选项 A:直接从项目运行(推荐用于开发)
./gradlew runRecaf
这将构建插件并自动加载它来启动 Recaf。
选项 B:手动安装
将 build/libs/recaf-mcp-plugin-1.2.0.jar 复制到 Recaf 的插件目录:
| 操作系统 |
插件目录 |
| macOS / Linux |
~/Recaf/plugins/ |
| Windows |
%APPDATA%/Recaf/plugins/ |
然后正常启动 Recaf。
验证:在 Recaf 的日志面板中查找以下内容:
========================================
Recaf MCP 插件已启用
桥接服务器在端口 9847 上运行
========================================
步骤 2:配置你的 AI 客户端
Claude Code
在 ~/.claude.json 中添加以下内容:
{
"mcpServers": {
"recaf": {
"command": "java",
"args": ["-jar", "/absolute/path/to/build/mcp/recaf-mcp-server-1.2.0.jar"]
}
}
}
然后重启 Claude Code。recaf 工具将出现在你的工具列表中。
Cursor
在 MCP 配置(设置 → MCP)中添加以下内容:
{
"mcpServers": {
"recaf": {
"command": "java",
"args": ["-jar", "/absolute/path/to/build/mcp/recaf-mcp-server-1.2.0.jar"]
}
}
}
其他支持 MCP 协议的客户端
任何支持 MCP 协议的客户端都可以使用此插件。将其配置为通过 java -jar 在 STDIO 上生成 MCP 服务器 JAR。
步骤 3:开始使用
当 Recaf 和你的 AI 客户端都运行后,你可以自然地进行交互:
Open /path/to/target.jar and list all classes
Decompile the com/example/Main class
Search for all strings containing "password"
Show me the call graph for com/example/Main
Rename com/example/a to com/example/LoginManager
Compare com/example/A with com/example/B
Remove the method "unused" from com/example/Foo
Show me the bytecode instructions for com/example/Main.main
Disassemble com/example/Crypto into JASM
Compile this modified Java source back into the workspace
Read the META-INF/MANIFEST.MF file
Create a patch of all my changes
Export the modified JAR to /tmp/output.jar
💻 使用示例
逆向工程混淆的 JAR 文件
1. "Open /path/to/obfuscated.jar"
2. "List all classes" — 获取包结构概述
3. "Decompile com/a/b/c" — 阅读反编译的源代码
4. "Search for strings containing 'http'" — 查找网络端点
5. "Get the call graph for com/a/b/c method d" — 了解控制流
6. "Rename com/a/b/c to com/app/NetworkManager" — 给它一个有意义的名称
7. "Export mappings as TinyV1 to ./mappings.tiny" — 保存工作成果
8. "Export the modified JAR to ./cleaned.jar" — 保存结果
多 JAR 文件比较
1. "Open /path/to/v1.jar" — 打开第一个 JAR 文件,返回工作区 ID
2. "Open /path/to/v2.jar" — 打开第二个 JAR 文件,返回工作区 ID
3. "List workspaces" — 查看两个工作区
4. "Switch to workspace v1-1" — 切换到第一个 JAR 文件的工作区
5. "Decompile com/example/Main" — 获取 v1 版本的源代码
6. "Switch to workspace v2-2" — 切换到第二个 JAR 文件的工作区
7. "Diff com/example/Main against the v1 source" — 比较版本差异
字节码编辑
1. "Open /path/to/target.jar"
2. "Remove the method 'checkLicense' from com/app/Main"
3. "Add a public field 'debug' of type boolean to com/app/Config"
4. "Export the modified JAR to /tmp/patched.jar"
编译与汇编往返操作
1. "Open /path/to/target.jar"
2. "Decompile com/app/Main" — 获取 Java 源代码
3. (修改源代码)→ "Compile this Java source for com.app.Main" — 编译并应用更改
4. "Decompile com/app/Main" — 验证更改是否生效
5. "Disassemble com/app/Crypto" — 获取 JASM 汇编文本
6. "Show me the bytecode for com/app/Crypto.encrypt" — 检查方法指令
7. "Create a patch" — 以 JSON 格式保存所有修改
8. "Export the modified JAR to /tmp/patched.jar"
📚 详细文档
项目结构
src/main/java/dev/recaf/mcp/
├── RecafMcpPlugin.java # 插件入口点 — CDI 注入 14 个 Recaf 服务
├── bridge/
│ ├── BridgeServer.java # 端口 :9847 上的 HTTP 服务器 — 将请求路由到处理程序
│ ├── WorkspaceRegistry.java # 多工作区注册表 — ID → 工作区映射
│ └── handlers/
│ ├── WorkspaceHandler.java # /workspace/* — 打开、关闭、切换、列出、类、信息、大纲、读取文件、删除类
│ ├── DecompileHandler.java # /decompile — 将类反编译为 Java 源代码
│ ├── SearchHandler.java # /search — 字符串、类、方法、字段、声明搜索
│ ├── AnalysisHandler.java # /analysis/* — 调用图和继承层次结构
│ ├── MappingHandler.java # /mapping/* — 重命名符号和导出映射
│ ├── BytecodeHandler.java # /bytecode/* — 编辑/添加/删除方法和字段、方法字节码指令
│ ├── DiffHandler.java # /diff — 比较两个类(统一差异)
│ ├── ExportHandler.java # /export/* — 导出 JAR 和反编译的源代码
│ ├── CompileHandler.java # /compile — 编译 Java 源代码并应用到工作区
│ ├── AssemblerHandler.java # /disassemble, /assemble — JASM 反汇编和汇编
│ └── PatchHandler.java # /patch — 创建和应用工作区更改补丁
├── server/
│ ├── RecafMcpServer.java # MCP 服务器 — STDIO JSON-RPC,分发 25 个工具
│ └── BridgeClient.java # HTTP 客户端 — 将 MCP 工具调用转发到桥接服务器
└── util/
├── JsonUtil.java # JSON 响应助手
├── ErrorMapper.java # 结构化错误代码、消息和建议
└── DiffUtil.java # 基于 LCS 的统一差异算法
桥接 HTTP API 参考
所有端点都接受带有 JSON 主体的 POST 请求,并返回 JSON 响应。
| 端点 |
描述 |
GET /health |
健康检查 — 返回 {"status":"ok"} |
POST /workspace/open |
打开文件: {"path": "/path/to/file.jar"} → 返回 workspaceId |
POST /workspace/close |
关闭工作区: {"workspaceId": "optional"} |
GET /workspace/info |
获取工作区信息 |
POST /workspace/classes |
列出类: {"filter": "opt", "offset": 0, "limit": 500} |
POST /workspace/class-info |
类详细信息: {"className": "com/example/Main"} |
POST /workspace/switch |
切换工作区: {"workspaceId": "xxx"} |
GET /workspace/list-workspaces |
列出所有已注册的工作区 |
POST /decompile |
反编译: {"className": "com/example/Main"} |
POST /search |
搜索: {"query": "text", "type": "string", "maxResults": 100} |
POST /analysis/call-graph |
调用图: {"className": "...", "methodName": "...", "depth": 3} |
POST /analysis/inheritance |
继承: {"className": "...", "direction": "both"} |
POST /mapping/rename |
重命名: {"type": "class", "oldName": "...", "newName": "..."} |
POST /mapping/export |
导出映射: {"format": "TinyV1", "outputPath": "/path"} |
POST /bytecode/edit-method |
编辑方法: {"className": "...", "methodName": "...", "methodDesc": "...", "accessFlags": 1} |
POST /bytecode/edit-field |
编辑字段: {"className": "...", "fieldName": "...", "accessFlags": 2} |
POST /bytecode/remove-member |
删除成员: {"className": "...", "memberName": "...", "memberType": "method"} |
POST /bytecode/add-field |
添加字段: {"className": "...", "fieldName": "...", "descriptor": "I"} |
POST /bytecode/add-method |
添加方法: {"className": "...", "methodName": "...", "methodDesc": "()V"} |
POST /diff |
比较类: {"className1": "A", "className2": "B"} 或 {"className1": "A", "source": "..."} |
POST /export/jar |
导出 JAR: {"outputPath": "/path/to/output.jar"} |
POST /export/source |
导出源代码: {"outputDir": "/path/to/src", "className": "optional"} |
POST /workspace/outline |
类大纲: {"className": "com/example/Main"} — 轻量级结构,无代码 |
POST /workspace/read-file |
读取文件: {"path": "META-INF/MANIFEST.MF", "maxChars": 60000} |
POST /workspace/delete-class |
删除类: {"className": "com/example/Main"} |
POST /bytecode/instructions |
方法字节码: {"className": "...", "methodName": "...", "methodDesc": "..."} |
POST /compile |
编译 Java: {"className": "com.example.Main", "source": "...", "targetVersion": 17, "debug": true} |
POST /disassemble |
反汇编类: {"className": "com/example/Main", "maxChars": 120000} |
POST /disassemble/method |
反汇编方法: {"className": "...", "methodName": "...", "methodDesc": "...", "maxChars": 120000} |
POST /assemble |
汇编 JASM: {"className": "com/example/Main", "source": "..."} |
POST /patch |
打补丁: {"action": "create"} 或 {"action": "apply", "patchJson": "..."} |
🔧 技术细节
| 项目 |
值 |
| MCP 协议版本 |
2024-11-05 |
| 桥接端口 |
9847(硬编码) |
| MCP 服务器依赖项 |
仅 Gson(无 MCP SDK — 轻量级自定义 JSON-RPC 实现) |
| 反编译超时时间 |
30 秒 |
| 默认最大搜索结果数 |
100 |
| 默认类列表限制 |
500(带偏移量分页) |
| Java 工具链 |
JDK 22+ |
| 构建系统 |
带有 Shadow 插件的 Gradle,用于生成胖 JAR |
| 总 MCP 工具数 |
25 |
🛠️ 故障排除
"Connection refused" 错误
- 确保 Recaf 正在运行,并且桥接服务器在端口 9847 上处于活动状态。
- 检查 Recaf 的日志面板中的启动横幅。
MCP 工具未出现在 AI 客户端中
- 验证
recaf-mcp-server-1.2.0.jar 的路径是否正确且为绝对路径。
- 确保
java 指向 JDK 22+:运行 java -version 进行检查。
- 更新 MCP 配置后重启你的 AI 客户端。
反编译返回空或错误
- 确保已打开工作区(先使用
open_jar)。
- 检查类名格式:使用
/ 分隔符(例如 com/example/Main),而不是 . 分隔符。
结构化错误响应
- 所有错误现在都包含
code、message 和 suggestion 字段。
- 常见代码:
NO_WORKSPACE、CLASS_NOT_FOUND、MEMBER_NOT_FOUND、INVALID_PARAMS、DECOMPILE_TIMEOUT、COMPILE_FAILED、ASSEMBLER_FAILED、PATCH_FAILED。
构建失败
- 确保已安装 JDK 22+。运行
./gradlew -q javaToolchains 查看检测到的 JDK。
- 如果使用非默认 JDK,请配置 Gradle 工具链。
📝 更新日志
v1.2.0
- Java 编译:
compile_java 通过 Recaf 的 JavacCompiler 编译 Java 源代码,并将结果应用到工作区。
- JASM 汇编/反汇编:
disassemble_class 和 assemble_class 用于完整类的 JASM 往返操作;method_disassemble 用于单个方法的反汇编。
- 方法字节码查看器:
method_bytecode 通过 ASM 树 API 显示详细的字节码指令(操作码、操作数、异常处理块、局部变量)。
- 类大纲:
class_outline 提供轻量级类结构(字段、方法、访问标志),无需反编译代码。
- 文件读取器:
read_file 从工作区读取非类文件(例如 MANIFEST.MF、配置文件、资源)。
- 类删除:
class_delete 从工作区中删除一个类。
- 补丁系统:
patch 工具创建和应用工作区更改补丁(可序列化的 JSON 格式)。
- 新错误代码:
COMPILE_FAILED、COMPILER_UNAVAILABLE、PATCH_FAILED。
- 4 个新的 Recaf 服务注入:AssemblerPipelineManager、JavacCompiler、PatchProvider、PatchApplier。
- 工具数量:从 16 个增加到 25 个。
v1.1.0
- 多工作区支持:可以同时打开多个 JAR 文件,使用
switch_workspace 和 list_workspaces 在它们之间切换。
- 字节码编辑:
edit_bytecode 工具具有 5 个操作:edit_method、edit_field、remove_member、add_field、add_method(基于 ASM)。
- 类比较:
diff_classes 工具生成两个反编译类之间或类与提供的源代码之间的统一差异。
- 导出:
export_jar 将工作区(包含修改)导出为 JAR 文件;export_source 将反编译的源代码导出到目录。
- 分页:
list_classes 现在支持 offset/limit,并带有 totalMatched/hasMore 元数据。
- 结构化错误:所有错误返回
code、message 和 suggestion 字段(例如 NO_WORKSPACE、CLASS_NOT_FOUND)。
- 错误检测:MCP 服务器现在在错误响应中设置
isError: true,以便 AI 客户端更好地处理。
- 工具数量:从 10 个增加到 16 个。
v1.0.0
- 初始版本,包含 10 个 MCP 工具:open_jar、close_workspace、list_classes、get_class_info、decompile_class、search_code、get_call_graph、get_inheritance、rename_symbol、export_mappings。
📄 许可证
本项目采用 MIT 许可证。