diff --git a/BUG_REPORT_HEADLESS_GSON.md b/BUG_REPORT_HEADLESS_GSON.md index af9573a..05e764a 100644 --- a/BUG_REPORT_HEADLESS_GSON.md +++ b/BUG_REPORT_HEADLESS_GSON.md @@ -2,11 +2,11 @@ ## Summary -The GhydraMCP Docker container fails to start the HTTP API server because `GhydraMCPServer.java` imports Gson, but Gson is not available in Ghidra's headless script classpath. +The MCGhidra Docker container fails to start the HTTP API server because `MCGhidraServer.java` imports Gson, but Gson is not available in Ghidra's headless script classpath. ## Environment -- GhydraMCP Docker image: `ghydramcp:latest` +- MCGhidra Docker image: `mcghidra:latest` - Ghidra Version: 11.4.2 - Build Date: 2025-08-26 @@ -14,12 +14,12 @@ The GhydraMCP Docker container fails to start the HTTP API server because `Ghydr 1. Build the Docker image: ```bash - docker build -t ghydramcp:latest -f docker/Dockerfile . + docker build -t mcghidra:latest -f docker/Dockerfile . ``` 2. Run with a binary: ```bash - docker run -p 8192:8192 -v /path/to/binary:/binaries/test ghydramcp:latest /binaries/test + docker run -p 8192:8192 -v /path/to/binary:/binaries/test mcghidra:latest /binaries/test ``` 3. Check logs: @@ -37,9 +37,9 @@ Analysis completes but the script fails to load: ``` INFO REPORT: Analysis succeeded for file: file:///binaries/cardv (HeadlessAnalyzer) -ERROR REPORT SCRIPT ERROR: GhydraMCPServer.java : The class could not be found. +ERROR REPORT SCRIPT ERROR: MCGhidraServer.java : The class could not be found. It must be the public class of the .java file: Failed to get OSGi bundle containing script: -/opt/ghidra/scripts/GhydraMCPServer.java (HeadlessAnalyzer) +/opt/ghidra/scripts/MCGhidraServer.java (HeadlessAnalyzer) ``` The health check fails because the HTTP server never starts: @@ -50,7 +50,7 @@ The health check fails because the HTTP server never starts: ## Root Cause Analysis -`GhydraMCPServer.java` (lines 22-24) imports Gson: +`MCGhidraServer.java` (lines 22-24) imports Gson: ```java import com.google.gson.Gson; @@ -61,14 +61,14 @@ import com.google.gson.JsonParser; However: 1. Gson is **not** bundled with Ghidra -2. The GhydraMCP extension JAR includes Gson, but headless scripts run in a **separate OSGi classloader** without access to extension lib dependencies +2. The MCGhidra extension JAR includes Gson, but headless scripts run in a **separate OSGi classloader** without access to extension lib dependencies 3. The Dockerfile doesn't copy Gson to Ghidra's script classpath ## Verification ```bash # Check if Gson is in the built extension -unzip -l target/GhydraMCP-*.zip | grep -i gson +unzip -l target/MCGhidra-*.zip | grep -i gson # Result: No matches # Check Ghidra's lib directories @@ -90,13 +90,13 @@ RUN curl -fsSL "https://repo1.maven.org/maven2/com/google/gson/gson/2.10.1/gson- ### Option 2: Use Built-in JSON (No External Dependencies) -Rewrite `GhydraMCPServer.java` to use only JDK classes: +Rewrite `MCGhidraServer.java` to use only JDK classes: - Replace Gson with `javax.json` or manual JSON string building - This ensures the script works without any external dependencies ### Option 3: Pre-compiled Script JAR -Compile `GhydraMCPServer.java` with Gson into a JAR and place it in the extension, then reference it differently in headless mode. +Compile `MCGhidraServer.java` with Gson into a JAR and place it in the extension, then reference it differently in headless mode. ## Impact @@ -106,7 +106,7 @@ Compile `GhydraMCPServer.java` with Gson into a JAR and place it in the extensio ## Additional Context -The main GhydraMCP plugin works fine in GUI mode because the extension's lib dependencies are loaded. This only affects the headless Docker workflow where scripts are loaded separately from the extension. +The main MCGhidra plugin works fine in GUI mode because the extension's lib dependencies are loaded. This only affects the headless Docker workflow where scripts are loaded separately from the extension. --- diff --git a/CHANGELOG.md b/CHANGELOG.md index 614760e..d6db257 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,14 +75,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). - **Silent Exception Handling:** Added debug logging to PortPool exception handlers and analysis fallback paths. - **File Descriptor Leak:** Fixed potential leak in `PortPool._try_acquire_port()` if write operations fail after lock acquisition. - **Hash Algorithm Consistency:** Changed query hash from MD5 to SHA-256 in pagination module for consistency with cursor ID generation. -- **Lazy PortPool Initialization:** `PortPool` now created on first use, avoiding `/tmp/ghydramcp-ports` directory creation when Docker tools are never used. +- **Lazy PortPool Initialization:** `PortPool` now created on first use, avoiding `/tmp/mcghidra-ports` directory creation when Docker tools are never used. - **Logging Configuration:** `configure_logging()` now called during server startup — debug messages actually work now. - **Type Hint Consistency:** Aligned `filtering.py` to use `List[T]` from typing module like rest of codebase. - **Parameter Naming:** Renamed `project_fields` to `fields` in `structs_get()` for consistency with other tools. - **Import Path:** Fixed `logging.py` to import `Context` from `fastmcp` (not deprecated `mcp.server.fastmcp` path). ### Added -- **Debug Logging Environment Variable:** Set `GHYDRAMCP_DEBUG=1` to enable DEBUG-level logging for troubleshooting. +- **Debug Logging Environment Variable:** Set `MCGHIDRA_DEBUG=1` to enable DEBUG-level logging for troubleshooting. ## [2025.12.1] - 2025-12-01 @@ -239,7 +239,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ## [1.1] - 2025-03-30 ### Added -- Initial release of GhydraMCP bridge +- Initial release of MCGhidra bridge - Basic Ghidra instance management tools - Function analysis tools - Variable manipulation tools @@ -250,11 +250,11 @@ 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/v2025.12.1...HEAD -[2025.12.1]: https://github.com/teal-bauer/GhydraMCP/compare/v2.0.0...v2025.12.1 -[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 -[1.1]: https://github.com/teal-bauer/GhydraMCP/compare/1.0...v1.1 -[1.0]: https://github.com/teal-bauer/GhydraMCP/releases/tag/1.0 \ No newline at end of file +[unreleased]: https://github.com/teal-bauer/MCGhidra/compare/v2025.12.1...HEAD +[2025.12.1]: https://github.com/teal-bauer/MCGhidra/compare/v2.0.0...v2025.12.1 +[2.0.0]: https://github.com/teal-bauer/MCGhidra/compare/v1.4.0...v2.0.0 +[1.4.0]: https://github.com/teal-bauer/MCGhidra/compare/v1.3.0...v1.4.0 +[1.3.0]: https://github.com/teal-bauer/MCGhidra/compare/v1.2...v1.3.0 +[1.2]: https://github.com/teal-bauer/MCGhidra/compare/v1.1...v1.2 +[1.1]: https://github.com/teal-bauer/MCGhidra/compare/1.0...v1.1 +[1.0]: https://github.com/teal-bauer/MCGhidra/releases/tag/1.0 \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7c83b7b..50fe512 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ -# Contributing to GhydraMCP +# Contributing to MCGhidra -Thank you for your interest in contributing to GhydraMCP! This document provides guidelines and information for contributors. +Thank you for your interest in contributing to MCGhidra! This document provides guidelines and information for contributors. ## Table of Contents @@ -13,10 +13,10 @@ Thank you for your interest in contributing to GhydraMCP! This document provides ## Project Structure -GhydraMCP consists of two main components: +MCGhidra consists of two main components: 1. **Java Plugin for Ghidra** (`src/main/java/eu/starsong/ghidra/`): - - Main class: `GhydraMCPPlugin.java` + - Main class: `MCGhidraPlugin.java` - API constants: `api/ApiConstants.java` - Endpoints: `endpoints/` directory - Data models: `model/` directory @@ -39,23 +39,23 @@ GhydraMCP consists of two main components: ```bash # Clone the repository -git clone https://github.com/starsong-consulting/GhydraMCP.git -cd GhydraMCP +git clone https://github.com/starsong-consulting/MCGhidra.git +cd MCGhidra # Build the project mvn clean package ``` This creates: -- `target/GhydraMCP-[version].zip` - The Ghidra plugin only -- `target/GhydraMCP-Complete-[version].zip` - Complete package with plugin and bridge script +- `target/MCGhidra-[version].zip` - The Ghidra plugin only +- `target/MCGhidra-Complete-[version].zip` - Complete package with plugin and bridge script ### Installing for Development 1. Build the project as described above 2. In Ghidra, go to `File` -> `Install Extensions` 3. Click the `+` button -4. Select the `GhydraMCP-[version].zip` file +4. Select the `MCGhidra-[version].zip` file 5. Restart Ghidra 6. Enable the plugin in `File` -> `Configure` -> `Developer` @@ -75,7 +75,7 @@ uv pip install mcp==1.6.0 requests==2.32.3 ## Versioning -GhydraMCP follows semantic versioning (SemVer) and uses explicit API versions: +MCGhidra follows semantic versioning (SemVer) and uses explicit API versions: ### Version Numbers @@ -244,4 +244,4 @@ If you have questions or need help, please: 2. Check existing documentation 3. Reach out to the maintainers directly -Thank you for contributing to GhydraMCP! \ No newline at end of file +Thank you for contributing to MCGhidra! \ No newline at end of file diff --git a/GHIDRA_HTTP_API.md b/GHIDRA_HTTP_API.md index 8d8d83b..a16b55b 100644 --- a/GHIDRA_HTTP_API.md +++ b/GHIDRA_HTTP_API.md @@ -1,4 +1,4 @@ -# GhydraMCP Ghidra Plugin HTTP API v2 +# MCGhidra Ghidra Plugin HTTP API v2 ## Overview @@ -159,7 +159,7 @@ Returns information about the current plugin instance, including details about t ``` ### `GET /instances` -Returns information about all active GhydraMCP plugin instances. +Returns information about all active MCGhidra plugin instances. ```json { "id": "req-instances", diff --git a/Makefile b/Makefile index 7abc5a2..5f6ed62 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -# GhydraMCP Makefile +# MCGhidra Makefile # Convenient commands for Docker and development operations .PHONY: help build build-dev up up-dev down down-dev logs logs-dev \ @@ -6,7 +6,7 @@ # Default target help: - @echo "GhydraMCP Docker Management" + @echo "MCGhidra Docker Management" @echo "============================" @echo "" @echo "Build commands:" @@ -44,10 +44,10 @@ help: # ============================================================================= build: - docker compose build ghydramcp + docker compose build mcghidra build-dev: - docker compose build ghydramcp-dev + docker compose build mcghidra-dev build-all: build build-dev @@ -56,14 +56,14 @@ build-all: build build-dev # ============================================================================= up: - docker compose --profile prod up -d ghydramcp - @echo "GhydraMCP starting... checking health in 30 seconds" + docker compose --profile prod up -d mcghidra + @echo "MCGhidra starting... checking health in 30 seconds" @sleep 30 @$(MAKE) health || echo "Server may still be starting up..." up-dev: - docker compose --profile dev up -d ghydramcp-dev - @echo "GhydraMCP (dev) starting..." + docker compose --profile dev up -d mcghidra-dev + @echo "MCGhidra (dev) starting..." down: docker compose --profile prod down @@ -90,7 +90,7 @@ ifndef FILE @exit 1 endif @echo "Analyzing: $(FILE)" - docker compose run --rm -v "$(dir $(FILE)):/binaries:ro" ghydramcp /binaries/$(notdir $(FILE)) + docker compose run --rm -v "$(dir $(FILE)):/binaries:ro" mcghidra /binaries/$(notdir $(FILE)) # Analyze in background (detached) analyze-bg: @@ -99,20 +99,20 @@ ifndef FILE @exit 1 endif @echo "Starting background analysis of: $(FILE)" - docker compose run -d -v "$(dir $(FILE)):/binaries:ro" ghydramcp /binaries/$(notdir $(FILE)) + docker compose run -d -v "$(dir $(FILE)):/binaries:ro" mcghidra /binaries/$(notdir $(FILE)) # ============================================================================= # Utility Commands # ============================================================================= shell: - docker compose --profile debug run --rm ghydramcp-shell + docker compose --profile debug run --rm mcghidra-shell logs: - docker compose logs -f ghydramcp + docker compose logs -f mcghidra logs-dev: - docker compose logs -f ghydramcp-dev + docker compose logs -f mcghidra-dev status: @echo "=== Container Status ===" @@ -122,8 +122,8 @@ status: @docker stats --no-stream $$(docker compose ps -q 2>/dev/null) 2>/dev/null || echo "No containers running" health: - @echo "Checking GhydraMCP API health..." - @curl -sf http://localhost:$${GHYDRA_PORT:-8192}/ | python3 -m json.tool 2>/dev/null \ + @echo "Checking MCGhidra API health..." + @curl -sf http://localhost:$${MCGHIDRA_PORT:-8192}/ | python3 -m json.tool 2>/dev/null \ || echo "API not responding (server may be starting or binary being analyzed)" # ============================================================================= @@ -135,7 +135,7 @@ clean: @echo "Containers and volumes removed" clean-all: clean - docker rmi ghydramcp:latest ghydramcp:dev 2>/dev/null || true + docker rmi mcghidra:latest mcghidra:dev 2>/dev/null || true @echo "Images removed" prune: @@ -147,10 +147,10 @@ prune: # ============================================================================= mcp: - uv run python -m ghydramcp + uv run python -m mcghidra mcp-dev: - uv run python -m ghydramcp --verbose + uv run python -m mcghidra --verbose # ============================================================================= # Development Commands diff --git a/QUICKSTART.md b/QUICKSTART.md index d4f4916..49d57dc 100644 --- a/QUICKSTART.md +++ b/QUICKSTART.md @@ -1,8 +1,8 @@ -# GhydraMCP Quick Start Guide +# MCGhidra Quick Start Guide -## What is GhydraMCP? +## What is MCGhidra? -GhydraMCP is a complete reverse engineering platform that combines: +MCGhidra is a complete reverse engineering platform that combines: - **Ghidra** - NSA's powerful binary analysis tool - **Docker** - Containerized, reproducible analysis environment - **HTTP REST API** - HATEOAS-compliant REST interface @@ -14,16 +14,16 @@ GhydraMCP is a complete reverse engineering platform that combines: ### 1. Analyze a Standard Binary (ELF/PE/Mach-O) ```bash -cd /home/rpm/claude/ghydramcp/GhydraMCP +cd /home/rpm/claude/mcghidra/MCGhidra # Build the Docker image (one time) -docker build -t ghydramcp:latest -f docker/Dockerfile . +docker build -t mcghidra:latest -f docker/Dockerfile . # Analyze any standard binary docker run -d --name my-analysis \ -p 8192:8192 \ -v $(pwd)/binaries:/binaries \ - ghydramcp:latest \ + mcghidra:latest \ /binaries/your-binary # Wait ~20 seconds for analysis, then access HTTP API @@ -45,7 +45,7 @@ python3 docker/arm_firmware_prep.py \ docker run -d --name arm-firmware \ -p 8192:8192 \ -v $(pwd)/binaries:/binaries \ - ghydramcp:latest \ + mcghidra:latest \ /binaries/your-firmware.elf ``` @@ -53,11 +53,11 @@ docker run -d --name arm-firmware \ ```bash # The MCP server is located at: -cd /home/rpm/claude/ghydramcp/GhydraMCP +cd /home/rpm/claude/mcghidra/MCGhidra ./launch.sh # Or with uv: -cd GhydraMCP && uv run ghydramcp +cd MCGhidra && uv run mcghidra ``` ## HTTP API Overview @@ -176,7 +176,7 @@ curl "http://localhost:8192/functions/$ENTRY/decompile" | jq -r '.result' ### List Running Containers ```bash -docker ps | grep ghydramcp +docker ps | grep mcghidra ``` ### View Logs @@ -201,7 +201,7 @@ docker run -d --name persistent \ -v $(pwd)/projects:/projects \ -v $(pwd)/binaries:/binaries \ -e PROJECT_NAME=MyProject \ - ghydramcp:latest \ + mcghidra:latest \ /binaries/my-binary # Projects are saved in ./projects/MyProject/ @@ -238,7 +238,7 @@ docker exec my-analysis sh -c 'chmod 644 /opt/ghidra/scripts/*.java' docker run -d --name analysis2 \ -p 8193:8192 \ -v $(pwd)/binaries:/binaries \ - ghydramcp:latest \ + mcghidra:latest \ /binaries/binary # Access at http://localhost:8193/ @@ -263,7 +263,7 @@ gcc -o binaries/test test.c docker run -d --name test-analysis \ -p 8192:8192 \ -v $(pwd)/binaries:/binaries \ - ghydramcp:latest \ + mcghidra:latest \ /binaries/test # Find hidden function @@ -284,7 +284,7 @@ python3 docker/arm_firmware_prep.py \ docker run -d --name cisco \ -p 8192:8192 \ -v $(pwd)/binaries:/binaries \ - ghydramcp:latest \ + mcghidra:latest \ /binaries/cisco.elf # Explore @@ -303,15 +303,15 @@ curl http://localhost:8192/data/strings | jq '.strings[] | select(.value | test( ## Project Structure ``` -GhydraMCP/ +MCGhidra/ ├── docker/ │ ├── Dockerfile # Main Docker image │ ├── entrypoint.sh # Container entry point -│ ├── GhydraMCPServer.java # HTTP API server (1724 lines) +│ ├── MCGhidraServer.java # HTTP API server (1724 lines) │ ├── ImportRawARM.java # Raw binary import script │ ├── arm_firmware_prep.py # ELF wrapper tool ⭐ │ └── README*.md # Documentation -├── src/ghydramcp/ # MCP server implementation +├── src/mcghidra/ # MCP server implementation │ ├── __init__.py │ ├── server.py # FastMCP server │ └── mixins/ # Modular functionality diff --git a/README.md b/README.md index d0d4d5f..30ec7cd 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# GhydraMCP +# MCGhidra **AI-native reverse engineering.** Give Claude (or any MCP client) direct access to Ghidra's analysis engine. @@ -60,10 +60,10 @@ No Ghidra installation needed. Analyze binaries in isolated containers. ```bash # Build the image (once) -cd GhydraMCP && docker build -t ghydramcp:latest -f docker/Dockerfile . +cd MCGhidra && docker build -t mcghidra:latest -f docker/Dockerfile . # Add to your MCP config -claude mcp add ghydramcp -- uv run --directory /path/to/GhydraMCP ghydramcp +claude mcp add mcghidra -- uv run --directory /path/to/MCGhidra mcghidra ``` Then in Claude: @@ -76,14 +76,14 @@ Claude will auto-start a container, wait for analysis, and begin work. ### Option 2: Native Ghidra 1. **Install the Ghidra plugin:** - - Download latest [release](https://github.com/starsong-consulting/GhydraMCP/releases) + - Download latest [release](https://github.com/starsong-consulting/MCGhidra/releases) - In Ghidra: `File → Install Extensions → +` → select the `.zip` - Restart Ghidra - - Enable in `File → Configure → Developer → GhydraMCPPlugin` + - Enable in `File → Configure → Developer → MCGhidraPlugin` 2. **Add MCP server:** ```bash - claude mcp add ghydramcp -- uv run --directory /path/to/GhydraMCP ghydramcp + claude mcp add mcghidra -- uv run --directory /path/to/MCGhidra mcghidra ``` 3. **Open a binary in Ghidra**, then ask Claude to analyze it. @@ -94,14 +94,14 @@ Claude will auto-start a container, wait for analysis, and begin work. ``` ┌──────────────┐ MCP ┌──────────────┐ HTTP ┌──────────────┐ -│ Claude │◄────────────►│ GhydraMCP │◄────────────►│ Ghidra │ +│ Claude │◄────────────►│ MCGhidra │◄────────────►│ Ghidra │ │ (or other │ stdio │ (Python) │ REST API │ Plugin │ │ MCP client) │ │ │ │ (Java) │ └──────────────┘ └──────────────┘ └──────────────┘ ``` - **Ghidra Plugin**: Exposes Ghidra's analysis via HTTP REST API (HATEOAS) -- **GhydraMCP Server**: Translates MCP tool calls to API requests +- **MCGhidra Server**: Translates MCP tool calls to API requests - **Multi-instance**: Analyze multiple binaries simultaneously on different ports - **Session isolation**: Docker containers get unique ports, preventing conflicts @@ -181,9 +181,9 @@ These guide Claude through systematic analysis with progress reporting. ```json { "mcpServers": { - "ghydramcp": { + "mcghidra": { "command": "uv", - "args": ["run", "--directory", "/path/to/GhydraMCP", "ghydramcp"] + "args": ["run", "--directory", "/path/to/MCGhidra", "mcghidra"] } } } @@ -191,7 +191,7 @@ These guide Claude through systematic analysis with progress reporting. **Claude Code**: ```bash -claude mcp add ghydramcp -- uv run --directory /path/to/GhydraMCP ghydramcp +claude mcp add mcghidra -- uv run --directory /path/to/MCGhidra mcghidra ``` --- @@ -267,25 +267,25 @@ See `--help` or the [API docs](GHIDRA_HTTP_API.md) for full parameter details. ```bash # Clone -git clone https://github.com/starsong-consulting/GhydraMCP -cd GhydraMCP +git clone https://github.com/starsong-consulting/MCGhidra +cd MCGhidra # Build Ghidra plugin mvn clean package -# → target/GhydraMCP-[version].zip +# → target/MCGhidra-[version].zip # Build Docker image -docker build -t ghydramcp:latest -f docker/Dockerfile . +docker build -t mcghidra:latest -f docker/Dockerfile . # Run MCP server (for development) -uv run ghydramcp +uv run mcghidra ``` --- ## Architecture -GhydraMCP is designed for AI agents: +MCGhidra is designed for AI agents: - **Lazy registration**: `instances_use` doesn't block — validates on first real call - **Non-blocking I/O**: All Docker/HTTP operations run in thread executors diff --git a/TESTING.md b/TESTING.md index 12d3c25..8d043c0 100644 --- a/TESTING.md +++ b/TESTING.md @@ -1,11 +1,11 @@ -# Testing GhydraMCP +# Testing MCGhidra -This document describes how to test the GhydraMCP plugin and bridge. +This document describes how to test the MCGhidra plugin and bridge. ## Prerequisites - Python 3.11 or higher -- Ghidra with the GhydraMCP plugin installed and running +- Ghidra with the MCGhidra plugin installed and running - The `requests` Python package (`pip install requests`) ## Running All Tests @@ -34,7 +34,7 @@ The `test_http_api.py` script tests the HTTP API exposed by the Java plugin. It ### Running the HTTP API Tests -1. Make sure Ghidra is running with the GhydraMCP plugin loaded +1. Make sure Ghidra is running with the MCGhidra plugin loaded 2. Run the tests: ```bash @@ -57,7 +57,7 @@ The `test_mcp_client.py` script tests the MCP bridge functionality using the MCP ### Running the MCP Bridge Tests -1. Make sure Ghidra is running with the GhydraMCP plugin loaded +1. Make sure Ghidra is running with the MCGhidra plugin loaded 2. Run the tests: ```bash @@ -89,7 +89,7 @@ The test script will: ### HTTP API Tests -- If tests are skipped with "Ghidra server not running or not accessible", make sure Ghidra is running and the GhydraMCP plugin is loaded. +- If tests are skipped with "Ghidra server not running or not accessible", make sure Ghidra is running and the MCGhidra plugin is loaded. - If tests fail with connection errors, check that the plugin is listening on the expected port (default: 8192). ### MCP Bridge Tests @@ -103,7 +103,7 @@ The test script will: To add a new test for an HTTP endpoint: -1. Add a new test method to the `GhydraMCPHttpApiTests` class +1. Add a new test method to the `MCGhidraHttpApiTests` class 2. Use the `requests` library to make HTTP requests to the endpoint 3. Verify the response using assertions diff --git a/bridge_mcp_hydra.py b/bridge_mcp_hydra.py index a5c1eac..f579a20 100644 --- a/bridge_mcp_hydra.py +++ b/bridge_mcp_hydra.py @@ -5,7 +5,7 @@ # "requests>=2.32.3", # ] # /// -# GhydraMCP Bridge for Ghidra HATEOAS API - Optimized for MCP integration +# MCGhidra Bridge for Ghidra HATEOAS API - Optimized for MCP integration # Provides namespaced tools for interacting with Ghidra's reverse engineering capabilities # Features: Cursor-based pagination, grep filtering, session isolation import os @@ -699,7 +699,7 @@ def paginate_response(data: List[Any], query_params: dict, # ================= End Cursor System ================= instructions = """ -GhydraMCP allows interacting with multiple Ghidra SRE instances. Ghidra SRE is a tool for reverse engineering and analyzing binaries, e.g. malware. +MCGhidra allows interacting with multiple Ghidra SRE instances. Ghidra SRE is a tool for reverse engineering and analyzing binaries, e.g. malware. 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. @@ -742,7 +742,7 @@ Use `cursor_list()` to see active cursors. Use `cursor_delete(cursor_id)` to clean up cursors. """ -mcp = FastMCP("GhydraMCP", instructions=instructions) +mcp = FastMCP("MCGhidra", instructions=instructions) ghidra_host = os.environ.get("GHIDRA_HYDRA_HOST", DEFAULT_GHIDRA_HOST) @@ -1162,7 +1162,7 @@ def _discover_instances(port_range, host=None, timeout=0.5) -> dict: timeout=timeout) if response.ok: - # Further validate it's a GhydraMCP instance by checking response format + # Further validate it's a MCGhidra instance by checking response format try: json_data = response.json() if "success" in json_data and json_data["success"] and "result" in json_data: @@ -2200,7 +2200,7 @@ def reverse_engineer_binary_prompt(port: int = None): - Security checks - Data transformation - Remember to use the available GhydraMCP tools: + Remember to use the available MCGhidra tools: - Use functions_list to find functions matching patterns - Use xrefs_list to find cross-references - Use functions_decompile for C-like representations @@ -6862,7 +6862,7 @@ def main(): discovery_thread = threading.Thread( target=periodic_discovery, daemon=True, - name="GhydraMCP-Discovery" + name="MCGhidra-Discovery" ) discovery_thread.start() diff --git a/docker-compose.yml b/docker-compose.yml index 4a6cfe5..ab1c9eb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,9 +1,9 @@ -# GhydraMCP Docker Compose Configuration -# Provides both development and production modes for Ghidra + GhydraMCP +# MCGhidra Docker Compose Configuration +# Provides both development and production modes for Ghidra + MCGhidra # # Usage: -# Development: docker compose up ghydramcp-dev -# Production: docker compose up ghydramcp +# Development: docker compose up mcghidra-dev +# Production: docker compose up mcghidra # # Set MODE in .env file to switch between dev/prod behaviors @@ -11,28 +11,28 @@ services: # ============================================================================= # Production Service - Optimized for stability and security # ============================================================================= - ghydramcp: + mcghidra: build: context: . dockerfile: docker/Dockerfile args: GHIDRA_VERSION: ${GHIDRA_VERSION:-11.4.2} GHIDRA_DATE: ${GHIDRA_DATE:-20250826} - image: ghydramcp:${GHYDRAMCP_VERSION:-latest} - container_name: ${COMPOSE_PROJECT_NAME:-ghydramcp}-server + image: mcghidra:${MCGHIDRAMCP_VERSION:-latest} + container_name: ${COMPOSE_PROJECT_NAME:-mcghidra}-server restart: unless-stopped ports: - - "${GHYDRA_PORT:-8192}:8192" + - "${MCGHIDRA_PORT:-8192}:8192" volumes: # Mount binaries to analyze (read-only in prod) - ${BINARIES_PATH:-./binaries}:/binaries:ro # Persist Ghidra projects between runs - - ghydra-projects:/projects + - mcghidra-projects:/projects environment: - - GHYDRA_MODE=${GHYDRA_MODE:-headless} - - GHYDRA_PORT=8192 - - GHYDRA_MAXMEM=${GHYDRA_MAXMEM:-2G} - - PROJECT_NAME=${PROJECT_NAME:-GhydraMCP} + - MCGHIDRA_MODE=${MCGHIDRA_MODE:-headless} + - MCGHIDRA_PORT=8192 + - MCGHIDRA_MAXMEM=${MCGHIDRA_MAXMEM:-2G} + - PROJECT_NAME=${PROJECT_NAME:-MCGhidra} healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8192/"] interval: 30s @@ -42,7 +42,7 @@ services: deploy: resources: limits: - memory: ${GHYDRA_MAXMEM:-2G} + memory: ${MCGHIDRA_MAXMEM:-2G} profiles: - prod - default @@ -50,17 +50,17 @@ services: # ============================================================================= # Development Service - Hot-reload and debugging friendly # ============================================================================= - ghydramcp-dev: + mcghidra-dev: build: context: . dockerfile: docker/Dockerfile args: GHIDRA_VERSION: ${GHIDRA_VERSION:-11.4.2} GHIDRA_DATE: ${GHIDRA_DATE:-20250826} - image: ghydramcp:dev - container_name: ${COMPOSE_PROJECT_NAME:-ghydramcp}-dev + image: mcghidra:dev + container_name: ${COMPOSE_PROJECT_NAME:-mcghidra}-dev ports: - - "${GHYDRA_PORT:-8192}:8192" + - "${MCGHIDRA_PORT:-8192}:8192" # Additional ports for debugging/multiple instances - "8193:8193" - "8194:8194" @@ -68,15 +68,15 @@ services: # Mount binaries (read-write in dev) - ${BINARIES_PATH:-./binaries}:/binaries:rw # Persist projects - - ghydra-projects-dev:/projects + - mcghidra-projects-dev:/projects # Mount scripts for live editing (development only) - - ./docker/GhydraMCPServer.java:/opt/ghidra/scripts/GhydraMCPServer.java:ro + - ./docker/MCGhidraServer.java:/opt/ghidra/scripts/MCGhidraServer.java:ro - ./docker/entrypoint.sh:/entrypoint.sh:ro environment: - - GHYDRA_MODE=${GHYDRA_MODE:-headless} - - GHYDRA_PORT=8192 - - GHYDRA_MAXMEM=${GHYDRA_MAXMEM:-4G} - - PROJECT_NAME=${PROJECT_NAME:-GhydraMCP-Dev} + - MCGHIDRA_MODE=${MCGHIDRA_MODE:-headless} + - MCGHIDRA_PORT=8192 + - MCGHIDRA_MAXMEM=${MCGHIDRA_MAXMEM:-4G} + - PROJECT_NAME=${PROJECT_NAME:-MCGhidra-Dev} healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8192/"] interval: 15s @@ -89,28 +89,28 @@ services: # ============================================================================= # Shell Service - Interactive debugging container # ============================================================================= - ghydramcp-shell: + mcghidra-shell: build: context: . dockerfile: docker/Dockerfile - image: ghydramcp:${GHYDRAMCP_VERSION:-latest} - container_name: ${COMPOSE_PROJECT_NAME:-ghydramcp}-shell + image: mcghidra:${MCGHIDRAMCP_VERSION:-latest} + container_name: ${COMPOSE_PROJECT_NAME:-mcghidra}-shell stdin_open: true tty: true volumes: - ${BINARIES_PATH:-./binaries}:/binaries:rw - - ghydra-projects-dev:/projects + - mcghidra-projects-dev:/projects environment: - - GHYDRA_MODE=shell + - MCGHIDRA_MODE=shell profiles: - debug volumes: - ghydra-projects: - name: ${COMPOSE_PROJECT_NAME:-ghydramcp}-projects - ghydra-projects-dev: - name: ${COMPOSE_PROJECT_NAME:-ghydramcp}-projects-dev + mcghidra-projects: + name: ${COMPOSE_PROJECT_NAME:-mcghidra}-projects + mcghidra-projects-dev: + name: ${COMPOSE_PROJECT_NAME:-mcghidra}-projects-dev networks: default: - name: ${COMPOSE_PROJECT_NAME:-ghydramcp}-network + name: ${COMPOSE_PROJECT_NAME:-mcghidra}-network diff --git a/docker/Dockerfile b/docker/Dockerfile index 2a9b1db..bfee5c2 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,14 +1,14 @@ -# GhydraMCP Docker Image -# Ghidra + GhydraMCP Plugin pre-installed for headless binary analysis +# MCGhidra Docker Image +# Ghidra + MCGhidra Plugin pre-installed for headless binary analysis # -# Build: docker build -t ghydramcp:latest -f docker/Dockerfile . -# Run: docker run -p 8192:8192 -v /path/to/binaries:/binaries ghydramcp:latest +# Build: docker build -t mcghidra:latest -f docker/Dockerfile . +# Run: docker run -p 8192:8192 -v /path/to/binaries:/binaries mcghidra:latest ARG GHIDRA_VERSION=11.4.2 ARG GHIDRA_DATE=20250826 # ============================================================================= -# Stage 1: Build the GhydraMCP plugin +# Stage 1: Build the MCGhidra plugin # ============================================================================= FROM eclipse-temurin:21-jdk-jammy AS builder @@ -33,7 +33,7 @@ RUN curl -fsSL "https://github.com/NationalSecurityAgency/ghidra/releases/downlo ENV GHIDRA_HOME=/opt/ghidra -# Copy GhydraMCP source and build +# Copy MCGhidra source and build WORKDIR /build # Copy pom.xml first and download dependencies (cached until pom.xml changes) @@ -63,7 +63,7 @@ RUN mvn package -P plugin-only -DskipTests \ -Dghidra.base.jar=${GHIDRA_HOME}/Ghidra/Features/Base/lib/Base.jar # ============================================================================= -# Stage 2: Runtime image with Ghidra + GhydraMCP +# Stage 2: Runtime image with Ghidra + MCGhidra # ============================================================================= # NOTE: Ghidra requires JDK (not JRE) - it checks for javac in LaunchSupport FROM eclipse-temurin:21-jdk-jammy AS runtime @@ -71,9 +71,9 @@ FROM eclipse-temurin:21-jdk-jammy AS runtime ARG GHIDRA_VERSION ARG GHIDRA_DATE -LABEL org.opencontainers.image.title="ghydramcp" \ - org.opencontainers.image.description="Ghidra + GhydraMCP Plugin for AI-assisted reverse engineering" \ - org.opencontainers.image.source="https://github.com/starsong-consulting/GhydraMCP" \ +LABEL org.opencontainers.image.title="mcghidra" \ + org.opencontainers.image.description="Ghidra + MCGhidra Plugin for AI-assisted reverse engineering" \ + org.opencontainers.image.source="https://github.com/starsong-consulting/MCGhidra" \ org.opencontainers.image.licenses="Apache-2.0" # Install runtime dependencies @@ -99,21 +99,21 @@ RUN curl -fsSL "https://github.com/NationalSecurityAgency/ghidra/releases/downlo ENV GHIDRA_HOME=/opt/ghidra ENV PATH="${GHIDRA_HOME}:${PATH}" -# Install the GhydraMCP plugin -COPY --from=builder /build/target/GhydraMCP-*.zip /tmp/ +# Install the MCGhidra plugin +COPY --from=builder /build/target/MCGhidra-*.zip /tmp/ RUN mkdir -p /opt/ghidra/Ghidra/Extensions \ - && unzip -q /tmp/GhydraMCP-*.zip -d /opt/ghidra/Ghidra/Extensions/ \ - && rm /tmp/GhydraMCP-*.zip \ + && unzip -q /tmp/MCGhidra-*.zip -d /opt/ghidra/Ghidra/Extensions/ \ + && rm /tmp/MCGhidra-*.zip \ && chown -R ghidra:ghidra /opt/ghidra/Ghidra/Extensions/ # Create directories for projects and binaries RUN mkdir -p /projects /binaries /home/ghidra/.ghidra \ && chown -R ghidra:ghidra /projects /binaries /home/ghidra -# Copy GhydraMCP Python scripts to user scripts directory +# Copy MCGhidra Python scripts to user scripts directory # Python/Jython scripts don't require OSGi bundle registration - they work without issue RUN mkdir -p /home/ghidra/ghidra_scripts -COPY docker/GhydraMCPServer.py /home/ghidra/ghidra_scripts/ +COPY docker/MCGhidraServer.py /home/ghidra/ghidra_scripts/ COPY docker/ImportRawARM.java /home/ghidra/ghidra_scripts/ # Set proper ownership and permissions @@ -129,16 +129,16 @@ RUN chmod 755 /entrypoint.sh USER ghidra WORKDIR /home/ghidra -# Expose the GhydraMCP HTTP API port (and additional ports for multiple instances) +# Expose the MCGhidra HTTP API port (and additional ports for multiple instances) EXPOSE 8192 8193 8194 8195 # Default environment -ENV GHYDRA_MODE=headless -ENV GHYDRA_PORT=8192 -ENV GHYDRA_MAXMEM=2G +ENV MCGHIDRA_MODE=headless +ENV MCGHIDRA_PORT=8192 +ENV MCGHIDRA_MAXMEM=2G # Healthcheck HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \ - CMD curl -f http://localhost:${GHYDRA_PORT}/ || exit 1 + CMD curl -f http://localhost:${MCGHIDRA_PORT}/ || exit 1 ENTRYPOINT ["/entrypoint.sh"] diff --git a/docker/GhydraMCPServer.py b/docker/GhydraMCPServer.py index 85e4456..47f74da 100644 --- a/docker/GhydraMCPServer.py +++ b/docker/GhydraMCPServer.py @@ -1,10 +1,10 @@ -# GhydraMCPServer.py - Headless Ghidra script for GhydraMCP HTTP API +# MCGhidraServer.py - Headless Ghidra script for MCGhidra HTTP API # Full API parity with the Java plugin implementation. # Python 2 / Jython compatible (no f-strings, no readAllBytes). # -# Usage: analyzeHeadless -import -postScript GhydraMCPServer.py [port] +# Usage: analyzeHeadless -import -postScript MCGhidraServer.py [port] # -#@category GhydraMCP +#@category MCGhidra #@keybinding #@menupath #@toolbar @@ -366,7 +366,7 @@ ROUTES = [ # HTTP Handler # ======================================================================== -class GhydraMCPHandler(HttpHandler): +class MCGhidraHandler(HttpHandler): def __init__(self, program, decompiler): self.program = program @@ -641,7 +641,7 @@ class GhydraMCPHandler(HttpHandler): "success": True, "api_version": API_VERSION, "api_version_string": API_VERSION_STRING, - "message": "GhydraMCP Headless API", + "message": "MCGhidra Headless API", "mode": "headless", } if self.program: @@ -2748,10 +2748,10 @@ class GhydraMCPHandler(HttpHandler): def run_server(port, program, decompiler): """Start the HTTP server with a single catch-all handler.""" server = HttpServer.create(InetSocketAddress(port), 0) - server.createContext("/", GhydraMCPHandler(program, decompiler)) + server.createContext("/", MCGhidraHandler(program, decompiler)) server.setExecutor(Executors.newCachedThreadPool()) server.start() - println("[GhydraMCP] HTTP server started on port %d" % port) + println("[MCGhidra] HTTP server started on port %d" % port) return server @@ -2775,7 +2775,7 @@ def main(): decompiler.openProgram(currentProgram) println("=========================================") - println(" GhydraMCP Headless HTTP Server") + println(" MCGhidra Headless HTTP Server") println("=========================================") println(" API Version: %s (compat: %d)" % (API_VERSION_STRING, API_VERSION)) println(" Port: %d" % port) @@ -2787,7 +2787,7 @@ def main(): server = run_server(port, currentProgram, decompiler) println("") - println("GhydraMCP Server running. Press Ctrl+C to stop.") + println("MCGhidra Server running. Press Ctrl+C to stop.") println("API available at: http://localhost:%d/" % port) # Keep the script running @@ -2796,7 +2796,7 @@ def main(): time.sleep(1) except KeyboardInterrupt: server.stop(0) - println("[GhydraMCP] Server stopped.") + println("[MCGhidra] Server stopped.") # Run diff --git a/docker/ImportRawARM.java b/docker/ImportRawARM.java index 60fdb69..2100ab4 100644 --- a/docker/ImportRawARM.java +++ b/docker/ImportRawARM.java @@ -1,6 +1,6 @@ // Import and analyze raw ARM firmware binary // This script imports a raw binary file with specified ARM processor and load address -// @author GhydraMCP +// @author MCGhidra // @category Binary.Import // @keybinding // @menupath diff --git a/docker/README.md b/docker/README.md index aff637f..08cfbcb 100644 --- a/docker/README.md +++ b/docker/README.md @@ -1,15 +1,15 @@ -# GhydraMCP Docker Setup +# MCGhidra Docker Setup -This directory contains Docker configuration for running GhydraMCP in headless mode. +This directory contains Docker configuration for running MCGhidra in headless mode. ## Quick Start ```bash # Build the image -docker build -t ghydramcp:latest -f docker/Dockerfile . +docker build -t mcghidra:latest -f docker/Dockerfile . # Analyze a binary -docker run -p 8192:8192 -v /path/to/binaries:/binaries ghydramcp /binaries/sample.exe +docker run -p 8192:8192 -v /path/to/binaries:/binaries mcghidra /binaries/sample.exe # Check API health curl http://localhost:8192/ @@ -20,17 +20,17 @@ curl http://localhost:8192/ The Docker container includes: 1. **Ghidra 11.4.2** - Full headless installation -2. **GhydraMCP Extension** - The Java plugin (installed in Extensions/) -3. **GhydraMCPServer.py** - Headless HTTP server (Jython, full API parity) +2. **MCGhidra Extension** - The Java plugin (installed in Extensions/) +3. **MCGhidraServer.py** - Headless HTTP server (Jython, full API parity) ### Why Two HTTP Servers? -The GhydraMCP plugin (`GhydraMCPPlugin.java`) is a full Ghidra GUI plugin that requires: +The MCGhidra plugin (`MCGhidraPlugin.java`) is a full Ghidra GUI plugin that requires: - Ghidra's `PluginTool` framework - `ProgramManager` service for program access - GUI event handling -These GUI services don't exist in headless mode. Instead, the container uses `GhydraMCPServer.py`, a Jython script that: +These GUI services don't exist in headless mode. Instead, the container uses `MCGhidraServer.py`, a Jython script that: - Runs via `analyzeHeadless -postScript` - Has direct access to `currentProgram` from the script context - Provides **full API parity** with the GUI plugin (45 routes) @@ -38,7 +38,7 @@ These GUI services don't exist in headless mode. Instead, the container uses `Gh ### Available Endpoints (Headless Mode) -The headless server implements the complete GhydraMCP HTTP API: +The headless server implements the complete MCGhidra HTTP API: | Category | Endpoints | Description | |----------|-----------|-------------| @@ -65,7 +65,7 @@ Imports a binary, analyzes it, and starts the HTTP API server: ```bash docker run -p 8192:8192 \ -v ./samples:/binaries \ - ghydramcp /binaries/sample.exe + mcghidra /binaries/sample.exe ``` ### Server Mode @@ -74,9 +74,9 @@ Opens an existing project and program: ```bash docker run -p 8192:8192 \ - -e GHYDRA_MODE=server \ + -e MCGHIDRA_MODE=server \ -v ./projects:/projects \ - ghydramcp program_name + mcghidra program_name ``` ### Analyze Mode @@ -85,10 +85,10 @@ Imports and analyzes without starting HTTP server: ```bash docker run \ - -e GHYDRA_MODE=analyze \ + -e MCGHIDRA_MODE=analyze \ -v ./samples:/binaries \ -v ./projects:/projects \ - ghydramcp /binaries/sample.exe + mcghidra /binaries/sample.exe ``` ### Shell Mode @@ -97,19 +97,19 @@ Interactive debugging: ```bash docker run -it \ - -e GHYDRA_MODE=shell \ - ghydramcp + -e MCGHIDRA_MODE=shell \ + mcghidra ``` ## Environment Variables | Variable | Default | Description | |----------|---------|-------------| -| `GHYDRA_MODE` | `headless` | Container mode (headless, server, analyze, shell) | -| `GHYDRA_PORT` | `8192` | HTTP API port | -| `GHYDRA_MAXMEM` | `2G` | JVM heap memory | +| `MCGHIDRA_MODE` | `headless` | Container mode (headless, server, analyze, shell) | +| `MCGHIDRA_PORT` | `8192` | HTTP API port | +| `MCGHIDRA_MAXMEM` | `2G` | JVM heap memory | | `PROJECT_DIR` | `/projects` | Ghidra project directory | -| `PROJECT_NAME` | `GhydraMCP` | Ghidra project name | +| `PROJECT_NAME` | `MCGhidra` | Ghidra project name | ## Docker Compose @@ -117,18 +117,18 @@ Use docker-compose for easier management: ```bash # Development mode (hot-reload scripts) -docker compose --profile dev up ghydramcp-dev +docker compose --profile dev up mcghidra-dev # Production mode -docker compose --profile prod up ghydramcp +docker compose --profile prod up mcghidra # Interactive shell -docker compose --profile debug run --rm ghydramcp-shell +docker compose --profile debug run --rm mcghidra-shell ``` ## MCP Integration -The GhydraMCP Python server includes Docker management tools: +The MCGhidra Python server includes Docker management tools: ```python # Check Docker status @@ -144,10 +144,10 @@ await docker_wait(port=8192, timeout=300) await docker_auto_start(binary_path="/path/to/binary.exe") # Get container logs -await docker_logs("ghydramcp-server") +await docker_logs("mcghidra-server") # Stop container -await docker_stop("ghydramcp-server") +await docker_stop("mcghidra-server") ``` ## Building @@ -157,10 +157,10 @@ await docker_stop("ghydramcp-server") make build # Using Docker directly -docker build -t ghydramcp:latest -f docker/Dockerfile . +docker build -t mcghidra:latest -f docker/Dockerfile . # Build with specific Ghidra version -docker build -t ghydramcp:latest \ +docker build -t mcghidra:latest \ --build-arg GHIDRA_VERSION=11.4.2 \ --build-arg GHIDRA_DATE=20250826 \ -f docker/Dockerfile . @@ -172,21 +172,21 @@ docker build -t ghydramcp:latest \ Analysis takes time. Monitor progress with: ```bash -docker logs -f ghydramcp-server +docker logs -f mcghidra-server ``` ### Port already in use Stop existing containers: ```bash -docker stop $(docker ps -q --filter "name=ghydramcp") +docker stop $(docker ps -q --filter "name=mcghidra") ``` ### Memory issues with large binaries Increase JVM heap: ```bash -docker run -e GHYDRA_MAXMEM=4G -p 8192:8192 ghydramcp /binaries/large.exe +docker run -e MCGHIDRA_MAXMEM=4G -p 8192:8192 mcghidra /binaries/large.exe ``` ### Permission denied on volumes diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index 014b2a2..ba80818 100755 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -1,26 +1,26 @@ #!/bin/bash -# GhydraMCP Docker Entrypoint +# MCGhidra Docker Entrypoint # Starts Ghidra in headless mode with HTTP API server set -e -GHYDRA_MODE=${GHYDRA_MODE:-headless} -GHYDRA_PORT=${GHYDRA_PORT:-8192} -GHYDRA_MAXMEM=${GHYDRA_MAXMEM:-2G} +MCGHIDRA_MODE=${MCGHIDRA_MODE:-headless} +MCGHIDRA_PORT=${MCGHIDRA_PORT:-8192} +MCGHIDRA_MAXMEM=${MCGHIDRA_MAXMEM:-2G} GHIDRA_HOME=${GHIDRA_HOME:-/opt/ghidra} # User scripts directory - Python scripts don't need OSGi bundle registration SCRIPT_DIR=${SCRIPT_DIR:-/home/ghidra/ghidra_scripts} # Project settings PROJECT_DIR=${PROJECT_DIR:-/projects} -PROJECT_NAME=${PROJECT_NAME:-GhydraMCP} +PROJECT_NAME=${PROJECT_NAME:-MCGhidra} echo "==============================================" -echo " GhydraMCP Docker Container" +echo " MCGhidra Docker Container" echo "==============================================" -echo " Mode: ${GHYDRA_MODE}" -echo " Port: ${GHYDRA_PORT}" -echo " Memory: ${GHYDRA_MAXMEM}" +echo " Mode: ${MCGHIDRA_MODE}" +echo " Port: ${MCGHIDRA_PORT}" +echo " Memory: ${MCGHIDRA_MAXMEM}" echo " Project: ${PROJECT_DIR}/${PROJECT_NAME}" echo "==============================================" @@ -28,25 +28,25 @@ echo "==============================================" mkdir -p "${PROJECT_DIR}" # Handle different modes -case "${GHYDRA_MODE}" in +case "${MCGHIDRA_MODE}" in headless) # Headless mode: Import a binary and start HTTP server if [ $# -eq 0 ]; then echo "" - echo "Usage: docker run ghydramcp:latest [binary_path] [options]" + echo "Usage: docker run mcghidra:latest [binary_path] [options]" echo "" echo "Examples:" echo " # Analyze a binary mounted at /binaries/sample.exe" - echo " docker run -p 8192:8192 -v ./samples:/binaries ghydramcp /binaries/sample.exe" + echo " docker run -p 8192:8192 -v ./samples:/binaries mcghidra /binaries/sample.exe" echo "" echo " # With custom project name" - echo " docker run -p 8192:8192 -v ./samples:/binaries -e PROJECT_NAME=malware ghydramcp /binaries/sample.exe" + echo " docker run -p 8192:8192 -v ./samples:/binaries -e PROJECT_NAME=malware mcghidra /binaries/sample.exe" echo "" echo "Environment variables:" - echo " GHYDRA_PORT - HTTP API port (default: 8192)" - echo " GHYDRA_MAXMEM - Max JVM heap (default: 2G)" - echo " PROJECT_NAME - Ghidra project name (default: GhydraMCP)" + echo " MCGHIDRA_PORT - HTTP API port (default: 8192)" + echo " MCGHIDRA_MAXMEM - Max JVM heap (default: 2G)" + echo " PROJECT_NAME - Ghidra project name (default: MCGhidra)" echo " PROJECT_DIR - Project directory (default: /projects)" echo "" echo "Starting in wait mode..." @@ -78,7 +78,7 @@ case "${GHYDRA_MODE}" in -import "${BINARY_PATH}" -max-cpu 2 -scriptPath "${SCRIPT_DIR}" - -postScript "GhydraMCPServer.py" "${GHYDRA_PORT}" + -postScript "MCGhidraServer.py" "${MCGHIDRA_PORT}" ) # Add any extra arguments passed @@ -93,10 +93,10 @@ case "${GHYDRA_MODE}" in server) # Server mode: Open existing project with HTTP server - echo "Starting GhydraMCP server on existing project..." + echo "Starting MCGhidra server on existing project..." if [ $# -eq 0 ]; then - echo "Usage: docker run -e GHYDRA_MODE=server ghydramcp [program_name]" + echo "Usage: docker run -e MCGHIDRA_MODE=server mcghidra [program_name]" echo "" echo " program_name: Name of program in the project to open" exit 1 @@ -110,14 +110,14 @@ case "${GHYDRA_MODE}" in -process "${PROGRAM_NAME}" \ -noanalysis \ -scriptPath "${SCRIPT_DIR}" \ - -postScript "GhydraMCPServer.py" "${GHYDRA_PORT}" \ + -postScript "MCGhidraServer.py" "${MCGHIDRA_PORT}" \ "$@" ;; analyze) # Analyze mode: Import and analyze, then exit (no HTTP server) if [ $# -eq 0 ]; then - echo "Usage: docker run -e GHYDRA_MODE=analyze ghydramcp [binary_path]" + echo "Usage: docker run -e MCGHIDRA_MODE=analyze mcghidra [binary_path]" exit 1 fi @@ -138,7 +138,7 @@ case "${GHYDRA_MODE}" in ;; *) - echo "Unknown mode: ${GHYDRA_MODE}" + echo "Unknown mode: ${MCGHIDRA_MODE}" echo "Valid modes: headless, server, analyze, shell" exit 1 ;; diff --git a/pom.xml b/pom.xml index fd9f039..b1253a3 100644 --- a/pom.xml +++ b/pom.xml @@ -4,11 +4,11 @@ 4.0.0 eu.starsong.ghidra - GhydraMCP + MCGhidra jar dev - GhydraMCP - https://github.com/starsong-consulting/GhydraMCP + MCGhidra + https://github.com/starsong-consulting/MCGhidra UTF-8 @@ -25,7 +25,7 @@ true yyyyMMdd-HHmmss dev - GhydraMCP-${git.commit.id.describe}-${maven.build.timestamp}.zip + MCGhidra-${git.commit.id.describe}-${maven.build.timestamp}.zip @@ -153,16 +153,16 @@ false - GhydraMCP + MCGhidra ${git.commit.id.abbrev}-${maven.build.timestamp} - eu.starsong.ghidra.GhydraMCP - GhydraMCP + eu.starsong.ghidra.MCGhidra + MCGhidra ${git.commit.id.abbrev}-${maven.build.timestamp} LaurieWired, Teal Bauer Expose multiple Ghidra tools to MCP servers with variable management - GhydraMCP + MCGhidra **/App.class @@ -187,7 +187,7 @@ src/assembly/ghidra-extension.xml - GhydraMCP-${git.commit.id.describe}-${maven.build.timestamp} + MCGhidra-${git.commit.id.describe}-${maven.build.timestamp} false @@ -203,7 +203,7 @@ src/assembly/complete-package.xml - GhydraMCP-Complete-${git.commit.id.describe}-${maven.build.timestamp} + MCGhidra-Complete-${git.commit.id.describe}-${maven.build.timestamp} false diff --git a/pyproject.toml b/pyproject.toml index e9604d9..db8bad7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [project] -name = "ghydramcp" +name = "mcghidra" version = "2025.12.3" description = "AI-assisted reverse engineering bridge: a multi-instance Ghidra plugin exposed via a HATEOAS REST API plus an MCP Python bridge for decompilation, analysis & binary manipulation" readme = "README.md" @@ -15,14 +15,14 @@ dependencies = [ ] [project.scripts] -ghydramcp = "ghydramcp:main" +mcghidra = "mcghidra:main" [build-system] requires = ["hatchling"] build-backend = "hatchling.build" [tool.hatch.build.targets.wheel] -packages = ["src/ghydramcp"] +packages = ["src/mcghidra"] [tool.hatch.build] sources = ["src"] diff --git a/run_tests.py b/run_tests.py index ed29763..e8a45f1 100644 --- a/run_tests.py +++ b/run_tests.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 """ -Test runner for GhydraMCP tests. +Test runner for MCGhidra tests. This script runs both the HTTP API tests and the MCP bridge tests. """ import os @@ -21,10 +21,10 @@ def run_http_api_tests(): # Import and run the tests try: - from test_http_api import GhydraMCPHttpApiTests + from test_http_api import MCGhidraHttpApiTests - # Create a test suite with all tests from GhydraMCPHttpApiTests - suite = unittest.TestLoader().loadTestsFromTestCase(GhydraMCPHttpApiTests) + # Create a test suite with all tests from MCGhidraHttpApiTests + suite = unittest.TestLoader().loadTestsFromTestCase(MCGhidraHttpApiTests) # Run the tests result = unittest.TextTestRunner(verbosity=2).run(suite) @@ -118,7 +118,7 @@ def run_comment_tests(): def run_all_tests(): """Run all tests""" - print_header("GhydraMCP Test Suite") + print_header("MCGhidra Test Suite") # Run test suites http_api_success = run_http_api_tests() diff --git a/src/assembly/ghidra-extension.xml b/src/assembly/ghidra-extension.xml index 72e19d2..8141438 100644 --- a/src/assembly/ghidra-extension.xml +++ b/src/assembly/ghidra-extension.xml @@ -11,23 +11,23 @@ false - + src/main/resources extension.properties Module.manifest - GhydraMCP + MCGhidra - + true - GhydraMCP/lib - GhydraMCP.jar + MCGhidra/lib + MCGhidra.jar false diff --git a/src/ghydramcp/__main__.py b/src/ghydramcp/__main__.py deleted file mode 100644 index f71f25e..0000000 --- a/src/ghydramcp/__main__.py +++ /dev/null @@ -1,9 +0,0 @@ -"""GhydraMCP package entry point. - -Allows running with: python -m ghydramcp -""" - -from .server import main - -if __name__ == "__main__": - main() diff --git a/src/main/java/eu/starsong/ghidra/GhydraMCPPlugin.java b/src/main/java/eu/starsong/ghidra/MCGhidraPlugin.java similarity index 95% rename from src/main/java/eu/starsong/ghidra/GhydraMCPPlugin.java rename to src/main/java/eu/starsong/ghidra/MCGhidraPlugin.java index d5c3082..542c2c4 100644 --- a/src/main/java/eu/starsong/ghidra/GhydraMCPPlugin.java +++ b/src/main/java/eu/starsong/ghidra/MCGhidraPlugin.java @@ -39,14 +39,14 @@ import ghidra.util.Msg; status = PluginStatus.RELEASED, packageName = ghidra.app.DeveloperPluginPackage.NAME, category = PluginCategoryNames.ANALYSIS, - shortDescription = "GhydraMCP Plugin for AI Analysis", + shortDescription = "MCGhidra Plugin for AI Analysis", description = "Exposes program data via HATEOAS HTTP API for AI-assisted reverse engineering with MCP (Model Context Protocol).", servicesRequired = { ProgramManager.class } ) -public class GhydraMCPPlugin extends Plugin implements ApplicationLevelPlugin { +public class MCGhidraPlugin extends Plugin implements ApplicationLevelPlugin { // Made public static to be accessible by InstanceEndpoints - public static final Map activeInstances = new ConcurrentHashMap<>(); + public static final Map activeInstances = new ConcurrentHashMap<>(); private static final Object baseInstanceLock = new Object(); private HttpServer server; @@ -54,10 +54,10 @@ public class GhydraMCPPlugin extends Plugin implements ApplicationLevelPlugin { private boolean isBaseInstance = false; /** - * Constructor for GhydraMCP Plugin. + * Constructor for MCGhidra Plugin. * @param tool The Ghidra PluginTool */ - public GhydraMCPPlugin(PluginTool tool) { + public MCGhidraPlugin(PluginTool tool) { super(tool); this.port = findAvailablePort(); @@ -70,8 +70,8 @@ public class GhydraMCPPlugin extends Plugin implements ApplicationLevelPlugin { } } - Msg.info(this, "GhydraMCPPlugin loaded on port " + port); - System.out.println("[GhydraMCP] Plugin loaded on port " + port); + Msg.info(this, "MCGhidraPlugin loaded on port " + port); + System.out.println("[MCGhidra] Plugin loaded on port " + port); try { startServer(); @@ -111,9 +111,9 @@ public class GhydraMCPPlugin extends Plugin implements ApplicationLevelPlugin { new Thread(() -> { server.start(); - Msg.info(this, "GhydraMCP HTTP server started on port " + port); - System.out.println("[GhydraMCP] HTTP server started on port " + port); - }, "GhydraMCP-HTTP-Server").start(); + Msg.info(this, "MCGhidra HTTP server started on port " + port); + System.out.println("[MCGhidra] HTTP server started on port " + port); + }, "MCGhidra-HTTP-Server").start(); } /** @@ -350,7 +350,7 @@ public class GhydraMCPPlugin extends Plugin implements ApplicationLevelPlugin { } Map rootData = new HashMap<>(); - rootData.put("message", "GhydraMCP API " + ApiConstants.API_VERSION); + rootData.put("message", "MCGhidra API " + ApiConstants.API_VERSION); rootData.put("documentation", "See GHIDRA_HTTP_API.md for full API documentation"); rootData.put("isBaseInstance", isBaseInstance); @@ -449,8 +449,8 @@ public class GhydraMCPPlugin extends Plugin implements ApplicationLevelPlugin { public void dispose() { if (server != null) { server.stop(0); // Stop immediately - Msg.info(this, "GhydraMCP HTTP server stopped on port " + port); - System.out.println("[GhydraMCP] HTTP server stopped on port " + port); + Msg.info(this, "MCGhidra HTTP server stopped on port " + port); + System.out.println("[MCGhidra] HTTP server stopped on port " + port); } activeInstances.remove(port); super.dispose(); diff --git a/src/main/java/eu/starsong/ghidra/endpoints/InstanceEndpoints.java b/src/main/java/eu/starsong/ghidra/endpoints/InstanceEndpoints.java index 90818ba..8022fbc 100644 --- a/src/main/java/eu/starsong/ghidra/endpoints/InstanceEndpoints.java +++ b/src/main/java/eu/starsong/ghidra/endpoints/InstanceEndpoints.java @@ -4,7 +4,7 @@ package eu.starsong.ghidra.endpoints; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpServer; import eu.starsong.ghidra.api.ResponseBuilder; - import eu.starsong.ghidra.GhydraMCPPlugin; // Need access to activeInstances + import eu.starsong.ghidra.MCGhidraPlugin; // Need access to activeInstances import ghidra.program.model.listing.Program; import ghidra.util.Msg; @@ -13,16 +13,16 @@ package eu.starsong.ghidra.endpoints; public class InstanceEndpoints extends AbstractEndpoint { - // Need a way to access the static activeInstances map from GhydraMCPPlugin + // Need a way to access the static activeInstances map from MCGhidraPlugin // This is a bit awkward and suggests the instance management might need // a different design, perhaps a dedicated manager class. // For now, we pass the map or use a static accessor if made public. - private final Map activeInstances; + private final Map activeInstances; // Note: Passing currentProgram might be null here if no program is open. // The constructor in AbstractEndpoint handles null program. // Updated constructor to accept port - public InstanceEndpoints(Program program, int port, Map instances) { + public InstanceEndpoints(Program program, int port, Map instances) { super(program, port); // Call super constructor this.activeInstances = instances; } @@ -46,7 +46,7 @@ package eu.starsong.ghidra.endpoints; // Accessing the static map directly - requires it to be accessible // or passed in constructor. - for (Map.Entry entry : activeInstances.entrySet()) { + for (Map.Entry entry : activeInstances.entrySet()) { Map instance = new HashMap<>(); int instancePort = entry.getKey(); instance.put("port", instancePort); diff --git a/src/ghydramcp/__init__.py b/src/mcghidra/__init__.py similarity index 75% rename from src/ghydramcp/__init__.py rename to src/mcghidra/__init__.py index 372aa62..2d5da94 100644 --- a/src/ghydramcp/__init__.py +++ b/src/mcghidra/__init__.py @@ -1,4 +1,4 @@ -"""GhydraMCP - AI-assisted reverse engineering bridge for Ghidra. +"""MCGhidra - AI-assisted reverse engineering bridge for Ghidra. A multi-instance Ghidra plugin exposed via HATEOAS REST API plus an MCP Python bridge for decompilation, analysis & binary manipulation. @@ -6,7 +6,7 @@ Python bridge for decompilation, analysis & binary manipulation. try: from importlib.metadata import version - __version__ = version("ghydramcp") + __version__ = version("mcghidra") except Exception: __version__ = "2025.12.1" diff --git a/src/mcghidra/__main__.py b/src/mcghidra/__main__.py new file mode 100644 index 0000000..a19d481 --- /dev/null +++ b/src/mcghidra/__main__.py @@ -0,0 +1,9 @@ +"""MCGhidra package entry point. + +Allows running with: python -m mcghidra +""" + +from .server import main + +if __name__ == "__main__": + main() diff --git a/src/ghydramcp/config.py b/src/mcghidra/config.py similarity index 83% rename from src/ghydramcp/config.py rename to src/mcghidra/config.py index 4228a13..74baf4f 100644 --- a/src/ghydramcp/config.py +++ b/src/mcghidra/config.py @@ -1,4 +1,4 @@ -"""Configuration management for GhydraMCP. +"""Configuration management for MCGhidra. Handles environment variables, default settings, and runtime configuration. """ @@ -14,18 +14,18 @@ class DockerConfig: """Docker-specific configuration.""" # Docker image settings - image_name: str = "ghydramcp" - image_tag: str = field(default_factory=lambda: os.environ.get("GHYDRAMCP_VERSION", "latest")) + image_name: str = "mcghidra" + image_tag: str = field(default_factory=lambda: os.environ.get("MCGHIDRAMCP_VERSION", "latest")) # Default container settings - default_port: int = field(default_factory=lambda: int(os.environ.get("GHYDRA_PORT", "8192"))) - default_memory: str = field(default_factory=lambda: os.environ.get("GHYDRA_MAXMEM", "2G")) + default_port: int = field(default_factory=lambda: int(os.environ.get("MCGHIDRA_PORT", "8192"))) + default_memory: str = field(default_factory=lambda: os.environ.get("MCGHIDRA_MAXMEM", "2G")) # Project directory (for building) project_dir: Optional[Path] = None # Auto-start settings - auto_start_enabled: bool = field(default_factory=lambda: os.environ.get("GHYDRA_DOCKER_AUTO", "false").lower() == "true") + auto_start_enabled: bool = field(default_factory=lambda: os.environ.get("MCGHIDRA_DOCKER_AUTO", "false").lower() == "true") auto_start_wait: bool = True auto_start_timeout: float = 300.0 @@ -49,8 +49,8 @@ def set_docker_config(config: DockerConfig) -> None: @dataclass -class GhydraConfig: - """Configuration for GhydraMCP server.""" +class MCGhidraConfig: + """Configuration for MCGhidra server.""" # Ghidra connection settings ghidra_host: str = field(default_factory=lambda: os.environ.get("GHIDRA_HOST", "localhost")) @@ -81,12 +81,12 @@ class GhydraConfig: # Feedback collection feedback_enabled: bool = field( - default_factory=lambda: os.environ.get("GHYDRA_FEEDBACK", "true").lower() == "true" + default_factory=lambda: os.environ.get("MCGHIDRA_FEEDBACK", "true").lower() == "true" ) feedback_db_path: str = field( default_factory=lambda: os.environ.get( - "GHYDRA_FEEDBACK_DB", - str(Path.home() / ".ghydramcp" / "feedback.db"), + "MCGHIDRA_FEEDBACK_DB", + str(Path.home() / ".mcghidra" / "feedback.db"), ) ) @@ -114,18 +114,18 @@ class GhydraConfig: # Global configuration instance (can be replaced for testing) -_config: Optional[GhydraConfig] = None +_config: Optional[MCGhidraConfig] = None -def get_config() -> GhydraConfig: +def get_config() -> MCGhidraConfig: """Get the global configuration instance.""" global _config if _config is None: - _config = GhydraConfig() + _config = MCGhidraConfig() return _config -def set_config(config: GhydraConfig) -> None: +def set_config(config: MCGhidraConfig) -> None: """Set the global configuration instance.""" global _config _config = config diff --git a/src/ghydramcp/core/__init__.py b/src/mcghidra/core/__init__.py similarity index 96% rename from src/ghydramcp/core/__init__.py rename to src/mcghidra/core/__init__.py index 72901c8..7299465 100644 --- a/src/ghydramcp/core/__init__.py +++ b/src/mcghidra/core/__init__.py @@ -1,4 +1,4 @@ -"""Core infrastructure for GhydraMCP. +"""Core infrastructure for MCGhidra. Contains HTTP client, pagination, progress reporting, and logging utilities. """ diff --git a/src/ghydramcp/core/filtering.py b/src/mcghidra/core/filtering.py similarity index 99% rename from src/ghydramcp/core/filtering.py rename to src/mcghidra/core/filtering.py index b8ab917..3cb48b2 100644 --- a/src/ghydramcp/core/filtering.py +++ b/src/mcghidra/core/filtering.py @@ -1,4 +1,4 @@ -"""Field projection and response size guard for GhydraMCP. +"""Field projection and response size guard for MCGhidra. Provides jq-style field projection, grep filtering, and token budget enforcement to prevent oversized MCP tool results. diff --git a/src/ghydramcp/core/http_client.py b/src/mcghidra/core/http_client.py similarity index 100% rename from src/ghydramcp/core/http_client.py rename to src/mcghidra/core/http_client.py diff --git a/src/ghydramcp/core/logging.py b/src/mcghidra/core/logging.py similarity index 96% rename from src/ghydramcp/core/logging.py rename to src/mcghidra/core/logging.py index 37c8242..5365a92 100644 --- a/src/ghydramcp/core/logging.py +++ b/src/mcghidra/core/logging.py @@ -11,7 +11,7 @@ if TYPE_CHECKING: from fastmcp import Context # Standard Python logger as fallback -logger = logging.getLogger("ghydramcp") +logger = logging.getLogger("mcghidra") async def log_debug(ctx: Optional["Context"], message: str) -> None: @@ -75,7 +75,7 @@ async def log_error(ctx: Optional["Context"], message: str) -> None: def configure_logging(level: int = logging.INFO) -> None: - """Configure the standard logger for GhydraMCP. + """Configure the standard logger for MCGhidra. Args: level: Logging level (default: INFO) diff --git a/src/ghydramcp/core/pagination.py b/src/mcghidra/core/pagination.py similarity index 100% rename from src/ghydramcp/core/pagination.py rename to src/mcghidra/core/pagination.py diff --git a/src/ghydramcp/core/progress.py b/src/mcghidra/core/progress.py similarity index 100% rename from src/ghydramcp/core/progress.py rename to src/mcghidra/core/progress.py diff --git a/src/ghydramcp/mixins/__init__.py b/src/mcghidra/mixins/__init__.py similarity index 91% rename from src/ghydramcp/mixins/__init__.py rename to src/mcghidra/mixins/__init__.py index a839bcd..e860c53 100644 --- a/src/ghydramcp/mixins/__init__.py +++ b/src/mcghidra/mixins/__init__.py @@ -1,11 +1,11 @@ -"""MCP Mixins for GhydraMCP. +"""MCP Mixins for MCGhidra. Domain-specific mixins that organize tools, resources, and prompts by functionality. Uses FastMCP's contrib.mcp_mixin pattern for clean modular organization. """ from .analysis import AnalysisMixin -from .base import GhydraMixinBase +from .base import MCGhidraMixinBase from .bookmarks import BookmarksMixin from .cursors import CursorsMixin from .data import DataMixin @@ -22,7 +22,7 @@ from .variables import VariablesMixin from .xrefs import XrefsMixin __all__ = [ - "GhydraMixinBase", + "MCGhidraMixinBase", "InstancesMixin", "FunctionsMixin", "DataMixin", diff --git a/src/ghydramcp/mixins/analysis.py b/src/mcghidra/mixins/analysis.py similarity index 99% rename from src/ghydramcp/mixins/analysis.py rename to src/mcghidra/mixins/analysis.py index c65730b..6e96087 100644 --- a/src/ghydramcp/mixins/analysis.py +++ b/src/mcghidra/mixins/analysis.py @@ -1,4 +1,4 @@ -"""Analysis mixin for GhydraMCP. +"""Analysis mixin for MCGhidra. Provides tools for program analysis operations. """ @@ -10,10 +10,10 @@ from fastmcp.contrib.mcp_mixin import mcp_tool from ..config import get_config from ..core.logging import logger -from .base import GhydraMixinBase +from .base import MCGhidraMixinBase -class AnalysisMixin(GhydraMixinBase): +class AnalysisMixin(MCGhidraMixinBase): """Mixin for analysis operations. Provides tools for: diff --git a/src/ghydramcp/mixins/base.py b/src/mcghidra/mixins/base.py similarity index 98% rename from src/ghydramcp/mixins/base.py rename to src/mcghidra/mixins/base.py index 0f465c8..fdd2343 100644 --- a/src/ghydramcp/mixins/base.py +++ b/src/mcghidra/mixins/base.py @@ -1,4 +1,4 @@ -"""Base mixin class for GhydraMCP domain mixins. +"""Base mixin class for MCGhidra domain mixins. Provides shared state and utilities for all domain mixins. """ @@ -23,8 +23,8 @@ from ..core.logging import log_debug, log_error, log_info, log_warning from ..core.pagination import paginate_response -class GhydraMixinBase(MCPMixin): - """Base class for GhydraMCP domain mixins. +class MCGhidraMixinBase(MCPMixin): + """Base class for MCGhidra domain mixins. Provides shared instance state and common utilities. All domain mixins should inherit from this class. diff --git a/src/ghydramcp/mixins/bookmarks.py b/src/mcghidra/mixins/bookmarks.py similarity index 97% rename from src/ghydramcp/mixins/bookmarks.py rename to src/mcghidra/mixins/bookmarks.py index aece74b..935500c 100644 --- a/src/ghydramcp/mixins/bookmarks.py +++ b/src/mcghidra/mixins/bookmarks.py @@ -1,4 +1,4 @@ -"""Bookmarks mixin for GhydraMCP. +"""Bookmarks mixin for MCGhidra. Provides tools for managing Ghidra bookmarks (annotations at addresses). """ @@ -9,10 +9,10 @@ from fastmcp import Context from fastmcp.contrib.mcp_mixin import mcp_tool from ..config import get_config -from .base import GhydraMixinBase +from .base import MCGhidraMixinBase -class BookmarksMixin(GhydraMixinBase): +class BookmarksMixin(MCGhidraMixinBase): """Mixin for bookmark operations. Provides tools for: diff --git a/src/ghydramcp/mixins/cursors.py b/src/mcghidra/mixins/cursors.py similarity index 97% rename from src/ghydramcp/mixins/cursors.py rename to src/mcghidra/mixins/cursors.py index 0f4324e..0442e4f 100644 --- a/src/ghydramcp/mixins/cursors.py +++ b/src/mcghidra/mixins/cursors.py @@ -1,4 +1,4 @@ -"""Cursor management mixin for GhydraMCP. +"""Cursor management mixin for MCGhidra. Provides tools for managing pagination cursors. """ @@ -9,10 +9,10 @@ from fastmcp import Context from fastmcp.contrib.mcp_mixin import mcp_tool from ..core.pagination import get_cursor_manager -from .base import GhydraMixinBase +from .base import MCGhidraMixinBase -class CursorsMixin(GhydraMixinBase): +class CursorsMixin(MCGhidraMixinBase): """Mixin for cursor management. Provides tools for navigating paginated results. diff --git a/src/ghydramcp/mixins/data.py b/src/mcghidra/mixins/data.py similarity index 99% rename from src/ghydramcp/mixins/data.py rename to src/mcghidra/mixins/data.py index 7c43c5c..25739fc 100644 --- a/src/ghydramcp/mixins/data.py +++ b/src/mcghidra/mixins/data.py @@ -1,4 +1,4 @@ -"""Data mixin for GhydraMCP. +"""Data mixin for MCGhidra. Provides tools for data items and strings operations. """ @@ -9,10 +9,10 @@ from fastmcp import Context from fastmcp.contrib.mcp_mixin import mcp_resource, mcp_tool from ..config import get_config -from .base import GhydraMixinBase +from .base import MCGhidraMixinBase -class DataMixin(GhydraMixinBase): +class DataMixin(MCGhidraMixinBase): """Mixin for data operations. Provides tools for: diff --git a/src/ghydramcp/mixins/datatypes.py b/src/mcghidra/mixins/datatypes.py similarity index 98% rename from src/ghydramcp/mixins/datatypes.py rename to src/mcghidra/mixins/datatypes.py index 79c61d8..915603f 100644 --- a/src/ghydramcp/mixins/datatypes.py +++ b/src/mcghidra/mixins/datatypes.py @@ -1,4 +1,4 @@ -"""Data types mixin for GhydraMCP. +"""Data types mixin for MCGhidra. Provides tools for managing enum and typedef data types. """ @@ -9,10 +9,10 @@ from fastmcp import Context from fastmcp.contrib.mcp_mixin import mcp_tool from ..config import get_config -from .base import GhydraMixinBase +from .base import MCGhidraMixinBase -class DataTypesMixin(GhydraMixinBase): +class DataTypesMixin(MCGhidraMixinBase): """Mixin for enum and typedef data type operations. Provides tools for: diff --git a/src/ghydramcp/mixins/docker.py b/src/mcghidra/mixins/docker.py similarity index 93% rename from src/ghydramcp/mixins/docker.py rename to src/mcghidra/mixins/docker.py index 3f56a36..df7d940 100644 --- a/src/ghydramcp/mixins/docker.py +++ b/src/mcghidra/mixins/docker.py @@ -1,4 +1,4 @@ -"""Docker management mixin for GhydraMCP. +"""Docker management mixin for MCGhidra. Provides tools for managing Ghidra Docker containers programmatically. Allows the MCP server to automatically start containers when Ghidra isn't available. @@ -21,17 +21,17 @@ from typing import Any, Dict, List, Optional from fastmcp import Context from fastmcp.contrib.mcp_mixin import mcp_tool -from ghydramcp.core.logging import logger -from ghydramcp.mixins.base import GhydraMixinBase +from mcghidra.core.logging import logger +from mcghidra.mixins.base import MCGhidraMixinBase # Port pool configuration (32 ports should handle many concurrent sessions) PORT_POOL_START = 8192 PORT_POOL_END = 8223 -PORT_LOCK_DIR = Path("/tmp/ghydramcp-ports") +PORT_LOCK_DIR = Path("/tmp/mcghidra-ports") class PortPool: - """Manages a pool of ports for GhydraMCP containers. + """Manages a pool of ports for MCGhidra containers. Uses file-based locking to coordinate port allocation across multiple processes. Each allocated port gets a lock file that persists until @@ -209,11 +209,11 @@ class PortPool: return cleaned -class DockerMixin(GhydraMixinBase): - """Docker container management for GhydraMCP. +class DockerMixin(MCGhidraMixinBase): + """Docker container management for MCGhidra. Provides tools to start, stop, and manage Ghidra containers - with the GhydraMCP plugin pre-installed. + with the MCGhidra plugin pre-installed. Supports multi-process environments with: - Dynamic port allocation from a pool (8192-8223) @@ -231,8 +231,8 @@ class DockerMixin(GhydraMixinBase): # Track containers started by this session _session_containers: Dict[str, Dict[str, Any]] = {} - # Label prefix for GhydraMCP containers - LABEL_PREFIX = "com.ghydramcp" + # Label prefix for MCGhidra containers + LABEL_PREFIX = "com.mcghidra" def __init__(self): """Initialize Docker mixin with session isolation.""" @@ -252,7 +252,7 @@ class DockerMixin(GhydraMixinBase): def port_pool(self) -> PortPool: """Get the port pool, creating it on first access. - Lazy initialization avoids creating /tmp/ghydramcp-ports + Lazy initialization avoids creating /tmp/mcghidra-ports until Docker tools are actually used. """ if self._port_pool is None: @@ -331,7 +331,7 @@ class DockerMixin(GhydraMixinBase): env = os.environ.copy() if project_dir: - env["COMPOSE_PROJECT_NAME"] = "ghydramcp" + env["COMPOSE_PROJECT_NAME"] = "mcghidra" return subprocess.run( cmd, @@ -345,7 +345,7 @@ class DockerMixin(GhydraMixinBase): def _generate_container_name(self, binary_name: str) -> str: """Generate a unique container name for this session. - Format: ghydramcp-{session_id}-{binary_stem} + Format: mcghidra-{session_id}-{binary_stem} Args: binary_name: Name of the binary being analyzed @@ -356,7 +356,7 @@ class DockerMixin(GhydraMixinBase): # Clean binary name for container naming stem = Path(binary_name).stem.lower() clean_name = "".join(c if c.isalnum() else "-" for c in stem)[:20] - return f"ghydramcp-{self.session_id}-{clean_name}" + return f"mcghidra-{self.session_id}-{clean_name}" def _get_container_labels(self, binary_path: str, port: int) -> Dict[str, str]: """Generate Docker labels for a container. @@ -383,7 +383,7 @@ class DockerMixin(GhydraMixinBase): label_filter: Optional[str] = None, session_only: bool = False, ) -> List[Dict[str, Any]]: - """Find GhydraMCP containers by label. + """Find MCGhidra containers by label. Args: label_filter: Additional label filter (e.g., "port=8192") @@ -431,19 +431,19 @@ class DockerMixin(GhydraMixinBase): @mcp_tool( name="docker_status", - description="Check Docker availability and running GhydraMCP containers", + description="Check Docker availability and running MCGhidra containers", ) async def docker_status(self, ctx: Optional[Context] = None) -> Dict[str, Any]: - """Check Docker status and list running GhydraMCP containers. + """Check Docker status and list running MCGhidra containers. Returns: Status information including: - docker_available: Whether Docker is installed - docker_running: Whether Docker daemon is running - session_id: This MCP instance's session ID - - containers: List of GhydraMCP containers with their status + - containers: List of MCGhidra containers with their status - port_pool: Port allocation status - - images: Available GhydraMCP images + - images: Available MCGhidra images """ result = { "docker_available": False, @@ -479,7 +479,7 @@ class DockerMixin(GhydraMixinBase): except subprocess.CalledProcessError: pass - # List all GhydraMCP containers (from any session) + # List all MCGhidra containers (from any session) result["containers"] = await self._find_containers_by_label() # List containers from this session only @@ -495,7 +495,7 @@ class DockerMixin(GhydraMixinBase): "ps", "-a", "--filter", - "name=ghydramcp", + "name=mcghidra", "--format", "{{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}", ] @@ -517,13 +517,13 @@ class DockerMixin(GhydraMixinBase): except subprocess.CalledProcessError: pass - # List GhydraMCP images + # List MCGhidra images try: images_result = await self._run_docker_cmd( [ "images", "--filter", - "reference=ghydramcp*", + "reference=mcghidra*", "--format", "{{.Repository}}:{{.Tag}}\t{{.Size}}\t{{.CreatedSince}}", ] @@ -546,7 +546,7 @@ class DockerMixin(GhydraMixinBase): @mcp_tool( name="docker_start", - description="Start a GhydraMCP Docker container to analyze a binary (auto-assigns port from pool)", + description="Start a MCGhidra Docker container to analyze a binary (auto-assigns port from pool)", ) async def docker_start( self, @@ -555,9 +555,9 @@ class DockerMixin(GhydraMixinBase): name: Optional[str] = None, ctx: Optional[Context] = None, ) -> Dict[str, Any]: - """Start a GhydraMCP Docker container for binary analysis. + """Start a MCGhidra Docker container for binary analysis. - This creates a new Ghidra instance in Docker with the GhydraMCP + This creates a new Ghidra instance in Docker with the MCGhidra plugin pre-installed. The binary will be imported and analyzed, then the HTTP API will be available. @@ -635,9 +635,9 @@ class DockerMixin(GhydraMixinBase): "-v", f"{binary_file.parent}:/binaries:ro", "-e", - f"GHYDRA_MAXMEM={memory}", + f"MCGHIDRA_MAXMEM={memory}", *label_args, - "ghydramcp:latest", + "mcghidra:latest", f"/binaries/{binary_file.name}", ] ) @@ -673,12 +673,12 @@ class DockerMixin(GhydraMixinBase): @mcp_tool( name="docker_stop", - description="Stop a running GhydraMCP Docker container", + description="Stop a running MCGhidra Docker container", ) async def docker_stop( self, name_or_id: str, remove: bool = True, ctx: Optional[Context] = None ) -> Dict[str, Any]: - """Stop a GhydraMCP Docker container. + """Stop a MCGhidra Docker container. For safety, this will only stop containers that belong to the current MCP session. Attempting to stop another session's container will fail @@ -752,7 +752,7 @@ class DockerMixin(GhydraMixinBase): @mcp_tool( name="docker_logs", - description="Get logs from a GhydraMCP Docker container", + description="Get logs from a MCGhidra Docker container", ) async def docker_logs( self, @@ -761,7 +761,7 @@ class DockerMixin(GhydraMixinBase): follow: bool = False, ctx: Optional[Context] = None, ) -> Dict[str, Any]: - """Get logs from a GhydraMCP container. + """Get logs from a MCGhidra container. Args: name_or_id: Container name or ID @@ -792,7 +792,7 @@ class DockerMixin(GhydraMixinBase): @mcp_tool( name="docker_build", - description="Build the GhydraMCP Docker image from source", + description="Build the MCGhidra Docker image from source", ) async def docker_build( self, @@ -801,12 +801,12 @@ class DockerMixin(GhydraMixinBase): project_dir: Optional[str] = None, ctx: Optional[Context] = None, ) -> Dict[str, Any]: - """Build the GhydraMCP Docker image. + """Build the MCGhidra Docker image. Args: tag: Image tag (default: 'latest') no_cache: Build without using cache - project_dir: Path to GhydraMCP project (auto-detected if not specified) + project_dir: Path to MCGhidra project (auto-detected if not specified) Returns: Build status @@ -824,7 +824,7 @@ class DockerMixin(GhydraMixinBase): proj_path = module_dir else: return { - "error": "Could not find GhydraMCP project directory. Please specify project_dir." + "error": "Could not find MCGhidra project directory. Please specify project_dir." } dockerfile = proj_path / "docker" / "Dockerfile" @@ -835,7 +835,7 @@ class DockerMixin(GhydraMixinBase): args = [ "build", "-t", - f"ghydramcp:{tag}", + f"mcghidra:{tag}", "-f", str(dockerfile), ] @@ -848,8 +848,8 @@ class DockerMixin(GhydraMixinBase): return { "success": True, - "image": f"ghydramcp:{tag}", - "message": f"Successfully built ghydramcp:{tag}", + "image": f"mcghidra:{tag}", + "message": f"Successfully built mcghidra:{tag}", "output": result.stdout[-2000:] if len(result.stdout) > 2000 else result.stdout, } @@ -899,12 +899,12 @@ class DockerMixin(GhydraMixinBase): @mcp_tool( name="docker_health", - description="Check if a GhydraMCP container's API is responding", + description="Check if a MCGhidra container's API is responding", ) async def docker_health( self, port: Optional[int] = None, timeout: float = 5.0, ctx: Optional[Context] = None ) -> Dict[str, Any]: - """Check if a GhydraMCP container's API is healthy. + """Check if a MCGhidra container's API is healthy. Args: port: API port to check (uses current instance if not specified) @@ -920,7 +920,7 @@ class DockerMixin(GhydraMixinBase): @mcp_tool( name="docker_auto_start", - description="Automatically start a GhydraMCP container with dynamic port allocation", + description="Automatically start a MCGhidra container with dynamic port allocation", ) async def docker_auto_start( self, @@ -978,10 +978,10 @@ class DockerMixin(GhydraMixinBase): } # Check if we have the image - if not any("ghydramcp" in img.get("name", "") for img in status.get("images", [])): + if not any("mcghidra" in img.get("name", "") for img in status.get("images", [])): return { "error": ( - "GhydraMCP Docker image not found. " + "MCGhidra Docker image not found. " "Build it with docker_build() or 'make build' first." ) } @@ -1017,14 +1017,14 @@ class DockerMixin(GhydraMixinBase): dry_run: bool = False, ctx: Optional[Context] = None, ) -> Dict[str, Any]: - """Clean up orphaned GhydraMCP containers and stale port locks. + """Clean up orphaned MCGhidra containers and stale port locks. This helps recover from crashed processes that left containers or port locks behind. By default, only cleans containers from the current session to prevent accidentally removing another agent's work. Set session_only=False - (with caution) to clean all GhydraMCP containers. + (with caution) to clean all MCGhidra containers. Args: session_only: Only clean up containers from this session (default: True for safety) diff --git a/src/ghydramcp/mixins/functions.py b/src/mcghidra/mixins/functions.py similarity index 99% rename from src/ghydramcp/mixins/functions.py rename to src/mcghidra/mixins/functions.py index 94914dd..744d714 100644 --- a/src/ghydramcp/mixins/functions.py +++ b/src/mcghidra/mixins/functions.py @@ -1,4 +1,4 @@ -"""Functions mixin for GhydraMCP. +"""Functions mixin for MCGhidra. Provides tools for function analysis, decompilation, and manipulation. """ @@ -10,10 +10,10 @@ from fastmcp import Context from fastmcp.contrib.mcp_mixin import mcp_resource, mcp_tool from ..config import get_config -from .base import GhydraMixinBase +from .base import MCGhidraMixinBase -class FunctionsMixin(GhydraMixinBase): +class FunctionsMixin(MCGhidraMixinBase): """Mixin for function operations. Provides tools for: diff --git a/src/ghydramcp/mixins/instances.py b/src/mcghidra/mixins/instances.py similarity index 98% rename from src/ghydramcp/mixins/instances.py rename to src/mcghidra/mixins/instances.py index 4b93269..af51b99 100644 --- a/src/ghydramcp/mixins/instances.py +++ b/src/mcghidra/mixins/instances.py @@ -1,4 +1,4 @@ -"""Instance management mixin for GhydraMCP. +"""Instance management mixin for MCGhidra. Provides tools for discovering, registering, and managing Ghidra instances. """ @@ -9,10 +9,10 @@ from typing import Any, Dict, Optional from fastmcp.contrib.mcp_mixin import mcp_resource, mcp_tool from ..config import get_config -from .base import GhydraMixinBase +from .base import MCGhidraMixinBase -class InstancesMixin(GhydraMixinBase): +class InstancesMixin(MCGhidraMixinBase): """Mixin for Ghidra instance management. Provides tools for: diff --git a/src/ghydramcp/mixins/memory.py b/src/mcghidra/mixins/memory.py similarity index 97% rename from src/ghydramcp/mixins/memory.py rename to src/mcghidra/mixins/memory.py index eaa3688..491c7e1 100644 --- a/src/ghydramcp/mixins/memory.py +++ b/src/mcghidra/mixins/memory.py @@ -1,4 +1,4 @@ -"""Memory mixin for GhydraMCP. +"""Memory mixin for MCGhidra. Provides tools for memory read/write operations. """ @@ -7,10 +7,10 @@ from typing import Any, Dict, Optional from fastmcp.contrib.mcp_mixin import mcp_tool -from .base import GhydraMixinBase +from .base import MCGhidraMixinBase -class MemoryMixin(GhydraMixinBase): +class MemoryMixin(MCGhidraMixinBase): """Mixin for memory operations. Provides tools for: diff --git a/src/ghydramcp/mixins/namespaces.py b/src/mcghidra/mixins/namespaces.py similarity index 98% rename from src/ghydramcp/mixins/namespaces.py rename to src/mcghidra/mixins/namespaces.py index a298ae1..8188953 100644 --- a/src/ghydramcp/mixins/namespaces.py +++ b/src/mcghidra/mixins/namespaces.py @@ -1,4 +1,4 @@ -"""Namespaces mixin for GhydraMCP. +"""Namespaces mixin for MCGhidra. Provides tools for querying namespaces and class definitions. """ @@ -9,10 +9,10 @@ from fastmcp import Context from fastmcp.contrib.mcp_mixin import mcp_resource, mcp_tool from ..config import get_config -from .base import GhydraMixinBase +from .base import MCGhidraMixinBase -class NamespacesMixin(GhydraMixinBase): +class NamespacesMixin(MCGhidraMixinBase): """Mixin for namespace and class operations. Provides tools for: diff --git a/src/ghydramcp/mixins/segments.py b/src/mcghidra/mixins/segments.py similarity index 97% rename from src/ghydramcp/mixins/segments.py rename to src/mcghidra/mixins/segments.py index 9082cb6..5d49c37 100644 --- a/src/ghydramcp/mixins/segments.py +++ b/src/mcghidra/mixins/segments.py @@ -1,4 +1,4 @@ -"""Segments mixin for GhydraMCP. +"""Segments mixin for MCGhidra. Provides tools for querying memory segments (sections) and their permissions. """ @@ -9,10 +9,10 @@ from fastmcp import Context from fastmcp.contrib.mcp_mixin import mcp_resource, mcp_tool from ..config import get_config -from .base import GhydraMixinBase +from .base import MCGhidraMixinBase -class SegmentsMixin(GhydraMixinBase): +class SegmentsMixin(MCGhidraMixinBase): """Mixin for memory segment operations. Provides tools for: diff --git a/src/ghydramcp/mixins/structs.py b/src/mcghidra/mixins/structs.py similarity index 99% rename from src/ghydramcp/mixins/structs.py rename to src/mcghidra/mixins/structs.py index 6a01a87..169b10d 100644 --- a/src/ghydramcp/mixins/structs.py +++ b/src/mcghidra/mixins/structs.py @@ -1,4 +1,4 @@ -"""Structs mixin for GhydraMCP. +"""Structs mixin for MCGhidra. Provides tools for struct data type operations. """ @@ -9,10 +9,10 @@ from fastmcp import Context from fastmcp.contrib.mcp_mixin import mcp_resource, mcp_tool from ..config import get_config -from .base import GhydraMixinBase +from .base import MCGhidraMixinBase -class StructsMixin(GhydraMixinBase): +class StructsMixin(MCGhidraMixinBase): """Mixin for struct operations. Provides tools for: diff --git a/src/ghydramcp/mixins/symbols.py b/src/mcghidra/mixins/symbols.py similarity index 99% rename from src/ghydramcp/mixins/symbols.py rename to src/mcghidra/mixins/symbols.py index 4f1ee0a..e7f0c19 100644 --- a/src/ghydramcp/mixins/symbols.py +++ b/src/mcghidra/mixins/symbols.py @@ -1,4 +1,4 @@ -"""Symbols mixin for GhydraMCP. +"""Symbols mixin for MCGhidra. Provides tools for symbol table operations including labels, imports, and exports. """ @@ -9,10 +9,10 @@ from fastmcp import Context from fastmcp.contrib.mcp_mixin import mcp_resource, mcp_tool from ..config import get_config -from .base import GhydraMixinBase +from .base import MCGhidraMixinBase -class SymbolsMixin(GhydraMixinBase): +class SymbolsMixin(MCGhidraMixinBase): """Mixin for symbol table operations. Provides tools for: diff --git a/src/ghydramcp/mixins/variables.py b/src/mcghidra/mixins/variables.py similarity index 98% rename from src/ghydramcp/mixins/variables.py rename to src/mcghidra/mixins/variables.py index a8c7707..cae27be 100644 --- a/src/ghydramcp/mixins/variables.py +++ b/src/mcghidra/mixins/variables.py @@ -1,4 +1,4 @@ -"""Variables mixin for GhydraMCP. +"""Variables mixin for MCGhidra. Provides tools for querying global and function-local variables. """ @@ -9,10 +9,10 @@ from fastmcp import Context from fastmcp.contrib.mcp_mixin import mcp_resource, mcp_tool from ..config import get_config -from .base import GhydraMixinBase +from .base import MCGhidraMixinBase -class VariablesMixin(GhydraMixinBase): +class VariablesMixin(MCGhidraMixinBase): """Mixin for variable operations. Provides tools for: diff --git a/src/ghydramcp/mixins/xrefs.py b/src/mcghidra/mixins/xrefs.py similarity index 98% rename from src/ghydramcp/mixins/xrefs.py rename to src/mcghidra/mixins/xrefs.py index 5d009a3..98cdc07 100644 --- a/src/ghydramcp/mixins/xrefs.py +++ b/src/mcghidra/mixins/xrefs.py @@ -1,4 +1,4 @@ -"""Cross-references mixin for GhydraMCP. +"""Cross-references mixin for MCGhidra. Provides tools for cross-reference (xref) operations. """ @@ -9,10 +9,10 @@ from fastmcp import Context from fastmcp.contrib.mcp_mixin import mcp_resource, mcp_tool from ..config import get_config -from .base import GhydraMixinBase +from .base import MCGhidraMixinBase -class XrefsMixin(GhydraMixinBase): +class XrefsMixin(MCGhidraMixinBase): """Mixin for cross-reference operations. Provides tools for: diff --git a/src/ghydramcp/server.py b/src/mcghidra/server.py similarity index 85% rename from src/ghydramcp/server.py rename to src/mcghidra/server.py index c14391c..6403844 100644 --- a/src/ghydramcp/server.py +++ b/src/mcghidra/server.py @@ -1,4 +1,4 @@ -"""GhydraMCP Server - FastMCP server composing all mixins. +"""MCGhidra Server - FastMCP server composing all mixins. This module creates and configures the FastMCP server by composing all domain-specific mixins into a single MCP server. @@ -13,7 +13,7 @@ from typing import Optional from fastmcp import FastMCP -from .config import GhydraConfig, get_config, set_config +from .config import MCGhidraConfig, get_config, set_config from .core.logging import configure_logging from .mixins import ( AnalysisMixin, @@ -35,10 +35,10 @@ from .mixins import ( def create_server( - name: str = "GhydraMCP", - config: Optional[GhydraConfig] = None, + name: str = "MCGhidra", + config: Optional[MCGhidraConfig] = None, ) -> FastMCP: - """Create and configure the GhydraMCP server. + """Create and configure the MCGhidra server. Args: name: Server name @@ -114,7 +114,7 @@ def _periodic_discovery(interval: int = 30): """ import requests as _requests - from .mixins.base import GhydraMixinBase + from .mixins.base import MCGhidraMixinBase config = get_config() @@ -133,9 +133,9 @@ def _periodic_discovery(interval: int = 30): if resp.ok: response = resp.json() if response.get("success", False): - with GhydraMixinBase._instances_lock: - if port not in GhydraMixinBase._instances: - GhydraMixinBase._instances[port] = { + with MCGhidraMixinBase._instances_lock: + if port not in MCGhidraMixinBase._instances: + MCGhidraMixinBase._instances[port] = { "url": url.rstrip("/"), "project": response.get("project", ""), "file": response.get("file", ""), @@ -149,27 +149,27 @@ def _periodic_discovery(interval: int = 30): def _handle_sigint(signum, frame): """Handle SIGINT gracefully.""" - print("\nShutting down GhydraMCP...", file=sys.stderr) + print("\nShutting down MCGhidra...", file=sys.stderr) sys.exit(0) def main(): - """Main entry point for the GhydraMCP server.""" + """Main entry point for the MCGhidra server.""" import logging import os import shutil - # Configure logging early (DEBUG if GHYDRAMCP_DEBUG is set) - log_level = logging.DEBUG if os.environ.get("GHYDRAMCP_DEBUG") else logging.INFO + # Configure logging early (DEBUG if MCGHIDRAMCP_DEBUG is set) + log_level = logging.DEBUG if os.environ.get("MCGHIDRAMCP_DEBUG") else logging.INFO configure_logging(log_level) try: from importlib.metadata import version - package_version = version("ghydramcp") + package_version = version("mcghidra") except Exception: package_version = "2025.12.1" - print(f"🔬 GhydraMCP v{package_version}", file=sys.stderr) + print(f"🔬 MCGhidra v{package_version}", file=sys.stderr) print(" AI-assisted reverse engineering bridge for Ghidra", file=sys.stderr) # Check Docker availability @@ -191,15 +191,15 @@ def main(): print(f" Discovering Ghidra instances on {config.ghidra_host}...", file=sys.stderr) from .core.http_client import safe_get - from .mixins.base import GhydraMixinBase + from .mixins.base import MCGhidraMixinBase found = 0 for port in config.quick_discovery_range: try: response = safe_get(port, "") if response.get("success", False): - with GhydraMixinBase._instances_lock: - GhydraMixinBase._instances[port] = { + with MCGhidraMixinBase._instances_lock: + MCGhidraMixinBase._instances[port] = { "url": f"http://{config.ghidra_host}:{port}", "project": response.get("project", ""), "file": response.get("file", ""), @@ -219,7 +219,7 @@ def main(): discovery_thread = threading.Thread( target=_periodic_discovery, daemon=True, - name="GhydraMCP-Discovery", + name="MCGhidra-Discovery", ) discovery_thread.start() diff --git a/test_comments.py b/test_comments.py index f38722e..043348f 100755 --- a/test_comments.py +++ b/test_comments.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 """ -Test script for the comment functionality in GhydraMCP. +Test script for the comment functionality in MCGhidra. Tests both HTTP API and MCP bridge interfaces for setting and retrieving different types of comments in Ghidra, including plate, pre, post, EOL, diff --git a/test_data_operations.py b/test_data_operations.py index 9fe8d51..bbc3df4 100755 --- a/test_data_operations.py +++ b/test_data_operations.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 """ -Comprehensive test script for data operations in GhydraMCP. +Comprehensive test script for data operations in MCGhidra. This script tests all data-related operations including: 1. Creating data items with different types diff --git a/test_http_api.py b/test_http_api.py index 62511cb..bd23412 100644 --- a/test_http_api.py +++ b/test_http_api.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 """ -Test script for the GhydraMCP HTTP API. +Test script for the MCGhidra HTTP API. This script tests the HTTP endpoints of the Java plugin. """ import json @@ -14,9 +14,9 @@ import sys DEFAULT_PORT = 8192 # Get host from environment variable or default to localhost -GHYDRAMCP_TEST_HOST = os.getenv('GHYDRAMCP_TEST_HOST') -if GHYDRAMCP_TEST_HOST and GHYDRAMCP_TEST_HOST.strip(): - BASE_URL = f"http://{GHYDRAMCP_TEST_HOST}:{DEFAULT_PORT}" +MCGHIDRA_TEST_HOST = os.getenv('MCGHIDRA_TEST_HOST') +if MCGHIDRA_TEST_HOST and MCGHIDRA_TEST_HOST.strip(): + BASE_URL = f"http://{MCGHIDRA_TEST_HOST}:{DEFAULT_PORT}" else: BASE_URL = f"http://localhost:{DEFAULT_PORT}" @@ -48,8 +48,8 @@ Endpoints requiring HATEOAS updates: This test suite enforces strict HATEOAS compliance with no backward compatibility. """ -class GhydraMCPHttpApiTests(unittest.TestCase): - """Test cases for the GhydraMCP HTTP API""" +class MCGhidraHttpApiTests(unittest.TestCase): + """Test cases for the MCGhidra HTTP API""" def assertStandardSuccessResponse(self, data): """Helper to assert the standard success response structure for HATEOAS API.""" diff --git a/test_mcp_client.py b/test_mcp_client.py index f17c61c..9933740 100644 --- a/test_mcp_client.py +++ b/test_mcp_client.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 """ -Test script for the GhydraMCP bridge using the MCP client. +Test script for the MCGhidra bridge using the MCP client. This script tests the bridge by sending MCP requests and handling responses. """ import json @@ -14,8 +14,8 @@ from mcp.client.session import ClientSession from mcp.client.stdio import StdioServerParameters, stdio_client # Get host and port from environment variables or use defaults -GHYDRAMCP_TEST_HOST = os.getenv('GHYDRAMCP_TEST_HOST', 'localhost') -GHYDRAMCP_TEST_PORT = int(os.getenv('GHYDRAMCP_TEST_PORT', '8192')) +MCGHIDRA_TEST_HOST = os.getenv('MCGHIDRA_TEST_HOST', 'localhost') +MCGHIDRA_TEST_PORT = int(os.getenv('MCGHIDRA_TEST_PORT', '8192')) # Set up logging logging.basicConfig(level=logging.INFO) @@ -95,8 +95,8 @@ async def test_bridge(): logger.info(f"List instances result: {list_instances_result}") # Set the current instance to use for subsequent calls - logger.info(f"Setting current instance to port {GHYDRAMCP_TEST_PORT}...") - use_instance_result = await session.call_tool("instances_use", arguments={"port": GHYDRAMCP_TEST_PORT}) + logger.info(f"Setting current instance to port {MCGHIDRA_TEST_PORT}...") + use_instance_result = await session.call_tool("instances_use", arguments={"port": MCGHIDRA_TEST_PORT}) logger.info(f"Use instance result: {use_instance_result}") # Call the functions_list tool (no port needed now) diff --git a/uv.lock b/uv.lock index fc17992..447a9a3 100644 --- a/uv.lock +++ b/uv.lock @@ -414,25 +414,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/db/ee/327a3f6c7ac5cde56c7c9449dbc6c0ab78b15c06a51ad5645ab880240120/fastmcp_feedback-2026.1.12.1-py3-none-any.whl", hash = "sha256:6a3dec71f3d3eae4eb0102eb0a86aa7853fb0419fb506a5a13d17deaf842c53c", size = 29789, upload-time = "2026-01-16T02:09:11.831Z" }, ] -[[package]] -name = "ghydramcp" -version = "2025.12.3" -source = { editable = "." } -dependencies = [ - { name = "fastmcp" }, - { name = "fastmcp-feedback" }, - { name = "mcp" }, - { name = "requests" }, -] - -[package.metadata] -requires-dist = [ - { name = "fastmcp", specifier = ">=2.0.0" }, - { name = "fastmcp-feedback", specifier = ">=1.0.0" }, - { name = "mcp", specifier = ">=1.22.0" }, - { name = "requests", specifier = ">=2.32.3" }, -] - [[package]] name = "greenlet" version = "3.3.1" @@ -589,6 +570,25 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, ] +[[package]] +name = "mcghidra" +version = "2025.12.3" +source = { editable = "." } +dependencies = [ + { name = "fastmcp" }, + { name = "fastmcp-feedback" }, + { name = "mcp" }, + { name = "requests" }, +] + +[package.metadata] +requires-dist = [ + { name = "fastmcp", specifier = ">=2.0.0" }, + { name = "fastmcp-feedback", specifier = ">=1.0.0" }, + { name = "mcp", specifier = ">=1.22.0" }, + { name = "requests", specifier = ">=2.32.3" }, +] + [[package]] name = "mcp" version = "1.23.1"