Skip to content

d4rkmen/jeb-mcp-ext

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

jeb-mcp-extension

A single-file JEB Decompiler engines plugin that augments JEB's built-in MCP server (the one started from Tools -> MCP Server in the JEB UI) without modifying jeb.jar or any vendor jars.

It adds a Python-script execution tool, hardens the server against a couple of known JEB bugs, and works directly with Cursor IDE / Claude Desktop / any other MCP client.

Tested on JEB 5.39.0 (mcpsdk-fatjar-0.11.2, Jackson 2) and JEB 5.40.0 (mcpsdk-fatjar-1.1.2, Jackson 3). The plugin auto-detects the SDK shape at runtime — the same .java file works on both.


Why

JEB's built-in MCP server is great, but out of the box it has three problems that bite hard with modern MCP clients:

  1. No run_python_script-style tool. You can't ask the LLM to drive JEB's own Jython API the way File -> Scripts... does.
  2. Strict Jackson in older JEB rejects MCP clients that send unknown fields like capabilities.elicitation.form (Cursor 2025+ does this on initialize), so the handshake never completes.
  3. **Tools -> MCP Server -> Stop is a one-way trip.** The static jebmcpserver field is never cleared, so subsequent Start returns the dead instance and you have to fully relaunch JEB to get the server back.

This plugin fixes all three.


Features

run_python_script MCP tool

Executes a .py file inside the running JEB process using JEB's bundled Jython 2.7 interpreter — the same engine that powers File -> Scripts... in the GUI.

Pre-bound globals (when present):

name type notes
engines IEnginesContext the live engines context
project IRuntimeProject None
ctx IClientContext adapter minimal headless adapter; UI-only methods throw

Inputs:

name type default notes
script_path string absolute path to the .py file
script_args string[] [] extra sys.argv (sys.argv[0] is always the script)
timeout_seconds integer 60 hard kill ceiling, capped at 600

Outputs: { success, stdout, stderr, duration_ms, timed_out, error? }.

Stdout / stderr are also tee'd live into JEB's Logger view (line by line) so you can watch a long-running script execute from inside JEB while still getting the full captured text back through MCP.

Stability / compatibility fixes

# Bug Fix
1 Strict-Jackson initialize handshake fails (JEB ≤ 5.39). Cursor's capabilities.elicitation.form causes a Jackson UnrecognizedPropertyException. On every fresh server instance, the watchdog reflects on the live IJebMcpServer graph and disables DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES on every Jackson ObjectMapper it finds. Replaces a static jar patch entirely.
2 Restart bug. JebMcpServerInstance.stop() never clears the static jebmcpserver field; subsequent start() returns the dead instance. Watchdog detects Server.isStopped() == true while the static is still set and clears it under the same monitor that start()/stop() synchronize on.
3 One bad tool wedges the loop. McpServer.sync(...) dispatches handlers serially on a single thread. Each injected handler runs inside try/catch, and run_python_script runs on a daemon-thread executor with a hard timeout. The executor is static + lazy + self-healing, so it survives plugin hot-reload.

The watchdog only injects/repairs our tool and the static field, and tweaks the SDK's ObjectMappers; it does not modify the original JEB-shipped tool handlers.


Repository layout

jeb_mcp/
├── mcp-ext-plugin/
│   └── MCPExtensionsPlugin.java   ← the plugin (single Java file, JEB compiles it on demand)
├── install.cmd                    ← copies the .java into <JEB>/coreplugins/scripts/
├── mcp.json                       ← example Cursor / MCP-client config
├── smoketest.py                   ← Jython script to verify run_python_script end-to-end
├── README.md

Installation

1. Drop the plugin into your JEB install

git clone https://github.com/<you>/jeb_mcp.git
cd jeb_mcp
install.cmd                                :: defaults to C:\Work\tools\JEB-5.40.0
install.cmd "C:\Work\tools\JEB-5.39.0"     :: or pass an explicit JEB root

That copies MCPExtensionsPlugin.java into <JEB>/coreplugins/scripts/. JEB compiles single-file Java plugins on demand at startup, so no separate build step is needed.

2. Start JEB and turn on its MCP server

Tools -> MCP Server -> Start (default port 8425).

You should see in JEB's Logger view:

[I] [mcp-ext] loaded; watching JEB MCP server for tool injection
[I] [mcp-ext] injected tools into JEB MCP server: [run_python_script]

