Use MCP to control Recaf4.0 to achieve methods like decompile/rename
Overview
Enable AI assistants to control Recaf 4.x through the Model Context Protocol (MCP) — decompile, search, analyze, edit bytecode, compile Java, assemble/disassemble JASM, diff classes, patch workspaces, deobfuscate, and export Java bytecode directly from your AI workflow. The plugin uses a dual-process architecture to bridge AI assistants with Recaf's powerful bytecode analysis engine: - — Runs inside Recaf's process. Injects Recaf services via CDI (Jakarta) and exposes them as HTTP endpoints on localhost:9847. - — A standalone fat JAR launched by the AI client. Communicates with the AI via STDIO JSON-RPC and forwards tool calls to the Bridge Server over HTTP. This separation is necessary because Recaf runs as a JavaFX desktop application with its own module system, while MCP requires a STDIO-based process that the AI client can spawn and manage. - — Required by Recaf 4.x. Make sure java on your PATH points to JDK 22 or higher. - — This plugin is built against snapshot d07958a5c7.
README
Recaf MCP Plugin
Enable AI assistants to control Recaf 4.x through the Model Context Protocol (MCP) — decompile, search, analyze, edit bytecode, compile Java, assemble/disassemble JASM, diff classes, patch workspaces, deobfuscate, and export Java bytecode directly from your AI workflow.
How It Works
The plugin uses a dual-process architecture to bridge AI assistants with Recaf’s powerful bytecode analysis engine:
┌─────────────────┐ 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 Plugin (Bridge Server) — Runs inside Recaf’s process. Injects Recaf services via CDI (Jakarta) and exposes them as HTTP endpoints on
localhost:9847. - MCP Server — A standalone fat JAR launched by the AI client. Communicates with the AI via STDIO JSON-RPC and forwards tool calls to the Bridge Server over HTTP.
This separation is necessary because Recaf runs as a JavaFX desktop application with its own module system, while MCP requires a STDIO-based process that the AI client can spawn and manage.
Available MCP Tools (28)
Workspace Management
| Tool | Description | Key Parameters |
|---|---|---|
open_jar |
Open a JAR, APK, or class file for analysis | path — absolute file path. Returns workspaceId. |
close_workspace |
Close the current or a specific workspace | workspaceId (optional) — close by ID |
switch_workspace |
Switch to a previously opened workspace | workspaceId — ID returned by open_jar |
list_workspaces |
List all registered workspaces | — |
list_classes |
List classes with offset/limit pagination | filter, offset, limit |
get_class_info |
Get class details: fields, methods, interfaces | className |
class_outline |
Lightweight class structure (no code, fast) | className |
read_file |
Read a non-class file (e.g. MANIFEST.MF, configs) | path, maxChars |
class_delete |
Delete a class from the workspace | className |
Analysis
| Tool | Description | Key Parameters |
|---|---|---|
decompile_class |
Decompile a class to Java source code | className |
search_code |
Search strings, references, or declarations | query, type, maxResults |
get_call_graph |
Get method call graph (callers and callees) | className, methodName, depth |
get_inheritance |
Get inheritance hierarchy (parents/children) | className, direction |
diff_classes |
Compare two classes or class vs. source code | className1, className2 or source |
method_bytecode |
View method bytecode instructions (opcodes, operands, try-catch, locals) | className, methodName, methodDesc |
Compilation & Assembly
| Tool | Description | Key Parameters |
|---|---|---|
compile_java |
Compile Java source and apply to workspace | className, source, targetVersion, debug |
disassemble_class |
Disassemble a class into JASM text | className, maxChars |
assemble_class |
Assemble JASM source and apply to workspace | className, source |
method_disassemble |
Disassemble a single method into JASM text | className, methodName, methodDesc, maxChars |
Modification
| Tool | Description | Key Parameters |
|---|---|---|
rename_symbol |
Rename class/field/method (updates all refs) | type, oldName, newName, className |
batch_rename |
Batch rename classes/fields/methods in one atomic operation | mappings — array of {type, oldName, newName, className?, descriptor?} |
edit_bytecode |
Add/remove/modify methods and fields | className, operation, + operation-specific params |
patch |
Create or apply workspace change patches | action (create/apply), patchJson |
Export
| Tool | Description | Key Parameters |
|---|---|---|
export_mappings |
Export rename mappings to a file | format, outputPath |
export_jar |
Export workspace as a JAR file | outputPath |
export_source |
Export decompiled source to a directory | outputDir, className (optional) |
Deobfuscation
| Tool | Description | Key Parameters |
|---|---|---|
eval_method |
Execute a static method in a sandboxed ClassLoader (e.g. string decryption) | className, methodName, methodDesc, arguments (optional), timeout (optional) |
simplify_method |
Multi-pass bytecode simplification: constant folding, dead branch elimination, goto chain combining, NOP cleanup, unreachable code removal | className, methodName, methodDesc, passes (optional) |
MCP Resources
| URI | Description |
|---|---|
recaf://workspace |
Current workspace information (JSON) |
recaf://classes |
Full class list of the current workspace (JSON) |
Prerequisites
- JDK 22+ — Required by Recaf 4.x. Make sure
javaon your PATH points to JDK 22 or higher. - Recaf 4.x — This plugin is built against snapshot
d07958a5c7. The build system will download it automatically.
Build
git clone https://github.com/your-repo/recaf-mcp-plugin.git
cd recaf-mcp-plugin
./gradlew build
This produces two JARs:
| File | Purpose |
|---|---|
build/libs/recaf-mcp-plugin-1.3.0.jar |
Recaf plugin (loads inside Recaf, runs the Bridge Server) |
build/mcp/recaf-mcp-server-1.3.0.jar |
MCP Server (standalone fat JAR, launched by AI client) |
Setup & Usage
Step 1: Start Recaf with the Plugin
Option A: Run directly from the project (recommended for development)
./gradlew runRecaf
This builds the plugin and launches Recaf with it auto-loaded.
Option B: Manual installation
Copy build/libs/recaf-mcp-plugin-1.3.0.jar to Recaf’s plugin directory:
| OS | Plugin Directory |
|---|---|
| macOS / Linux | ~/Recaf/plugins/ |
| Windows | %APPDATA%/Recaf/plugins/ |
Then start Recaf normally.
Verify: Look for this in Recaf’s Logging panel:
========================================
Recaf MCP Plugin enabled
Bridge Server running on port 9847
========================================
Step 2: Configure Your AI Client
Claude Code
Add to ~/.claude.json:
{
"mcpServers": {
"recaf": {
"command": "java",
"args": ["-jar", "/absolute/path/to/build/mcp/recaf-mcp-server-1.3.0.jar"]
}
}
}
Then restart Claude Code. The recaf tools will appear in your tool list.
Cursor
Add to your MCP configuration (Settings → MCP):
{
"mcpServers": {
"recaf": {
"command": "java",
"args": ["-jar", "/absolute/path/to/build/mcp/recaf-mcp-server-1.3.0.jar"]
}
}
}
Other MCP-Compatible Clients
Any client that supports the MCP protocol can use this plugin. Configure it to spawn the MCP Server JAR via java -jar over STDIO.
Step 3: Start Using
Once both Recaf and your AI client are running, you can interact naturally:
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
Example Workflows
Reverse Engineering an Obfuscated 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
Multi-JAR Comparison
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
Bytecode Editing
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"
Compile & Assemble Round-Trip
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"
Deobfuscation Workflow
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"
Project Structure
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
Bridge HTTP API Reference
All endpoints accept POST with JSON body and return JSON responses.
| Endpoint | Description |
|---|---|
GET /health |
Health check — returns {"status":"ok"} |
POST /workspace/open |
Open a file: {"path": "/path/to/file.jar"} → returns workspaceId |
POST /workspace/close |
Close workspace: {"workspaceId": "optional"} |
GET /workspace/info |
Get workspace info |
POST /workspace/classes |
List classes: {"filter": "opt", "offset": 0, "limit": 500} |
POST /workspace/class-info |
Class details: {"className": "com/example/Main"} |
POST /workspace/switch |
Switch workspace: {"workspaceId": "xxx"} |
GET /workspace/list-workspaces |
List all registered workspaces |
POST /decompile |
Decompile: {"className": "com/example/Main"} |
POST /search |
Search: {"query": "text", "type": "string", "maxResults": 100} |
POST /analysis/call-graph |
Call graph: {"className": "...", "methodName": "...", "depth": 3} |
POST /analysis/inheritance |
Inheritance: {"className": "...", "direction": "both"} |
POST /mapping/rename |
Rename: {"type": "class", "oldName": "...", "newName": "..."} |
POST /mapping/batch-rename |
Batch rename: {"mappings": [{"type": "class", "oldName": "...", "newName": "..."}, ...]} |
POST /mapping/export |
Export mappings: {"format": "TinyV1", "outputPath": "/path"} |
POST /bytecode/edit-method |
Edit method: {"className": "...", "methodName": "...", "methodDesc": "...", "accessFlags": 1} |
POST /bytecode/edit-field |
Edit field: {"className": "...", "fieldName": "...", "accessFlags": 2} |
POST /bytecode/remove-member |
Remove member: {"className": "...", "memberName": "...", "memberType": "method"} |
POST /bytecode/add-field |
Add field: {"className": "...", "fieldName": "...", "descriptor": "I"} |
POST /bytecode/add-method |
Add method: {"className": "...", "methodName": "...", "methodDesc": "()V"} |
POST /diff |
Diff classes: {"className1": "A", "className2": "B"} or {"className1": "A", "source": "..."} |
POST /export/jar |
Export JAR: {"outputPath": "/path/to/output.jar"} |
POST /export/source |
Export source: {"outputDir": "/path/to/src", "className": "optional"} |
POST /workspace/outline |
Class outline: {"className": "com/example/Main"} — lightweight structure, no code |
POST /workspace/read-file |
Read file: {"path": "META-INF/MANIFEST.MF", "maxChars": 60000} |
POST /workspace/delete-class |
Delete class: {"className": "com/example/Main"} |
POST /bytecode/instructions |
Method bytecode: {"className": "...", "methodName": "...", "methodDesc": "..."} |
POST /compile |
Compile Java: {"className": "com.example.Main", "source": "...", "targetVersion": 17, "debug": true} |
POST /disassemble |
Disassemble class: {"className": "com/example/Main", "maxChars": 120000} |
POST /disassemble/method |
Disassemble method: {"className": "...", "methodName": "...", "methodDesc": "...", "maxChars": 120000} |
POST /assemble |
Assemble JASM: {"className": "com/example/Main", "source": "..."} |
POST /patch |
Patch: {"action": "create"} or {"action": "apply", "patchJson": "..."} |
POST /deobf/eval-method |
Eval method: {"className": "...", "methodName": "...", "methodDesc": "...", "arguments": [...], "timeout": 5000} |
POST /deobf/simplify-method |
Simplify method: {"className": "...", "methodName": "...", "methodDesc": "...", "passes": 3} |
Technical Details
| Item | Value |
|---|---|
| MCP Protocol Version | 2024-11-05 |
| Bridge Port | 9847 (hardcoded) |
| MCP Server Dependencies | Gson only (no MCP SDK — lightweight custom JSON-RPC implementation) |
| Decompile Timeout | 30 seconds |
| Default Max Search Results | 100 |
| Default Class List Limit | 500 (with offset pagination) |
| Java Toolchain | JDK 22+ |
| Build System | Gradle with Shadow plugin for fat JAR |
| Total MCP Tools | 28 |
Troubleshooting
“Connection refused” errors from MCP Server
- Make sure Recaf is running and the Bridge Server is active on port 9847.
- Check Recaf’s Logging panel for the startup banner.
MCP tools not appearing in AI client
- Verify the path to
recaf-mcp-server-1.3.0.jaris correct and absolute. - Make sure
javapoints to JDK 22+: runjava -versionto check. - Restart your AI client after updating the MCP configuration.
Decompilation returns empty or errors
- Ensure a workspace is open (use
open_jarfirst). - Check the class name format: use
/separators (e.g.com/example/Main), not.separators.
Structured error responses
- All errors now include
code,message, andsuggestionfields. - Common codes:
NO_WORKSPACE,CLASS_NOT_FOUND,MEMBER_NOT_FOUND,INVALID_PARAMS,DECOMPILE_TIMEOUT,COMPILE_FAILED,ASSEMBLER_FAILED,PATCH_FAILED,EVAL_FAILED,EVAL_TIMEOUT,SIMPLIFY_FAILED.
Build fails
- Ensure JDK 22+ is installed. Run
./gradlew -q javaToolchainsto see detected JDKs. - If using a non-default JDK, configure a Gradle toolchain.
Changelog
v1.3.0
- String decryption —
eval_methodexecutes static methods in a sandboxed ClassLoader, enabling direct invocation of obfuscator string decryption functions to recover plaintext - Bytecode simplification —
simplify_methodperforms multi-pass bytecode transforms: constant folding, dead branch elimination, goto chain combining, NOP cleanup, and unreachable code removal - New error codes —
EVAL_FAILED,EVAL_TIMEOUT,SIMPLIFY_FAILED - Deobfuscation handler — new
DeobfuscationHandlerwith sandboxedWorkspaceClassLoader(parent = PlatformClassLoader for isolation) - COMPUTE_FRAMES fallback — simplify_method falls back to
COMPUTE_MAXSifCOMPUTE_FRAMESfails on malformed bytecode - Tool count: 26 → 28
v1.2.0
- Batch rename —
batch_renameapplies multiple class/field/method renames in a single atomic operation, ideal for deobfuscation workflows - Java compilation —
compile_javacompiles Java source code via Recaf’s JavacCompiler and applies the result to the workspace - JASM assembly/disassembly —
disassemble_classandassemble_classfor full class JASM round-trip;method_disassemblefor single method disassembly - Method bytecode viewer —
method_bytecodeshows detailed bytecode instructions (opcodes, operands, try-catch blocks, local variables) via ASM tree API - Class outline —
class_outlineprovides lightweight class structure (fields, methods, access flags) without decompiling code - File reader —
read_filereads non-class files from the workspace (e.g. MANIFEST.MF, config files, resources) - Class deletion —
class_deleteremoves a class from the workspace - Patch system —
patchtool creates and applies workspace change patches (serializable JSON format) - New error codes —
COMPILE_FAILED,COMPILER_UNAVAILABLE,PATCH_FAILED - 4 new Recaf service injections — AssemblerPipelineManager, JavacCompiler, PatchProvider, PatchApplier
- Tool count: 16 → 26
v1.1.0
- Multi-workspace support — open multiple JARs simultaneously, switch between them with
switch_workspaceandlist_workspaces - Bytecode editing —
edit_bytecodetool with 5 operations: edit_method, edit_field, remove_member, add_field, add_method (ASM-based) - Class diff —
diff_classestool produces unified diff between two decompiled classes or class vs. provided source - Export —
export_jarexports the workspace (with modifications) as a JAR;export_sourceexports decompiled source to a directory - Pagination —
list_classesnow supportsoffset/limitwithtotalMatched/hasMoremetadata - Structured errors — all errors return
code,message, andsuggestionfields (e.g.NO_WORKSPACE,CLASS_NOT_FOUND) - Error detection — MCP Server now sets
isError: trueon error responses for better AI client handling - Tool count: 10 → 16
v1.0.0
- Initial release with 10 MCP tools: open_jar, close_workspace, list_classes, get_class_info, decompile_class, search_code, get_call_graph, get_inheritance, rename_symbol, export_mappings
License
MIT
Install
This server does not publish a one-line install command.
Open the repository installation guideConfiguration
{
"mcpServers": {
"recaf": {
"command": "java",
"args": ["-jar", "/absolute/path/to/build/mcp/recaf-mcp-server-1.3.0.jar"]
}
}
}