Recaf MCP插件
](<>)    
运作原理
该插件使用双进程架构将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工具(25)
工作空间管理
| 工具 | 说明 | 关键参数 |
|---|---|---|
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 |
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要求。请确保
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.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/ |
| 窗户 | %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.2.0.jar"]
}
}
}然后重新启动Claude Code。这 recaf 工具将出现在您的工具列表中。
光标
添加到MCP配置(设置→ MCP):
{
"mcpServers": {
"recaf": {
"command": "java",
"args": ["-jar", "/absolute/path/to/build/mcp/recaf-mcp-server-1.2.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"项目结构
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
├── server/
│ ├── RecafMcpServer.java # MCP Server — STDIO JSON-RPC, 25 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/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+ |
| 构建系统 | Gradle with Shadow插件用于胖JAR |
| MCP工具总数 | 25 |
故障排除
MCP服务器出现“连接被拒绝”错误
- 确保Recaf正在运行,并且网桥服务器在端口9847上处于活动状态。
- 检查Recaf的日志面板中的启动横幅。
MCP工具未出现在AI客户端中
- 验证路径
recaf-mcp-server-1.2.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.
构建失败
- 确保已安装JDK 22+。跑
./gradlew -q javaToolchains查看检测到的JDK。 - 如果使用非默认JDK,请配置 Gradle工具链.
更新日志
v1.2.0版本
- 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→ 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_ass_info、反编译类、搜索代码、get_call_graph、get_heritance、重命名符号、导出映射
许可证
麻省理工学院
