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:
parent
4379bea14f
commit
bc1e137878
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
31
README.md
31
README.md
@ -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)
|
||||
{
|
||||
|
||||
@ -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
10
pom.xml
@ -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>
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user