On JEB 5.39 you'll additionally see:

[I] [mcp-ext] patched N Jackson ObjectMapper(s): FAIL_ON_UNKNOWN_PROPERTIES disabled

The injection happens automatically the first time the MCP server is started (watchdog polls every 2 s).

3. Point your MCP client at JEB

mcp.json (Cursor, Claude Desktop, etc.):

{
  "mcpServers": {
    "jeb": {
      "url": "http://localhost:8425/mcp"
    }
  }
}

No stdio proxy is needed — modern MCP clients support HTTP+SSE directly, and the plugin makes JEB's strict Jackson accept whatever capability fields the client sends.

4. Verify with the smoketest

From any MCP client (or via Cursor's tool runner):

// Tool: run_python_script
{
  "script_path": "C:\\Work\\jeb_mcp\\smoketest.py",
  "script_args": ["hello"],
  "timeout_seconds": 30,
}

Expected (truncated):

{
  "success": true,
  "duration_ms": 551,
  "timed_out": false,
  "stdout": "...\n[smoketest] hello from JEB MCP run_python_script  ts=...\n... engines: com.pnfsoftware.jebglobal.Sr (projects=1)\n...",
  "stderr": "",
}

How it works (short version)

  • Single-file Java plugin in <JEB>/coreplugins/scripts/. JEB's IEnginesPlugin lifecycle calls load()/execute()/dispose() for us.
  • **load() spawns a daemon "watchdog" thread** that polls every 2 s for changes to JebMcpServerInstance.get(). When it sees a fresh IJebMcpServer, it:
    1. (best-effort) walks the object graph and disables strict Jackson;
    2. reflects out the McpSyncServer;
    3. removes any stale tool registration with our names, then re-registers run_python_script with the current SDK API.
  • Cross-version reflection. Both the schema setter (Tool$Builder.inputSchema(String) vs (McpJsonMapper, String)) and the result builder (structuredContent(Map) vs structuredContent(Object)) changed between JEB 5.39 and 5.40. The plugin tries the legacy signature first, falls back to the new one on NoSuchMethodException, and caches a JacksonMcpJsonMapperSupplier instance for the new path.
  • Obfuscation-resilient field lookups. Internal JEB classes (com.pnfsoftware.jeb.client.mcp.WH, etc.) get re-obfuscated between releases. Every reference goes through findFieldValueByTypeName, i.e. we match by Java type, not by field name, so renames don't break us.
  • No jeb.jar mutation, no proxy, no jar swap — the plugin is the only artifact that needs to be installed.

Compatibility

JEB mcpsdk-fatjar Jackson inputSchema setter structuredContent setter Status
5.39.0 0.11.2 2.x (String) (Map) OK
5.40.0 1.1.2 3.x (McpJsonMapper, String) (Object) OK
  • Java target: 21 (matches JEB's required JDK 21).
  • Jython: any 2.7.x bundled with JEB (5.39/5.40 both ship 2.7.3).
  • OS: developed and tested on Windows; nothing in the plugin is platform- specific (install.cmd is the only Windows-only piece — the .java file itself just needs to land in <JEB>/coreplugins/scripts/).

Troubleshooting

symptom likely cause what to do
[E] [mcp-ext] forced injection failed: java.lang.reflect.InvocationTargetException JEB hot-reloaded the plugin and the previous incarnation already registered the tools. The next watchdog tick (≤ 2 s) re-injects via removeTool + addTool — should self-heal. If it doesn't, full-restart JEB.
RejectedExecutionException ... ThreadPoolExecutor [Terminated] JEB called dispose() on a previous plugin instance; a zombie tool registration is still live. Newer plugin builds make the executor static + self-healing — restart JEB once and the next call rebuilds the pool.
Response missing structured content from the MCP client Old plugin running on a new SDK (or vice versa). Reinstall and restart JEB.
MCP initialize hangs / errors with UnrecognizedPropertyException on JEB 5.39 The Jackson lenient-mode patch didn't run yet. Verify in the Logger view that [I] [mcp-ext] patched N Jackson ObjectMapper(s) appeared. If not, restart the MCP server from the menu — the watchdog will redo the patch.

License

MIT. See the header of mcp-ext-plugin/MCPExtensionsPlugin.java.

Originally by d4rkmen.

About

JEB Decompiler Plugin: native MCP tweaks

Topics

Resources

License

Stars

Watchers

Forks

Contributors