chore: prepare v2.0.0 release

- Update version to v2.0.0 in ApiConstants.java and bridge_mcp_hydra.py
- Create CHANGELOG v2.0.0 section with release date
- Fix Ghidra 11.3.2+ compatibility in TransactionHelper (endTransaction signature)
- Clarify instances_list vs instances_discover usage in documentation
- Remove commented-out code in pom.xml

Fixes #7
Closes #5
This commit is contained in:
Teal Bauer 2025-11-11 12:54:03 +01:00
parent 4379bea14f
commit bc1e137878
7 changed files with 53 additions and 76 deletions

View File

@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
## [Unreleased]
## [2.0.0] - 2025-11-11
### Added
- **MCP Integration Refactor:** Refactored the Python bridge for improved MCP integration. (337f89e)
- Introduced MCP resources for loading context (e.g., instances, functions, disassembly).
@ -115,7 +117,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
- Initial project setup
- Basic MCP bridge functionality
[unreleased]: https://github.com/teal-bauer/GhydraMCP/compare/v1.4.0...HEAD
[unreleased]: https://github.com/teal-bauer/GhydraMCP/compare/v2.0.0...HEAD
[2.0.0]: https://github.com/teal-bauer/GhydraMCP/compare/v1.4.0...v2.0.0
[1.4.0]: https://github.com/teal-bauer/GhydraMCP/compare/v1.3.0...v1.4.0
[1.3.0]: https://github.com/teal-bauer/GhydraMCP/compare/v1.2...v1.3.0
[1.2]: https://github.com/teal-bauer/GhydraMCP/compare/v1.1...v1.2

View File

@ -83,12 +83,12 @@ When making changes, update version numbers in these locations:
1. **Plugin Version** in `src/main/java/eu/starsong/ghidra/api/ApiConstants.java`:
```java
public static final String PLUGIN_VERSION = "v2.0.0-beta.1";
public static final String PLUGIN_VERSION = "v2.0.0";
```
2. **Bridge Version** in `bridge_mcp_hydra.py`:
```python
BRIDGE_VERSION = "v2.0.0-beta.1"
BRIDGE_VERSION = "v2.0.0"
```
### API Versions

View File

