使用说明
Recaf MCP插件
使AI助手能够控制 Recaf 4.x 穿过 模型上下文协议(MCP) --反编译、搜索、分析、编辑字节码、编译Java、组装/反汇编JASM、差异类、补丁工作区、去混淆,以及直接从AI工作流导出Java字节码。
运作原理
该插件使用双进程架构将AI助手与Recaf强大的字节码分析引擎连接起来:
┌─────────────────┐ STDIO / JSON-RPC ┌─────────────────┐ HTTP :9847 ┌─────────────────┐
│ AI Assistant │ ◄──────────────────────► │ MCP Server │ ◄────────────────► │ Recaf Plugin │
│ (Claude Code, │ │ (Standalone JAR) │ │ (Bridge Server) │
│ Cursor, etc.) │ └─────────────────┘ └────────┬────────┘
└─────────────────┘ │
┌────────┴────────┐
│ Recaf 4.x │
│ (Analysis Engine)│
└─────────────────┘
- Recaf插件(网桥服务器) --在Recaf的进程中运行。通过CDI(Jakarta)注入Recaf服务,并将其作为HTTP端点公开在
localhost:9847. - MCP服务器 --AI客户端启动的独立胖JAR。通过STDIO JSON-RPC与AI通信,并通过HTTP将工具调用转发到网桥服务器。
这种分离是必要的,因为Recaf作为具有自己模块系统的JavaFX桌面应用程序运行,而MCP需要一个基于STDIO的进程,AI客户端可以生成和管理该进程。
可用的MCP工具(28)
工作空间管理
| 工具 | 说明 | 关键参数 |
|---|---|---|
open_jar |
打开JAR、APK或类文件进行分析 | path --绝对文件路径。退货 workspaceId. |
close_workspace |
关闭当前或特定工作区 | workspaceId (可选)--按ID关闭 |
switch_workspace |
切换到以前打开的工作区 | workspaceId --返回的ID open_jar |
list_workspaces |
列出所有已注册的工作区 | -- |
list_classes |
列出具有偏移/限制分页的类 | filter, offset, limit |
get_class_info |
获取类详细信息:字段、方法、接口 | className |
class_outline |
轻量级类结构(无代码,快速) | className |
read_file |
读取非类文件(例如MANIFEST.MF、configs) | 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 |
查看方法字节码指令(操作码、操作数、try-catch、局部变量) | 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 |
batch_rename |
在一个原子操作中批量重命名类/字段/方法 | mappings --数组 {type, oldName, newName, className?, descriptor?} |
edit_bytecode |
添加/删除/修改方法和字段 | className, operation,+操作特定参数 |
patch |
创建或应用工作区更改补丁 | action (创建/应用), patchJson |
出口
| 工具 | 说明 | 关键参数 |
|---|---|---|
export_mappings |
将重命名映射导出到文件 | format, outputPath |
export_jar |
将工作区导出为JAR文件 | outputPath |
export_source |
将反编译的源代码导出到目录 | outputDir, className (可选) |
反混淆
| 工具 | 说明 | 关键参数 |
|---|---|---|
eval_method |
在沙盒ClassLoader中执行静态方法(例如字符串解密) | className, methodName, methodDesc, arguments (可选), timeout (可选) |
simplify_method |
多通道字节码简化:常量折叠、死分支消除、goto链合并、NOP清理、不可达代码删除 | className, methodName, methodDesc, passes (可选) |
MCP资源
| URI | 描述 |
|---|---|
recaf://workspace |
当前工作区信息(JSON) |
recaf://classes |
当前工作区的完整类列表(JSON) |
先决条件
- JDK 22+ --Recaf 4.x要求。请确保
javaPATH指向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.3.0.jar |
Recaf插件(加载到Recaf内部,运行网桥服务器) |
build/mcp/recaf-mcp-server-1.3.0.jar |
MCP服务器(独立胖JAR,由AI客户端启动) |
设置和使用
步骤1:使用插件启动Recaf
选项A:直接从项目运行(建议用于开发)
./gradlew runRecaf
这将构建插件并启动自动加载的Recaf。
选项B:手动安装
复制 build/libs/recaf-mcp-plugin-1.3.0.jar 到Recaf的插件目录:
| 操作系统 | 插件目录 |
|---|---|
| macOS/Linux | ~/Recaf/plugins/ |
| 窗户 | %APPDATA%/Recaf/plugins/ |
然后正常启动Recaf。
验证: 在Recaf的日志记录面板中查找此内容:
========================================
Recaf MCP Plugin enabled
Bridge Server running on port 9847
========================================
步骤2:配置您的AI客户端
克劳德代码
添加 ~/.claude.json:
{
"mcpServers": {
"recaf": {
"command": "java",
"args": ["-jar", "/absolute/path/to/build/mcp/recaf-mcp-server-1.3.0.jar"]
}
}
}
然后重新启动Claude Code。这 recaf 工具将出现在您的工具列表中。
光标
添加到MCP配置(设置→ MCP):
{
"mcpServers": {
"recaf": {
"command": "java",
"args": ["-jar", "/absolute/path/to/build/mcp/recaf-mcp-server-1.3.0.jar"]
}
}
}
其他MCP兼容客户端
任何支持MCP协议的客户端都可以使用此插件。配置它以通过以下方式生成MCP服务器JAR java -jar 通过STDIO。
步骤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" — get an overview of the package structure
3. "Decompile com/a/b/c" — read the decompiled source
4. "Search for strings containing 'http'" — find network endpoints
5. "Get the call graph for com/a/b/c method d" — understand control flow
6. "Rename com/a/b/c to com/app/NetworkManager" — give it a meaningful name
7. "Export mappings as TinyV1 to ./mappings.tiny" — save your work
8. "Export the modified JAR to ./cleaned.jar" — save the result
多JAR比较
1. "Open /path/to/v1.jar" — opens first JAR, returns workspaceId
2. "Open /path/to/v2.jar" — opens second JAR, returns workspaceId
3. "List workspaces" — see both workspaces
4. "Switch to workspace v1-1" — switch to first JAR
5. "Decompile com/example/Main" — get v1 source
6. "Switch to workspace v2-2" — switch to second JAR
7. "Diff com/example/Main against the v1 source" — compare versions
字节码编辑
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" — get the Java source
3. (modify the source) → "Compile this Java source for com.app.Main" — compile & apply
4. "Decompile com/app/Main" — verify the changes took effect
5. "Disassemble com/app/Crypto" — get JASM assembly text
6. "Show me the bytecode for com/app/Crypto.encrypt" — inspect method instructions
7. "Create a patch" — save all modifications as JSON
8. "Export the modified JAR to /tmp/patched.jar"
消毒工作流程
1. "Open /path/to/obfuscated.jar"
2. "Decompile com/a/b/c" — find encrypted strings and decryption method signatures
3. "eval_method com/a/b/Decryptor decrypt (Ljava/lang/String;)Ljava/lang/String; with args [{type:'string', value:'encrypted_data'}]"
— call the decryption function directly, get plaintext result
4. "simplify_method com/a/b/c main (Ljava/lang/String;)V" — remove opaque predicates and dead branches
5. "Decompile com/a/b/c" — verify the simplified code is cleaner
6. "Batch rename the deobfuscated symbols"
7. "Export the cleaned JAR to /tmp/deobfuscated.jar"
项目结构
src/main/java/dev/recaf/mcp/
├── RecafMcpPlugin.java # Plugin entry point — CDI injection of 14 Recaf services
├── bridge/
│ ├── BridgeServer.java # HTTP server on :9847 — routes requests to handlers
│ ├── WorkspaceRegistry.java # Multi-workspace registry — ID → Workspace mapping
│ └── handlers/
│ ├── WorkspaceHandler.java # /workspace/* — open, close, switch, list, classes, info, outline, read-file, delete-class
│ ├── DecompileHandler.java # /decompile — decompile class to Java source
│ ├── SearchHandler.java # /search — string, class, method, field, declaration search
│ ├── AnalysisHandler.java # /analysis/* — call graph & inheritance hierarchy
│ ├── MappingHandler.java # /mapping/* — rename symbols & export mappings
│ ├── BytecodeHandler.java # /bytecode/* — edit/add/remove methods & fields, method bytecode instructions
│ ├── DiffHandler.java # /diff — compare two classes (unified diff)
│ ├── ExportHandler.java # /export/* — export JAR & decompiled source
│ ├── CompileHandler.java # /compile — compile Java source & apply to workspace
│ ├── AssemblerHandler.java # /disassemble, /assemble — JASM disassembly & assembly
│ └── PatchHandler.java # /patch — create & apply workspace patches
│ └── DeobfuscationHandler.java # /deobf/* — eval method (string decryption) & bytecode simplification
├── server/
│ ├── RecafMcpServer.java # MCP Server — STDIO JSON-RPC, 28 tools dispatch
│ └── BridgeClient.java # HTTP client — forwards MCP tool calls to Bridge Server
└── util/
├── JsonUtil.java # JSON response helpers
├── ErrorMapper.java # Structured error codes, messages & suggestions
└── DiffUtil.java # LCS-based unified diff algorithm
桥接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/batch-rename |
批量重命名: {"mappings": [{"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": "..."} |
POST /deobf/eval-method |
评估方法: {"className": "...", "methodName": "...", "methodDesc": "...", "arguments": [...], "timeout": 5000} |
POST /deobf/simplify-method |
简化方法: {"className": "...", "methodName": "...", "methodDesc": "...", "passes": 3} |
技术细节
| 项目 | 价值 |
|---|---|
| MCP协议版本 | 2024-11-05 |
| 大桥港口 | 9847 (硬编码) |
| MCP服务器依赖关系 | 仅限Gson(无MCP SDK——轻量级自定义JSON-RPC实现) |
| 解压缩超时 | 30秒 |
| 默认最大搜索结果 | 100 |
| 默认类列表限制 | 500(带偏移分页) |
| Java工具链 | JDK 22+ |
| 构建系统 | Gradle with Shadow插件用于胖JAR |
| MCP工具总数 | 28 |
故障排除
MCP服务器出现“连接被拒绝”错误
- 确保Recaf正在运行,并且网桥服务器在端口9847上处于活动状态。
- 检查Recaf的日志面板中的启动横幅。
MCP工具未出现在AI客户端中
- 验证路径
recaf-mcp-server-1.3.0.jar是正确和绝对的。 - 确保
java指向JDK 22+:运行java -version检查。 - 更新MCP配置后重新启动AI客户端。
反编译返回空或错误
- 确保工作区处于打开状态(使用
open_jar第一)。 - 检查类名格式:use
/分离器(例如。com/example/Main),不.分离器。
结构化错误响应
- 所有错误现在包括
code,message,以及suggestion领域。 - 常用代码:
NO_WORKSPACE,CLASS_NOT_FOUND,MEMBER_NOT_FOUND,INVALID_PARAMS,DECOMPILE_TIMEOUT,COMPILE_FAILED,ASSEMBLER_FAILED,PATCH_FAILED,EVAL_FAILED,EVAL_TIMEOUT,SIMPLIFY_FAILED.
构建失败
- 确保已安装JDK 22+。跑
./gradlew -q javaToolchains查看检测到的JDK。 - 如果使用非默认JDK,请配置 Gradle工具链.
更新日志
v1.3.0版本
- 字符串解密 —
eval_method在沙盒ClassLoader中执行静态方法,允许直接调用混淆器字符串解密函数来恢复明文 - 字节码简化 —
simplify_method执行多遍字节码转换:常量折叠、死分支消除、goto链组合、NOP清理和不可达代码删除 - 新错误代码 —
EVAL_FAILED,EVAL_TIMEOUT,SIMPLIFY_FAILED - 脱毒处理器 新
DeobfuscationHandler使用沙盒WorkspaceClassLoader(父级=用于隔离的PlatformClassLoader) - COMPUTE_FRAMES回退 --simplefy_method回退到
COMPUTE_MAXS如果COMPUTE_FRAMES处理格式错误的字节码失败 - 工具数量:26→ 28
v1.2.0版本
- 批量重命名 —
batch_rename在单个原子操作中应用多个类/字段/方法重命名,非常适合去模糊工作流 - Java编译 —
compile_java通过Recaf的JavacCompiler编译Java源代码,并将结果应用于工作区 - JASM组装/拆卸 —
disassemble_class和assemble_classJASM全班往返;method_disassemble用于单方法拆卸 - 方法字节码查看器 —
method_bytecode显示了通过ASM树API执行的详细字节码指令(操作码、操作数、try-catch块、本地变量) - 课程大纲 —
class_outline提供轻量级的类结构(字段、方法、访问标志),无需反编译代码 - 文件读取器 —
read_file从工作区读取非类文件(例如MANIFEST.MF、配置文件、资源) - 类删除 —
class_delete从工作区中删除类 - 补丁系统 —
patch该工具创建并应用工作区更改补丁(可序列化JSON格式) - 新错误代码 —
COMPILE_FAILED,COMPILER_UNAVAILABLE,PATCH_FAILED - 4次新的Recaf服务注射 --AssemblerPipelineManager、JavacCompiler、PatchProvider、PatchApplier
- 工具数量:16→ 26
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_ass_info、反编译类、搜索代码、get_call_graph、get_heritance、重命名符号、导出映射
许可证
麻省理工学院
