README
🚀 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 许可证。
Scan to join WeChat group