@ -121,7 +121,7 @@ First, download the latest [release](https://github.com/teal-bauer/GhydraMCP/rel
1. Run Ghidra
2. Select `File` -> `Install Extensions`
3. Click the `+` button
4. Select the `GhydraMCP-2.0.0-beta.1.zip` (or your chosen version) from the downloaded release
4. Select the `GhydraMCP-[version].zip` file from the downloaded release
5. Restart Ghidra
6. Make sure the GhydraMCPPlugin is enabled in `File` -> `Configure` -> `Developer`
@ -177,10 +177,10 @@ Theoretically, any MCP client should work with GhydraMCP. Two examples are given
- `update_data`: Update both name and type (params: address, name, data_type)
**Instance Management**:
- `list_instances`: List active Ghidra instances (no params)
- `list_instances`: List active Ghidra instances, automatically discovering new ones on default host (no params) - **use this first**
- `discover_instances`: Discover instances on a specific host (params: host [optional]) - **only use for non-default hosts**
- `register_instance`: Register new instance (params: port, url)
- `unregister_instance`: Remove instance (params: port)
- `discover_instances`: Auto-discover running instances (params: host [optional])
**Example Usage**:
```python
@ -210,12 +210,10 @@ client.use_tool("ghydra", "update_data", {"address": "0x00401238", "name": "ptr_
client.use_tool("ghydra", "delete_data", {"address": "0x0040123C"})
# Instance management
client.use_tool("ghydra", "list_instances") # Lists all instances (auto-discovers on default host)
client.use_tool("ghydra", "discover_instances", {"host": "192.168.1.10"}) # Only if scanning different host
client.use_tool("ghydra", "register_instance", {"port": 8192, "url": "http://localhost:8192/"})
client.use_tool("ghydra", "register_instance", {"port": 8193})
# Auto-discover instances
client.use_tool("ghydra", "discover_instances") # Default host
client.use_tool("ghydra", "discover_instances", {"host": "192.168.1.10"}) # Custom host
```
## Client Setup
@ -256,24 +254,7 @@ Check which Ghidra instances are currently running.
**Assistant:**
```
I'll check which Ghidra instances are currently running by discovering any active instances.
View result from discover_instances from ghydra (local)
{
"found": 2,
"instances": [
{
"port": 8192,
"url": "http://localhost:8192",
"result": "Registered instance on port 8192 at http://localhost:8192"
},
{
"port": 8193,
"url": "http://localhost:8193",
"result": "Registered instance on port 8193 at http://localhost:8193"
}
]
}
I'll check which Ghidra instances are currently running.
View result from list_instances from ghydra (local)
{

View File

@ -31,7 +31,7 @@ DEFAULT_GHIDRA_HOST = "localhost"
QUICK_DISCOVERY_RANGE = range(DEFAULT_GHIDRA_PORT, DEFAULT_GHIDRA_PORT+10)
FULL_DISCOVERY_RANGE = range(DEFAULT_GHIDRA_PORT, DEFAULT_GHIDRA_PORT+20)
BRIDGE_VERSION = "v2.0.0-beta.5"
BRIDGE_VERSION = "v2.0.0"
REQUIRED_API_VERSION = 2005
current_instance_port = DEFAULT_GHIDRA_PORT
@ -39,7 +39,10 @@ current_instance_port = DEFAULT_GHIDRA_PORT
instructions = """
GhydraMCP allows interacting with multiple Ghidra SRE instances. Ghidra SRE is a tool for reverse engineering and analyzing binaries, e.g. malware.
First, run `instances_discover()` to find all available Ghidra instances (both already known and newly discovered). Then use `instances_use(port)` to set your working instance.
First, run `instances_list()` to see all available Ghidra instances (automatically discovers instances on the default host).
Then use `instances_use(port)` to set your working instance.
Note: Use `instances_discover(host)` only if you need to scan a different host.
The API is organized into namespaces for different types of operations:
- instances_* : For managing Ghidra instances
@ -1151,7 +1154,19 @@ def reverse_engineer_binary_prompt(port: int = None):
# Instance management tools
@mcp.tool()
def instances_list() -> dict:
"""List all active Ghidra instances"""
"""List all active Ghidra instances
This is the primary tool for working with instances. It automatically discovers
new instances on the default host before listing.
Use instances_discover(host) only if you need to scan a different host.
Returns:
dict: Contains 'instances' list with all available Ghidra instances
"""
# Auto-discover new instances before listing
_discover_instances(QUICK_DISCOVERY_RANGE, host=None, timeout=0.5)
with instances_lock:
return {
"instances": [
@ -1167,44 +1182,32 @@ def instances_list() -> dict:
@mcp.tool()
def instances_discover(host: str = None) -> dict:
"""Discover available Ghidra instances by scanning ports
"""Discover Ghidra instances on a specific host
Use this ONLY when you need to discover instances on a different host.
For normal usage, just use instances_list() which auto-discovers on the default host.
Args:
host: Optional host to scan (default: configured ghidra_host)
host: Host to scan for Ghidra instances (default: configured ghidra_host)
Returns:
dict: Contains 'found' count, 'new_instances' count, and 'instances' list with all available instances
dict: Contains 'instances' list with all available instances after discovery
"""
# Get newly discovered instances
discovery_result = _discover_instances(QUICK_DISCOVERY_RANGE, host=host, timeout=0.5)
new_instances = discovery_result.get("instances", [])
new_count = len(new_instances)
# Discover instances on the specified host
_discover_instances(QUICK_DISCOVERY_RANGE, host=host, timeout=0.5)
# Get all currently known instances (including ones that were already registered)
all_instances = []
# Return all instances (same format as instances_list for consistency)
with instances_lock:
for port, info in active_instances.items():
instance_info = {
return {
"instances": [
{
"port": port,
"url": info["url"],
"project": info.get("project", ""),
"file": info.get("file", ""),
"plugin_version": info.get("plugin_version", "unknown"),
"api_version": info.get("api_version", "unknown")
"file": info.get("file", "")
}
# Mark if this was newly discovered in this call
instance_info["newly_discovered"] = any(inst["port"] == port for inst in new_instances)
all_instances.append(instance_info)
# Sort by port for consistent ordering
all_instances.sort(key=lambda x: x["port"])
return {
"found": len(all_instances), # Total instances available
"new_instances": new_count, # How many were newly discovered
"instances": all_instances # All available instances
for port, info in active_instances.items()
]
}
@mcp.tool()

10
pom.xml
View File

@ -99,16 +99,6 @@
</resources>
<plugins>
<!-- Set Java version -->
<!-- Resources plugin to handle filtering -->
<!-- <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.3.1</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin> -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>

View File

@ -1,7 +1,7 @@
package eu.starsong.ghidra.api;
public class ApiConstants {
public static final String PLUGIN_VERSION = "v2.0.0-beta.5";
public static final String PLUGIN_VERSION = "v2.0.0";
public static final int API_VERSION = 2005;
public static final int DEFAULT_PORT = 8192;
public static final int MAX_PORT_ATTEMPTS = 10;

View File

@ -38,7 +38,7 @@ public class TransactionHelper {
Msg.error(TransactionHelper.class, "Transaction failed: " + transactionName, e);
} finally {
if (txId >= 0) {
program.endTransaction(txId, success);
success = program.endTransaction(txId, success);
}
}
});