diff --git a/.env.template b/.env.template new file mode 100644 index 00000000..0248fb3b --- /dev/null +++ b/.env.template @@ -0,0 +1,48 @@ +# Environment variables for GhidraMCP +# Copy this file to .env and customize for your environment +# .env is gitignored — your local settings stay local + +# ============================================================================= +# Ghidra Installation +# ============================================================================= + +# Path to your Ghidra installation directory +# Used by deploy-to-ghidra.ps1 and copy-ghidra-libs scripts +# Examples: +# Windows: GHIDRA_PATH=C:\ghidra_12.0.3_PUBLIC +# Linux: GHIDRA_PATH=/opt/ghidra_12.0.3_PUBLIC +# macOS: GHIDRA_PATH=/Applications/ghidra_12.0.3_PUBLIC +GHIDRA_PATH= + +# ============================================================================= +# Server Configuration +# ============================================================================= + +# Ghidra MCP plugin HTTP server (the Java side) +GHIDRA_SERVER_URL=http://127.0.0.1:8089/ + +# MCP bridge server (the Python side, SSE transport only) +MCP_HOST=127.0.0.1 +MCP_PORT=8081 + +# ============================================================================= +# Development Settings +# ============================================================================= + +# Logging level: DEBUG, INFO, WARNING, ERROR +GHIDRA_MCP_LOG_LEVEL=INFO + +# Decompile timeout in seconds (default: 60) +# Increase for complex functions +DECOMPILE_TIMEOUT=60 + +# ============================================================================= +# Knowledge Database (Optional — RE-Universe PostgreSQL + pgvector) +# ============================================================================= +# Used by knowledge DB MCP tools (store_function_knowledge, query_knowledge_context, etc.) +# The bridge gracefully degrades if the DB is unreachable. +# KNOWLEDGE_DB_HOST=10.0.10.30 +# KNOWLEDGE_DB_PORT=5432 +# KNOWLEDGE_DB_NAME=bsim +# KNOWLEDGE_DB_USER=ben +# KNOWLEDGE_DB_PASSWORD= diff --git a/.github/MARKDOWN_NAMING_GUIDE.md b/.github/MARKDOWN_NAMING_GUIDE.md new file mode 100644 index 00000000..4a1ce8c3 --- /dev/null +++ b/.github/MARKDOWN_NAMING_GUIDE.md @@ -0,0 +1,321 @@ +# Markdown File Naming Best Practices + +> **Standards for naming markdown files** in the Ghidra MCP project. + +--- + +## šŸ“‹ Best Practices Summary + +### āœ… Standard Conventions + +1. **Use kebab-case** (lowercase with hyphens) for most files + - āœ… `getting-started.md` + - āŒ `GETTING_STARTED.md` + +2. **Reserve UPPERCASE** for special files only + - āœ… `README.md` - Entry point documentation + - āœ… `CHANGELOG.md` - Version history (industry standard) + - āœ… `CONTRIBUTING.md` - Contribution guide (GitHub standard) + - āœ… `LICENSE.md` - License file (legal document) + +3. **Use descriptive, readable names** + - āœ… `binary-analysis-guide.md` + - āŒ `BAG.md` + +4. **Keep it concise** (under 40 characters) + - āœ… `structure-discovery-guide.md` + - āš ļø `comprehensive-structure-discovery-master-guide-with-examples.md` (too long) + +5. **Avoid special characters** + - āœ… `api-reference.md` + - āŒ `api_reference.md` (use hyphens, not underscores) + - āŒ `api reference.md` (no spaces) + +6. **Use singular form** unless plural is standard + - āœ… `error-code.md` + - āŒ `error-codes.md` (unless documenting multiple) + +--- + +## šŸ”„ Recommended Renames + +### Root Level Files + +| Current Name | Recommended Name | Reason | Priority | +|--------------|------------------|--------|----------| +| **Keep As-Is (Industry Standards)** |||| +| `README.md` | āœ… Keep | GitHub/industry standard | - | +| `CHANGELOG.md` | āœ… Keep | Industry standard | - | +| `CONTRIBUTING.md` | āœ… Keep | GitHub standard | - | +| `LICENSE` | āœ… Keep | Legal standard | - | +| **Project Core** |||| +| `START_HERE.md` | `getting-started.md` | More descriptive, kebab-case | High | +| `CLAUDE.md` | `ai-assistant-guide.md` | Generic, descriptive | Medium | +| `DOCUMENTATION_INDEX.md` | `docs-index.md` | Shorter, kebab-case | High | +| `PROJECT_STRUCTURE.md` | `project-structure.md` | Consistent casing | Medium | +| **Configuration** |||| +| `NAMING_CONVENTIONS.md` | `naming-conventions.md` | Kebab-case | Medium | +| `MAVEN_VERSION_MANAGEMENT.md` | `maven-guide.md` | Shorter, clearer | Low | +| **Reports** |||| +| `ORGANIZATION_SUMMARY.md` | `reports/organization-summary.md` | Move to reports/, kebab-case | High | +| `PROJECT_CLEANUP_SUMMARY.md` | `reports/cleanup-summary.md` | Move to reports/, shorter | High | +| `QUICKWIN_COMPLETION_REPORT.md` | `reports/quickwin-report.md` | Move to reports/, shorter | High | +| `SESSION_SUMMARY_BINARY_ANALYSIS.md` | `reports/binary-analysis-session.md` | Move to reports/, clearer order | High | +| `CLEANUP_FINAL_REPORT.md` | `reports/cleanup-final.md` | Move to reports/, shorter | High | +| `VERSION_FIX_COMPLETE.md` | `reports/version-fix-complete.md` | Move to reports/, kebab-case | High | +| `VERSION_MANAGEMENT_COMPLETE.md` | `reports/version-management-complete.md` | Move to reports/, kebab-case | High | +| `VERSION_MANAGEMENT_STRATEGY.md` | `reports/version-management-strategy.md` | Move to reports/, kebab-case | High | +| **Improvements** |||| +| `IMPROVEMENTS.md` | `improvements.md` | Kebab-case | Low | +| `IMPROVEMENTS_QUICK_REFERENCE.md` | `improvements-quick-ref.md` | Shorter, kebab-case | Medium | +| `MCP_TOOLS_IMPROVEMENTS.md` | `mcp-tools-improvements.md` | Kebab-case | Medium | +| `GAME_EXE_IMPROVEMENTS.md` | `game-exe-improvements.md` | Kebab-case | Medium | + +--- + +## šŸ“‚ Directory-Specific Naming + +### docs/ Directory + +**Pattern**: `-.md` + +Examples: +- `api-reference.md` āœ… +- `development-guide.md` āœ… +- `troubleshooting-guide.md` āœ… +- `error-codes.md` āœ… + +### docs/guides/ Directory + +**Pattern**: `-guide.md` or `-.md` + +Examples: +- `ordinal-restoration-guide.md` āœ… +- `structure-discovery-guide.md` āœ… +- `register-reuse-fix.md` āœ… + +### docs/analysis/ Directory + +**Pattern**: `-analysis.md` + +Examples: +- `game-exe-analysis.md` āœ… +- `d2client-analysis.md` āœ… +- `storm-library-analysis.md` āœ… + +### docs/reports/ Directory + +**Pattern**: `-report.md` or `-.md` + +Examples: +- `cleanup-report.md` āœ… +- `performance-report-2025-11.md` āœ… +- `organization-summary.md` āœ… + +--- + +## šŸŽÆ Implementation Plan + +### Phase 1: Critical Renames (High Priority) + +**Impact**: Improves discoverability and consistency + +```bash +# Move reports to docs/reports/ +mv ORGANIZATION_SUMMARY.md docs/reports/organization-summary.md +mv PROJECT_CLEANUP_SUMMARY.md docs/reports/cleanup-summary.md +mv QUICKWIN_COMPLETION_REPORT.md docs/reports/quickwin-report.md +mv SESSION_SUMMARY_BINARY_ANALYSIS.md docs/reports/binary-analysis-session.md +mv CLEANUP_FINAL_REPORT.md docs/reports/cleanup-final.md +mv VERSION_FIX_COMPLETE.md docs/reports/version-fix-complete.md +mv VERSION_MANAGEMENT_COMPLETE.md docs/reports/version-management-complete.md +mv VERSION_MANAGEMENT_STRATEGY.md docs/reports/version-management-strategy.md + +# Rename core files +mv START_HERE.md getting-started.md +mv DOCUMENTATION_INDEX.md docs-index.md +``` + +### Phase 2: Consistency Updates (Medium Priority) + +**Impact**: Consistent naming across project + +```bash +# Rename to kebab-case +mv CLAUDE.md ai-assistant-guide.md +mv PROJECT_STRUCTURE.md project-structure.md +mv NAMING_CONVENTIONS.md naming-conventions.md +mv IMPROVEMENTS_QUICK_REFERENCE.md improvements-quick-ref.md +mv MCP_TOOLS_IMPROVEMENTS.md mcp-tools-improvements.md +mv GAME_EXE_IMPROVEMENTS.md game-exe-improvements.md +``` + +### Phase 3: Reference Updates (Required after renaming) + +**Action items**: +1. Update all internal links in markdown files +2. Update references in code/scripts +3. Update VSCode settings +4. Update .gitignore patterns +5. Update CI/CD paths + +--- + +## šŸ“ Naming Rules by File Type + +### Documentation Files + +| Type | Pattern | Example | +|------|---------|---------| +| Guide | `-guide.md` | `installation-guide.md` | +| Reference | `-reference.md` | `api-reference.md` | +| Tutorial | `-tutorial.md` | `quickstart-tutorial.md` | +| Index | `-index.md` | `docs-index.md` | + +### Analysis Files + +| Type | Pattern | Example | +|------|---------|---------| +| Binary | `-analysis.md` | `game-exe-analysis.md` | +| Component | `-.md` | `d2client-ui-analysis.md` | +| Overview | `-overview.md` | `architecture-overview.md` | + +### Report Files + +| Type | Pattern | Example | +|------|---------|---------| +| Status | `-status.md` | `project-status.md` | +| Summary | `-summary.md` | `cleanup-summary.md` | +| Report | `-report.md` | `performance-report.md` | +| Dated | `-YYYY-MM.md` | `milestone-2025-11.md` | + +### Configuration Files + +| Type | Pattern | Example | +|------|---------|---------| +| Standards | `-conventions.md` | `naming-conventions.md` | +| Config Guide | `-guide.md` | `maven-guide.md` | +| Setup | `-setup.md` | `environment-setup.md` | + +--- + +## āœ… Checklist for New Files + +Before creating a new markdown file: + +- [ ] Use kebab-case (lowercase with hyphens) +- [ ] Keep name under 40 characters +- [ ] Make it descriptive and searchable +- [ ] Follow directory-specific patterns +- [ ] Avoid abbreviations unless widely known +- [ ] Check for similar existing files +- [ ] Add to appropriate index file +- [ ] Use `.md` extension (not `.markdown`) + +--- + +## šŸ” Special Cases + +### When to Use UPPERCASE + +**ONLY for these standard files**: +- `README.md` - Primary documentation entry +- `CHANGELOG.md` - Version history (Keep-a-Changelog standard) +- `CONTRIBUTING.md` - Contribution guidelines (GitHub standard) +- `LICENSE` or `LICENSE.md` - Legal license file +- `CODE_OF_CONDUCT.md` - Community standards (GitHub standard) +- `SECURITY.md` - Security policies (GitHub standard) + +### When to Use Underscores + +**AVOID** underscores in markdown files. Use hyphens instead. + +Exception: Generated files that must match tool conventions. + +### When to Use Numbers + +**Prefix with zero** for ordering: +- āœ… `01-introduction.md` +- āœ… `02-installation.md` +- āœ… `03-usage.md` + +**Date suffixes**: +- āœ… `report-2025-11-06.md` +- āŒ `report-11-6-2025.md` + +--- + +## šŸ“Š Impact Analysis + +### Benefits of Standardization + +1. **Improved Discoverability** + - Files easier to find with predictable patterns + - Better IDE autocomplete + +2. **Consistency** + - Uniform appearance in file listings + - Professional presentation + +3. **Maintainability** + - Clear naming conventions for contributors + - Reduced confusion + +4. **SEO/Search** + - Better search results with descriptive names + - Easier to remember and share + +### Migration Effort + +| Phase | Files Affected | Effort | Risk | +|-------|----------------|--------|------| +| Phase 1 | 8 reports | 1-2 hours | Low | +| Phase 2 | 6 core files | 2-3 hours | Medium | +| Phase 3 | Link updates | 3-4 hours | Medium | +| **Total** | **14 files** | **6-9 hours** | **Low-Medium** | + +--- + +## šŸš€ Migration Strategy + +### Safe Renaming Process + +1. **Create branch** + ```bash + git checkout -b standardize-markdown-names + ``` + +2. **Rename files** (preserves history) + ```bash + git mv OLD_NAME.md new-name.md + ``` + +3. **Update references** + - Search and replace in all markdown files + - Update scripts and code references + - Update documentation indexes + +4. **Test** + - Verify all links work + - Check CI/CD pipelines + - Test local builds + +5. **Commit and PR** + ```bash + git commit -m "refactor: standardize markdown file naming conventions" + ``` + +--- + +## šŸ“š References + +- [GitHub Documentation Standards](https://docs.github.com/en/communities) +- [Keep a Changelog](https://keepachangelog.com/) +- [Semantic File Names](https://semver.org/) +- [Markdown Guide](https://www.markdownguide.org/basic-syntax/) + +--- + +**Last Updated**: November 6, 2025 +**Version**: 1.0.0 +**Status**: Proposed Standard diff --git a/.github/workflows/README.md b/.github/workflows/README.md new file mode 100644 index 00000000..dcc895d0 --- /dev/null +++ b/.github/workflows/README.md @@ -0,0 +1,198 @@ +# Release Workflows Documentation + +This directory contains GitHub Actions workflows for automated building, testing, and releasing of GhidraMCP. + +## šŸ“‹ Available Workflows + +### 1. `build.yml` - Continuous Integration + +**Triggers:** Push to main, Pull Requests + +- Builds the project with Maven +- Downloads required Ghidra libraries +- Runs all tests +- Creates build artifacts + +### 2. `release.yml` - Manual/Tagged Releases + +**Triggers:** + +- Git tags matching `v*.*.*` (e.g., `v1.2.0`) +- Manual trigger via GitHub Actions UI + +**Features:** + +- Full build and test execution +- Comprehensive release artifact preparation +- Automatic GitHub release creation +- Professional release notes generation +- Installation instructions included + +### 3. `auto-release.yml` - Automatic Version Releases + +**Triggers:** Version changes in `pom.xml` on main branch + +**Features:** + +- Detects version bumps in pom.xml +- Automatically creates and pushes tags +- Builds and releases without manual intervention +- Generates changelog from commits + +### 4. `pre-release.yml` - Development Pre-Releases + +**Triggers:** Manual trigger only + +**Features:** + +- Creates pre-release versions from any branch +- Validates pre-release version format +- Marks releases as pre-release in GitHub +- Includes testing warnings and feedback instructions + +## šŸš€ How to Create a Release + +### Option 1: Manual Release (Recommended) + +1. **Via Git Tag:** + + ```bash + git tag -a v1.2.0 -m "Release version 1.2.0" + git push origin v1.2.0 + ``` + +2. **Via GitHub Actions UI:** + - Go to Actions → "Create Release" + - Click "Run workflow" + - Enter version (e.g., "1.2.0") + - Choose whether to create a tag + - Click "Run workflow" + +### Option 2: Automatic Release + +1. **Update version in pom.xml:** + + ```xml + 1.3.0 + ``` + +2. **Commit and push to main:** + + ```bash + git add pom.xml + git commit -m "bump version to 1.3.0" + git push origin main + ``` + +3. **Release is created automatically!** + +### Option 3: Pre-Release for Testing + +1. **Via GitHub Actions UI:** + - Go to Actions → "Create Pre-Release" + - Click "Run workflow" + - Enter pre-release version (e.g., "1.3.0-beta.1") + - Select source branch + - Click "Run workflow" + +## šŸ“¦ Release Artifacts + +Each release includes: +- **`GhidraMCP-{version}.zip`** - Main Ghidra plugin +- **`bridge_mcp_ghidra.py`** - MCP server with 57 tools +- **`requirements.txt`** - Python dependencies +- **`README.md`** - Complete project documentation +- **`INSTALLATION.md`** - Quick installation guide +- **`LICENSE`** - License file (if present) + +## šŸ”§ Technical Details + +### Build Environment +- **OS:** Ubuntu Latest +- **Java:** OpenJDK 21 (Temurin) +- **Ghidra:** Version 12.0.3 (auto-downloaded) +- **Maven:** Latest stable version +- **Build Command:** `mvn clean package assembly:single` + +### Required Libraries +All Ghidra libraries are automatically downloaded and configured: +- Base.jar, Decompiler.jar, Docking.jar +- Generic.jar, Project.jar, SoftwareModeling.jar +- Utility.jar, Gui.jar + +### Quality Assurance +- **Full test suite execution** (158 tests) +- **Build verification** before release creation +- **Artifact validation** and proper naming +- **Professional documentation** generation + +## šŸ·ļø Version Format Guidelines + +### Stable Releases +- **Format:** `X.Y.Z` (e.g., `1.2.0`) +- **Semantic Versioning:** + - X = Major version (breaking changes) + - Y = Minor version (new features) + - Z = Patch version (bug fixes) + +### Pre-Releases +- **Format:** `X.Y.Z-{type}.N` (e.g., `1.3.0-beta.1`) +- **Types:** + - `alpha` - Early development version + - `beta` - Feature-complete testing version + - `rc` - Release candidate + +## šŸ› ļø Workflow Maintenance + +### Updating Ghidra Version +Update these variables in all workflow files: +```yaml +env: + GHIDRA_VERSION: 12.0.3 + GHIDRA_DATE: 20250415 +``` + +### Adding New Artifacts +Modify the "Prepare release artifacts" step in each workflow to include additional files. + +### Customizing Release Notes +Edit the release notes generation sections to include project-specific information. + +## šŸ” Troubleshooting + +### Common Issues + +**Build Failures:** +- Check Java version compatibility +- Verify Ghidra library downloads +- Review Maven configuration + +**Tag Creation Issues:** +- Ensure proper permissions +- Check for existing tags +- Verify version format + +**Release Upload Problems:** +- Confirm GitHub token permissions +- Check artifact file sizes +- Verify file paths + +### Debug Information +Each workflow provides: +- **Step-by-step logs** for troubleshooting +- **Artifact listings** for verification +- **Build summaries** in GitHub Actions UI +- **Release links** for easy access + +## šŸ“Š Workflow Status + +| Workflow | Status | Purpose | Frequency | +|----------|--------|---------|-----------| +| Build | āœ… Active | CI/CD | Every push/PR | +| Release | āœ… Active | Stable releases | Manual/Tagged | +| Auto-Release | āœ… Active | Version bump releases | Automatic | +| Pre-Release | āœ… Active | Testing releases | Manual | + +--- + +**For support with release workflows, please check the GitHub Actions logs or create an issue in the repository.** \ No newline at end of file diff --git a/.github/workflows/auto-release.yml b/.github/workflows/auto-release.yml new file mode 100644 index 00000000..124d7cac --- /dev/null +++ b/.github/workflows/auto-release.yml @@ -0,0 +1,241 @@ +name: Auto Release on Version Bump + +on: + push: + branches: [ "main" ] + paths: + - 'pom.xml' # Trigger when pom.xml is modified + +jobs: + check-version: + runs-on: ubuntu-latest + outputs: + version-changed: ${{ steps.version-check.outputs.changed }} + new-version: ${{ steps.version-check.outputs.version }} + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 2 # Need at least 2 commits to compare + + - name: Check version change + id: version-check + run: | + # Get current version from pom.xml + CURRENT_VERSION=$(grep -m1 '' pom.xml | sed 's/.*\(.*\)<\/version>.*/\1/' | tr -d '[:space:]') + echo "Current version: $CURRENT_VERSION" + + # Get previous version from pom.xml in the previous commit + PREVIOUS_VERSION=$(git show HEAD~1:pom.xml | grep -m1 '' | sed 's/.*\(.*\)<\/version>.*/\1/' | tr -d '[:space:]') + echo "Previous version: $PREVIOUS_VERSION" + + # Check if version changed and is not a SNAPSHOT + if [ "$CURRENT_VERSION" != "$PREVIOUS_VERSION" ] && [[ ! "$CURRENT_VERSION" =~ SNAPSHOT ]]; then + echo "Version changed from $PREVIOUS_VERSION to $CURRENT_VERSION" + echo "changed=true" >> $GITHUB_OUTPUT + echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT + else + echo "Version unchanged or is SNAPSHOT, no release needed" + echo "changed=false" >> $GITHUB_OUTPUT + fi + + create-auto-release: + needs: check-version + if: needs.check-version.outputs.version-changed == 'true' + runs-on: ubuntu-latest + permissions: + contents: write + + env: + GHIDRA_VERSION: 12.0.3 + GHIDRA_DATE: 20260210 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + cache: maven + + - name: Download Ghidra + run: | + echo "Downloading Ghidra ${{ env.GHIDRA_VERSION }}..." + wget --no-verbose -O ghidra.zip https://github.com/NationalSecurityAgency/ghidra/releases/download/Ghidra_${{ env.GHIDRA_VERSION }}_build/ghidra_${{ env.GHIDRA_VERSION }}_PUBLIC_${{ env.GHIDRA_DATE }}.zip + 7z x -bd ghidra.zip + + - name: Install Ghidra JARs to Maven local repository + run: | + GHIDRA_DIR="ghidra_${{ env.GHIDRA_VERSION }}_PUBLIC" + GV="${{ env.GHIDRA_VERSION }}" + echo "Installing Ghidra JARs from ${GHIDRA_DIR}..." + + # Framework JARs + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Framework/Generic/lib/Generic.jar" -DgroupId=ghidra -DartifactId=Generic -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Framework/SoftwareModeling/lib/SoftwareModeling.jar" -DgroupId=ghidra -DartifactId=SoftwareModeling -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Framework/Project/lib/Project.jar" -DgroupId=ghidra -DartifactId=Project -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Framework/Docking/lib/Docking.jar" -DgroupId=ghidra -DartifactId=Docking -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Framework/Utility/lib/Utility.jar" -DgroupId=ghidra -DartifactId=Utility -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Framework/Gui/lib/Gui.jar" -DgroupId=ghidra -DartifactId=Gui -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Framework/FileSystem/lib/FileSystem.jar" -DgroupId=ghidra -DartifactId=FileSystem -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Framework/Graph/lib/Graph.jar" -DgroupId=ghidra -DartifactId=Graph -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Framework/DB/lib/DB.jar" -DgroupId=ghidra -DartifactId=DB -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Framework/Emulation/lib/Emulation.jar" -DgroupId=ghidra -DartifactId=Emulation -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Framework/Help/lib/Help.jar" -DgroupId=ghidra -DartifactId=Help -Dversion=${GV} -Dpackaging=jar + + # Feature JARs + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Features/Base/lib/Base.jar" -DgroupId=ghidra -DartifactId=Base -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Features/Decompiler/lib/Decompiler.jar" -DgroupId=ghidra -DartifactId=Decompiler -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Features/PDB/lib/PDB.jar" -DgroupId=ghidra -DartifactId=PDB -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Features/FunctionID/lib/FunctionID.jar" -DgroupId=ghidra -DartifactId=FunctionID -Dversion=${GV} -Dpackaging=jar + + echo "Installed 15 Ghidra JARs to Maven local repository" + + - name: Build with Maven + run: | + echo "Building GhidraMCP..." + mvn clean package assembly:single -DskipTests + echo "Build complete." + ls -la target/GhidraMCP-*.zip 2>/dev/null || ls -la target/*.zip + + - name: Create and push tag + run: | + VERSION="${{ needs.check-version.outputs.new-version }}" + TAG="v${VERSION}" + + # Check if tag already exists + if git rev-parse "$TAG" >/dev/null 2>&1; then + echo "Tag $TAG already exists, skipping tag creation" + else + git config user.name "GitHub Actions" + git config user.email "actions@github.com" + git tag -a "$TAG" -m "Auto-release version $VERSION" + git push origin "$TAG" + echo "Created and pushed tag: $TAG" + fi + + - name: Prepare release artifacts + run: | + VERSION="${{ needs.check-version.outputs.new-version }}" + echo "Preparing release artifacts for version $VERSION..." + mkdir -p release + + # Copy main plugin ZIP + if [ -f "target/GhidraMCP-${VERSION}.zip" ]; then + cp target/GhidraMCP-${VERSION}.zip release/ + else + ZIP_FILE=$(find target/ -name "GhidraMCP-*.zip" | head -1) + if [ -n "$ZIP_FILE" ]; then + cp "$ZIP_FILE" release/GhidraMCP-${VERSION}.zip + else + echo "ERROR: No zip file found in target directory!" + exit 1 + fi + fi + + # Copy essential files + cp bridge_mcp_ghidra.py release/ + cp requirements.txt release/ + cp README.md release/ + [ -f LICENSE ] && cp LICENSE release/ + + # Dynamic tool count + MCP_TOOLS=$(grep -c '@mcp.tool()' bridge_mcp_ghidra.py 2>/dev/null || echo "unknown") + + cat > release/INSTALLATION.md << INSTEOF + # GhidraMCP ${VERSION} Installation + + ## Quick Start + 1. In Ghidra: **File > Install Extensions > Add** and select GhidraMCP-${VERSION}.zip + 2. Restart Ghidra, enable plugin: **File > Configure > Configure All Plugins > GhidraMCP** + 3. Install Python dependencies: \`pip install -r requirements.txt\` + 4. Run: \`python bridge_mcp_ghidra.py\` + + ## What's Included + - GhidraMCP-${VERSION}.zip - Ghidra extension + - bridge_mcp_ghidra.py - MCP server with ${MCP_TOOLS} tools + - requirements.txt - Python dependencies + + For complete documentation, see [README](https://github.com/bethington/ghidra-mcp#readme). + INSTEOF + + echo "Release artifacts:" + ls -la release/ + + - name: Generate release notes + run: | + VERSION="${{ needs.check-version.outputs.new-version }}" + MCP_TOOLS=$(grep -c '@mcp.tool()' bridge_mcp_ghidra.py 2>/dev/null || echo "unknown") + GUI_EPS=$(grep -c 'createContext(' src/main/java/com/xebyte/GhidraMCPPlugin.java 2>/dev/null || echo "unknown") + HEADLESS_EPS=$(grep -c 'createContext(' src/main/java/com/xebyte/headless/GhidraMCPHeadlessServer.java 2>/dev/null || echo "unknown") + + # Get commits since last tag + LAST_TAG=$(git describe --tags --abbrev=0 HEAD~1 2>/dev/null || echo "") + + cat > release_notes.md << GENEOF + # GhidraMCP ${VERSION} + + Production-ready Model Context Protocol server for Ghidra reverse engineering platform. + + ## By the Numbers + + | Metric | Value | + |--------|-------| + | **MCP Tools** | ${MCP_TOOLS} | + | **GUI Endpoints** | ${GUI_EPS} | + | **Headless Endpoints** | ${HEADLESS_EPS} | + | **Java** | 21 LTS | + | **Ghidra** | ${{ env.GHIDRA_VERSION }} | + + ## Installation + + 1. Download **GhidraMCP-${VERSION}.zip** below + 2. In Ghidra: **File > Install Extensions > Add** and select the ZIP + 3. Restart Ghidra, enable plugin: **File > Configure > Configure All Plugins > GhidraMCP** + 4. Install Python bridge: \`pip install -r requirements.txt\` + 5. Run: \`python bridge_mcp_ghidra.py\` + + See [CHANGELOG.md](https://github.com/bethington/ghidra-mcp/blob/main/CHANGELOG.md) for detailed release notes. + + ## Recent Changes + + GENEOF + + if [ -n "$LAST_TAG" ]; then + git log --oneline --no-merges ${LAST_TAG}..HEAD >> release_notes.md + else + echo "Initial release" >> release_notes.md + fi + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + tag_name: "v${{ needs.check-version.outputs.new-version }}" + name: "GhidraMCP ${{ needs.check-version.outputs.new-version }}" + body_path: release_notes.md + files: | + release/* + draft: false + prerelease: false + fail_on_unmatched_files: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Auto-release summary + run: | + VERSION="${{ needs.check-version.outputs.new-version }}" + MCP_TOOLS=$(grep -c '@mcp.tool()' bridge_mcp_ghidra.py 2>/dev/null || echo "unknown") + echo "## Auto-Release Created" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Version:** $VERSION" >> $GITHUB_STEP_SUMMARY + echo "**MCP Tools:** $MCP_TOOLS" >> $GITHUB_STEP_SUMMARY + echo "**Trigger:** Version bump detected in pom.xml" >> $GITHUB_STEP_SUMMARY + echo "**Tag:** v$VERSION" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "[Download Release](https://github.com/${{ github.repository }}/releases/tag/v$VERSION)" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 868268ac..0bf26fec 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,17 +10,24 @@ jobs: build: runs-on: ubuntu-latest env: - GHIDRA_VERSION: 11.3.2 - GHIDRA_DATE: 20250415 + GHIDRA_VERSION: 12.0.3 + GHIDRA_DATE: 20260210 GHIDRA_LIBS: >- Features/Base/lib/Base.jar Features/Decompiler/lib/Decompiler.jar + Features/PDB/lib/PDB.jar + Features/FunctionID/lib/FunctionID.jar Framework/Docking/lib/Docking.jar Framework/Generic/lib/Generic.jar Framework/Project/lib/Project.jar Framework/SoftwareModeling/lib/SoftwareModeling.jar Framework/Utility/lib/Utility.jar Framework/Gui/lib/Gui.jar + Framework/FileSystem/lib/FileSystem.jar + Framework/Graph/lib/Graph.jar + Framework/DB/lib/DB.jar + Framework/Emulation/lib/Emulation.jar + Framework/Help/lib/Help.jar steps: - uses: actions/checkout@v4 @@ -36,21 +43,53 @@ jobs: wget --no-verbose -O ghidra.zip https://github.com/NationalSecurityAgency/ghidra/releases/download/Ghidra_${{ env.GHIDRA_VERSION }}_build/ghidra_${{ env.GHIDRA_VERSION }}_PUBLIC_${{ env.GHIDRA_DATE }}.zip 7z x -bd ghidra.zip - - name: Copy Ghidra libs + - name: Install Ghidra JARs to Maven local repository run: | - mkdir -p ./lib - for libfile in ${{ env.GHIDRA_LIBS }} - do echo "Copying ${libfile} to lib/" - cp ghidra_${{ env.GHIDRA_VERSION }}_PUBLIC/Ghidra/${libfile} ./lib/ - done + GHIDRA_DIR="ghidra_${{ env.GHIDRA_VERSION }}_PUBLIC" + + # Install Framework JARs + mvn -q install:install-file -Dfile="$GHIDRA_DIR/Ghidra/Framework/Generic/lib/Generic.jar" \ + -DgroupId=ghidra -DartifactId=Generic -Dversion=${{ env.GHIDRA_VERSION }} -Dpackaging=jar + mvn -q install:install-file -Dfile="$GHIDRA_DIR/Ghidra/Framework/SoftwareModeling/lib/SoftwareModeling.jar" \ + -DgroupId=ghidra -DartifactId=SoftwareModeling -Dversion=${{ env.GHIDRA_VERSION }} -Dpackaging=jar + mvn -q install:install-file -Dfile="$GHIDRA_DIR/Ghidra/Framework/Project/lib/Project.jar" \ + -DgroupId=ghidra -DartifactId=Project -Dversion=${{ env.GHIDRA_VERSION }} -Dpackaging=jar + mvn -q install:install-file -Dfile="$GHIDRA_DIR/Ghidra/Framework/Docking/lib/Docking.jar" \ + -DgroupId=ghidra -DartifactId=Docking -Dversion=${{ env.GHIDRA_VERSION }} -Dpackaging=jar + mvn -q install:install-file -Dfile="$GHIDRA_DIR/Ghidra/Framework/Utility/lib/Utility.jar" \ + -DgroupId=ghidra -DartifactId=Utility -Dversion=${{ env.GHIDRA_VERSION }} -Dpackaging=jar + mvn -q install:install-file -Dfile="$GHIDRA_DIR/Ghidra/Framework/Gui/lib/Gui.jar" \ + -DgroupId=ghidra -DartifactId=Gui -Dversion=${{ env.GHIDRA_VERSION }} -Dpackaging=jar + mvn -q install:install-file -Dfile="$GHIDRA_DIR/Ghidra/Framework/FileSystem/lib/FileSystem.jar" \ + -DgroupId=ghidra -DartifactId=FileSystem -Dversion=${{ env.GHIDRA_VERSION }} -Dpackaging=jar + mvn -q install:install-file -Dfile="$GHIDRA_DIR/Ghidra/Framework/Graph/lib/Graph.jar" \ + -DgroupId=ghidra -DartifactId=Graph -Dversion=${{ env.GHIDRA_VERSION }} -Dpackaging=jar + mvn -q install:install-file -Dfile="$GHIDRA_DIR/Ghidra/Framework/DB/lib/DB.jar" \ + -DgroupId=ghidra -DartifactId=DB -Dversion=${{ env.GHIDRA_VERSION }} -Dpackaging=jar + mvn -q install:install-file -Dfile="$GHIDRA_DIR/Ghidra/Framework/Emulation/lib/Emulation.jar" \ + -DgroupId=ghidra -DartifactId=Emulation -Dversion=${{ env.GHIDRA_VERSION }} -Dpackaging=jar + mvn -q install:install-file -Dfile="$GHIDRA_DIR/Ghidra/Framework/Help/lib/Help.jar" \ + -DgroupId=ghidra -DartifactId=Help -Dversion=${{ env.GHIDRA_VERSION }} -Dpackaging=jar + + # Install Feature JARs + mvn -q install:install-file -Dfile="$GHIDRA_DIR/Ghidra/Features/Base/lib/Base.jar" \ + -DgroupId=ghidra -DartifactId=Base -Dversion=${{ env.GHIDRA_VERSION }} -Dpackaging=jar + mvn -q install:install-file -Dfile="$GHIDRA_DIR/Ghidra/Features/Decompiler/lib/Decompiler.jar" \ + -DgroupId=ghidra -DartifactId=Decompiler -Dversion=${{ env.GHIDRA_VERSION }} -Dpackaging=jar + mvn -q install:install-file -Dfile="$GHIDRA_DIR/Ghidra/Features/PDB/lib/PDB.jar" \ + -DgroupId=ghidra -DartifactId=PDB -Dversion=${{ env.GHIDRA_VERSION }} -Dpackaging=jar + mvn -q install:install-file -Dfile="$GHIDRA_DIR/Ghidra/Features/FunctionID/lib/FunctionID.jar" \ + -DgroupId=ghidra -DartifactId=FunctionID -Dversion=${{ env.GHIDRA_VERSION }} -Dpackaging=jar + + echo "āœ… Installed Ghidra JARs to Maven local repository" - name: Build with Maven - run: mvn clean package assembly:single + run: mvn clean package assembly:single -DskipTests - name: Assemble release directory run: | mkdir release - cp target/GhidraMCP-*-SNAPSHOT.zip release/ + cp target/GhidraMCP-*.zip release/ || { echo "No zip found in target/"; ls -la target/; exit 1; } cp bridge_mcp_ghidra.py release/ - name: Upload artifact diff --git a/.github/workflows/pre-release.yml b/.github/workflows/pre-release.yml new file mode 100644 index 00000000..9ced4afc --- /dev/null +++ b/.github/workflows/pre-release.yml @@ -0,0 +1,193 @@ +name: Create Pre-Release + +on: + workflow_dispatch: + inputs: + version: + description: 'Pre-release version (e.g., 3.2.0-beta.1)' + required: true + branch: + description: 'Branch to create pre-release from' + required: true + default: 'main' + +env: + GHIDRA_VERSION: 12.0.3 + GHIDRA_DATE: 20260210 + +jobs: + create-prerelease: + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ github.event.inputs.branch }} + fetch-depth: 0 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + cache: maven + + - name: Validate version format + run: | + VERSION="${{ github.event.inputs.version }}" + if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+-(alpha|beta|rc)\.[0-9]+$ ]]; then + echo "Invalid pre-release version format: $VERSION" + echo "Expected format: X.Y.Z-{alpha|beta|rc}.N (e.g., 3.2.0-beta.1)" + exit 1 + fi + echo "Version format valid: $VERSION" + + - name: Download Ghidra + run: | + echo "Downloading Ghidra ${{ env.GHIDRA_VERSION }}..." + wget --no-verbose -O ghidra.zip https://github.com/NationalSecurityAgency/ghidra/releases/download/Ghidra_${{ env.GHIDRA_VERSION }}_build/ghidra_${{ env.GHIDRA_VERSION }}_PUBLIC_${{ env.GHIDRA_DATE }}.zip + 7z x -bd ghidra.zip + + - name: Install Ghidra JARs to Maven local repository + run: | + GHIDRA_DIR="ghidra_${{ env.GHIDRA_VERSION }}_PUBLIC" + GV="${{ env.GHIDRA_VERSION }}" + echo "Installing Ghidra JARs from ${GHIDRA_DIR}..." + + # Framework JARs + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Framework/Generic/lib/Generic.jar" -DgroupId=ghidra -DartifactId=Generic -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Framework/SoftwareModeling/lib/SoftwareModeling.jar" -DgroupId=ghidra -DartifactId=SoftwareModeling -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Framework/Project/lib/Project.jar" -DgroupId=ghidra -DartifactId=Project -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Framework/Docking/lib/Docking.jar" -DgroupId=ghidra -DartifactId=Docking -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Framework/Utility/lib/Utility.jar" -DgroupId=ghidra -DartifactId=Utility -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Framework/Gui/lib/Gui.jar" -DgroupId=ghidra -DartifactId=Gui -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Framework/FileSystem/lib/FileSystem.jar" -DgroupId=ghidra -DartifactId=FileSystem -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Framework/Graph/lib/Graph.jar" -DgroupId=ghidra -DartifactId=Graph -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Framework/DB/lib/DB.jar" -DgroupId=ghidra -DartifactId=DB -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Framework/Emulation/lib/Emulation.jar" -DgroupId=ghidra -DartifactId=Emulation -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Framework/Help/lib/Help.jar" -DgroupId=ghidra -DartifactId=Help -Dversion=${GV} -Dpackaging=jar + + # Feature JARs + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Features/Base/lib/Base.jar" -DgroupId=ghidra -DartifactId=Base -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Features/Decompiler/lib/Decompiler.jar" -DgroupId=ghidra -DartifactId=Decompiler -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Features/PDB/lib/PDB.jar" -DgroupId=ghidra -DartifactId=PDB -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Features/FunctionID/lib/FunctionID.jar" -DgroupId=ghidra -DartifactId=FunctionID -Dversion=${GV} -Dpackaging=jar + + echo "Installed 15 Ghidra JARs to Maven local repository" + + - name: Build with Maven + run: | + echo "Building GhidraMCP pre-release..." + mvn clean package assembly:single -DskipTests + echo "Build complete." + ls -la target/GhidraMCP-*.zip 2>/dev/null || ls -la target/*.zip + + - name: Create pre-release tag + run: | + VERSION="${{ github.event.inputs.version }}" + TAG="v${VERSION}" + + if git rev-parse "$TAG" >/dev/null 2>&1; then + echo "Tag $TAG already exists!" + exit 1 + fi + + git config user.name "GitHub Actions" + git config user.email "actions@github.com" + git tag -a "$TAG" -m "Pre-release $VERSION from branch ${{ github.event.inputs.branch }}" + git push origin "$TAG" + echo "Created and pushed tag: $TAG" + + - name: Prepare pre-release artifacts + run: | + VERSION="${{ github.event.inputs.version }}" + echo "Preparing pre-release artifacts..." + mkdir -p release + + # Copy main plugin ZIP + if [ -f "target/GhidraMCP-${VERSION}.zip" ]; then + cp target/GhidraMCP-${VERSION}.zip release/ + else + ZIP_FILE=$(find target/ -name "GhidraMCP-*.zip" | head -1) + if [ -n "$ZIP_FILE" ]; then + cp "$ZIP_FILE" release/GhidraMCP-${VERSION}.zip + else + echo "ERROR: No zip file found in target directory!" + exit 1 + fi + fi + + # Copy essential files + cp bridge_mcp_ghidra.py release/ + cp requirements.txt release/ + cp README.md release/ + [ -f LICENSE ] && cp LICENSE release/ + + echo "Pre-release artifacts prepared:" + ls -la release/ + + - name: Generate pre-release notes + run: | + VERSION="${{ github.event.inputs.version }}" + BRANCH="${{ github.event.inputs.branch }}" + MCP_TOOLS=$(grep -c '@mcp.tool()' bridge_mcp_ghidra.py 2>/dev/null || echo "unknown") + + cat > release_notes.md << GENEOF + # GhidraMCP ${VERSION} Pre-Release + + **This is a pre-release version for testing purposes.** + + - **Version:** ${VERSION} + - **Source Branch:** ${BRANCH} + - **MCP Tools:** ${MCP_TOOLS} + - **Build Date:** $(date -u +"%Y-%m-%d %H:%M:%S UTC") + + ## Recent Changes + + GENEOF + + git log --oneline --no-merges -15 >> release_notes.md + + cat >> release_notes.md << GENEOF + + ## Installation + + Same as stable releases: + 1. In Ghidra: **File > Install Extensions > Add** and select the ZIP + 2. Restart Ghidra, enable plugin + 3. \`pip install -r requirements.txt\` + 4. \`python bridge_mcp_ghidra.py\` + + --- + + **Pre-release: use for testing only.** + GENEOF + + - name: Create GitHub Pre-Release + uses: softprops/action-gh-release@v2 + with: + tag_name: "v${{ github.event.inputs.version }}" + name: "GhidraMCP ${{ github.event.inputs.version }} (Pre-Release)" + body_path: release_notes.md + files: | + release/* + draft: false + prerelease: true + generate_release_notes: false + fail_on_unmatched_files: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Pre-release summary + run: | + VERSION="${{ github.event.inputs.version }}" + BRANCH="${{ github.event.inputs.branch }}" + echo "## Pre-Release Created" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Version:** ${VERSION}" >> $GITHUB_STEP_SUMMARY + echo "**Branch:** ${BRANCH}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "[Download Pre-Release](https://github.com/${{ github.repository }}/releases/tag/v${VERSION})" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..f114be08 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,313 @@ +name: Create Release + +on: + push: + tags: + - 'v*.*.*' # Triggers on version tags like v1.2.0 + workflow_dispatch: # Allows manual triggering + inputs: + version: + description: 'Release version (e.g., 1.2.0)' + required: true + default: '1.2.0' + create_tag: + description: 'Create and push tag for this release' + type: boolean + default: true + +env: + GHIDRA_VERSION: 12.0.3 + GHIDRA_DATE: 20260210 + +jobs: + create-release: + runs-on: ubuntu-latest + permissions: + contents: write # Required for creating releases and tags + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Fetch full history for proper tagging + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + cache: maven + + - name: Determine version + id: version + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + VERSION="${{ github.event.inputs.version }}" + else + VERSION="${GITHUB_REF#refs/tags/v}" + fi + echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT + echo "TAG=v${VERSION}" >> $GITHUB_OUTPUT + echo "Release version: ${VERSION}" + + - name: Create and push tag (if manual trigger) + if: github.event_name == 'workflow_dispatch' && github.event.inputs.create_tag == 'true' + run: | + git config user.name "GitHub Actions" + git config user.email "actions@github.com" + git tag -a "${{ steps.version.outputs.TAG }}" -m "Release ${{ steps.version.outputs.VERSION }}" + git push origin "${{ steps.version.outputs.TAG }}" + + - name: Download Ghidra + run: | + echo "Downloading Ghidra ${{ env.GHIDRA_VERSION }}..." + wget --no-verbose -O ghidra.zip https://github.com/NationalSecurityAgency/ghidra/releases/download/Ghidra_${{ env.GHIDRA_VERSION }}_build/ghidra_${{ env.GHIDRA_VERSION }}_PUBLIC_${{ env.GHIDRA_DATE }}.zip + 7z x -bd ghidra.zip + + - name: Install Ghidra JARs to Maven local repository + run: | + GHIDRA_DIR="ghidra_${{ env.GHIDRA_VERSION }}_PUBLIC" + GV="${{ env.GHIDRA_VERSION }}" + echo "Installing Ghidra JARs from ${GHIDRA_DIR}..." + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Framework/Generic/lib/Generic.jar" -DgroupId=ghidra -DartifactId=Generic -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Framework/SoftwareModeling/lib/SoftwareModeling.jar" -DgroupId=ghidra -DartifactId=SoftwareModeling -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Framework/Project/lib/Project.jar" -DgroupId=ghidra -DartifactId=Project -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Framework/Docking/lib/Docking.jar" -DgroupId=ghidra -DartifactId=Docking -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Framework/Utility/lib/Utility.jar" -DgroupId=ghidra -DartifactId=Utility -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Framework/Gui/lib/Gui.jar" -DgroupId=ghidra -DartifactId=Gui -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Framework/FileSystem/lib/FileSystem.jar" -DgroupId=ghidra -DartifactId=FileSystem -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Framework/Graph/lib/Graph.jar" -DgroupId=ghidra -DartifactId=Graph -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Framework/DB/lib/DB.jar" -DgroupId=ghidra -DartifactId=DB -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Framework/Emulation/lib/Emulation.jar" -DgroupId=ghidra -DartifactId=Emulation -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Features/Base/lib/Base.jar" -DgroupId=ghidra -DartifactId=Base -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Features/Decompiler/lib/Decompiler.jar" -DgroupId=ghidra -DartifactId=Decompiler -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Features/PDB/lib/PDB.jar" -DgroupId=ghidra -DartifactId=PDB -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Features/FunctionID/lib/FunctionID.jar" -DgroupId=ghidra -DartifactId=FunctionID -Dversion=${GV} -Dpackaging=jar + mvn -q install:install-file -Dfile="${GHIDRA_DIR}/Ghidra/Framework/Help/lib/Help.jar" -DgroupId=ghidra -DartifactId=Help -Dversion=${GV} -Dpackaging=jar + echo "āœ… Installed 15 Ghidra JARs to Maven local repository" + + - name: Build with Maven + run: | + echo "Building GhidraMCP with Maven..." + mvn clean package assembly:single -DskipTests + echo "Build complete. Artifacts:" + ls -la target/ + + - name: Verify build + run: | + echo "Verifying build artifacts..." + ls -la target/GhidraMCP-*.zip 2>/dev/null || ls -la target/*.zip + echo "āœ… Build verified" + # Note: Java tests are integration tests requiring a running Ghidra instance. + # Compilation is verified in the build step above. + + - name: Prepare release artifacts + run: | + echo "Preparing release artifacts..." + mkdir -p release + + # List what's in target directory for debugging + echo "Contents of target directory:" + ls -la target/ + + # Copy main plugin ZIP (the version should match the tag) + if [ -f "target/GhidraMCP-${{ steps.version.outputs.VERSION }}.zip" ]; then + echo "Copying versioned zip: GhidraMCP-${{ steps.version.outputs.VERSION }}.zip" + cp target/GhidraMCP-${{ steps.version.outputs.VERSION }}.zip release/ + elif [ -f "target/GhidraMCP.zip" ]; then + echo "Copying non-versioned zip: GhidraMCP.zip -> GhidraMCP-${{ steps.version.outputs.VERSION }}.zip" + cp target/GhidraMCP.zip release/GhidraMCP-${{ steps.version.outputs.VERSION }}.zip + else + echo "Looking for any zip file in target..." + ZIP_FILE=$(find target/ -name "*.zip" | head -1) + if [ -n "$ZIP_FILE" ]; then + echo "Found zip file: $ZIP_FILE" + cp "$ZIP_FILE" release/GhidraMCP-${{ steps.version.outputs.VERSION }}.zip + else + echo "ERROR: No zip file found in target directory!" + exit 1 + fi + fi + + # Copy Python MCP bridge + cp bridge_mcp_ghidra.py release/ + + # Copy requirements files + cp requirements.txt release/ + + # Copy installation script + cp copy-ghidra-libs.bat release/ 2>/dev/null || echo "copy-ghidra-libs.bat not found, skipping" + + # Copy README and LICENSE + cp README.md release/ + cp LICENSE release/ 2>/dev/null || echo "LICENSE file not found, skipping" + + # Create installation instructions + MCP_TOOLS=$(grep -c '@mcp.tool()' bridge_mcp_ghidra.py 2>/dev/null || echo "179") + cat > release/INSTALLATION.md << INSTEOF + # GhidraMCP Installation Instructions + + ## Quick Installation + + 1. **Install the Ghidra Plugin:** + - In Ghidra: **File > Install Extensions > Add** and select \`GhidraMCP-${{ steps.version.outputs.VERSION }}.zip\` + - Restart Ghidra and enable the plugin: **File > Configure > Configure All Plugins > GhidraMCP** + + 2. **Install Python Dependencies:** + \`\`\`bash + pip install -r requirements.txt + \`\`\` + + 3. **Run the MCP Server:** + \`\`\`bash + python bridge_mcp_ghidra.py + \`\`\` + + ## What's Included + + - \`GhidraMCP-${{ steps.version.outputs.VERSION }}.zip\` - Ghidra extension + - \`bridge_mcp_ghidra.py\` - MCP server with ${MCP_TOOLS} tools + - \`requirements.txt\` - Python dependencies + - \`README.md\` - Complete documentation + + For detailed documentation, see the [README](https://github.com/bethington/ghidra-mcp#readme). + INSTEOF + + echo "Release artifacts prepared:" + ls -la release/ + + # Verify the main zip file is present + if [ -f "release/GhidraMCP-${{ steps.version.outputs.VERSION }}.zip" ]; then + echo "āœ… Main plugin zip confirmed: release/GhidraMCP-${{ steps.version.outputs.VERSION }}.zip" + ls -la "release/GhidraMCP-${{ steps.version.outputs.VERSION }}.zip" + else + echo "āŒ ERROR: Main plugin zip not found in release directory!" + echo "Contents of release directory:" + ls -la release/ + exit 1 + fi + + - name: Generate release notes + id: release_notes + run: | + VERSION="${{ steps.version.outputs.VERSION }}" + # Count MCP tools dynamically from bridge + MCP_TOOLS=$(grep -c '@mcp.tool()' bridge_mcp_ghidra.py 2>/dev/null || echo "193") + # Count GUI endpoints: direct createContext + shared EndpointRegistry entries + GUI_DIRECT=$(grep -cP '(?:server|httpServer)\.createContext\(' src/main/java/com/xebyte/GhidraMCPPlugin.java 2>/dev/null || echo "0") + REGISTRY=$(grep -cP '(?:get|post)\(\s*"/' src/main/java/com/xebyte/core/EndpointRegistry.java 2>/dev/null || echo "0") + GUI_EPS=$((GUI_DIRECT + REGISTRY)) + # Count headless endpoints: direct createContext + shared EndpointRegistry entries + HEADLESS_DIRECT=$(grep -cP '(?:server|httpServer)\.createContext\(' src/main/java/com/xebyte/headless/GhidraMCPHeadlessServer.java 2>/dev/null || echo "0") + HEADLESS_EPS=$((HEADLESS_DIRECT + REGISTRY)) + + cat > release_notes.md << GENEOF + # GhidraMCP Release ${VERSION} + + Production-ready Model Context Protocol server for Ghidra reverse engineering platform. + + ## By the Numbers + + | Metric | Value | + |--------|-------| + | **MCP Tools** | ${MCP_TOOLS} | + | **GUI Endpoints** | ${GUI_EPS} | + | **Headless Endpoints** | ${HEADLESS_EPS} | + | **Java** | 21 LTS | + | **Ghidra** | ${{ env.GHIDRA_VERSION }} | + + ## Installation + + 1. Download **GhidraMCP-${VERSION}.zip** below + 2. In Ghidra: **File > Install Extensions > Add** and select the ZIP + 3. Restart Ghidra, enable plugin: **File > Configure > Configure All Plugins > GhidraMCP** + 4. Start server: **Tools > GhidraMCP > Start MCP Server** + 5. Install Python bridge: \`pip install -r requirements.txt\` + 6. Run: \`python bridge_mcp_ghidra.py\` + + ## What's Included + + - **GhidraMCP-${VERSION}.zip** — Ghidra extension (GUI plugin) + - **bridge_mcp_ghidra.py** — MCP protocol bridge (${MCP_TOOLS} tools) + - **requirements.txt** — Python dependencies + + See [CHANGELOG.md](https://github.com/bethington/ghidra-mcp/blob/main/CHANGELOG.md) for detailed release notes. + See [README.md](https://github.com/bethington/ghidra-mcp#readme) for full documentation. + GENEOF + + - name: Debug release files + run: | + echo "=== DEBUG: Files that will be uploaded to release ===" + echo "Main plugin zip:" + ls -la release/GhidraMCP-${{ steps.version.outputs.VERSION }}.zip || echo "āŒ ZIP NOT FOUND" + + echo "All release files:" + find release/ -type f -exec ls -la {} \; + + echo "File checksums:" + find release/ -type f -exec sha256sum {} \; + + - name: Check if release already exists + id: check_release + run: | + if gh release view "${{ steps.version.outputs.TAG }}" --json body --jq '.body' 2>/dev/null | grep -q "By the Numbers"; then + echo "EXISTS=true" >> $GITHUB_OUTPUT + echo "Release exists with custom notes — will upload artifacts only" + else + echo "EXISTS=false" >> $GITHUB_OUTPUT + echo "No existing release or has default notes — will create with generated notes" + fi + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ steps.version.outputs.TAG }} + name: "GhidraMCP ${{ steps.version.outputs.VERSION }}" + body_path: ${{ steps.check_release.outputs.EXISTS == 'false' && 'release_notes.md' || '' }} + files: | + release/GhidraMCP-${{ steps.version.outputs.VERSION }}.zip + release/bridge_mcp_ghidra.py + release/requirements.txt + release/README.md + release/INSTALLATION.md + release/copy-ghidra-libs.bat + draft: false + prerelease: false + generate_release_notes: false + fail_on_unmatched_files: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Upload build artifacts + uses: actions/upload-artifact@v4 + with: + name: ghidra-mcp-${{ steps.version.outputs.VERSION }} + path: | + release/* + target/*.jar + retention-days: 30 + + - name: Release Summary + run: | + echo "## šŸŽ‰ Release ${{ steps.version.outputs.VERSION }} Created Successfully!" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### šŸ“¦ Artifacts" >> $GITHUB_STEP_SUMMARY + echo "- **Plugin:** GhidraMCP-${{ steps.version.outputs.VERSION }}.zip" >> $GITHUB_STEP_SUMMARY + MCP_TOOLS=$(grep -c '@mcp.tool()' bridge_mcp_ghidra.py 2>/dev/null || echo "179") + echo "- **MCP Server:** bridge_mcp_ghidra.py (${MCP_TOOLS} tools)" >> $GITHUB_STEP_SUMMARY + echo "- **Dependencies:** requirements.txt" >> $GITHUB_STEP_SUMMARY + echo "- **Documentation:** README.md, INSTALLATION.md" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### šŸ”— Links" >> $GITHUB_STEP_SUMMARY + echo "- [Release Page](https://github.com/${{ github.repository }}/releases/tag/${{ steps.version.outputs.TAG }})" >> $GITHUB_STEP_SUMMARY + echo "- [Download ZIP](https://github.com/${{ github.repository }}/releases/download/${{ steps.version.outputs.TAG }}/GhidraMCP-${{ steps.version.outputs.VERSION }}.zip)" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### šŸ“Š Build Info" >> $GITHUB_STEP_SUMMARY + echo "- **Java Version:** 21" >> $GITHUB_STEP_SUMMARY + echo "- **Ghidra Version:** ${{ env.GHIDRA_VERSION }}" >> $GITHUB_STEP_SUMMARY + echo "- **Build Time:** $(date -u +"%Y-%m-%d %H:%M:%S UTC")" >> $GITHUB_STEP_SUMMARY + echo "- **Commit:** ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY + + echo "āœ… Release workflow completed successfully!" \ No newline at end of file diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 00000000..f251127c --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,192 @@ +name: Tests + +on: + push: + branches: [ main, develop ] + pull_request: + branches: [ main, develop ] + +jobs: + java-build: + name: Java Build (Maven) + runs-on: ubuntu-latest + strategy: + matrix: + java-version: [ '21' ] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Java + uses: actions/setup-java@v4 + with: + java-version: ${{ matrix.java-version }} + distribution: 'temurin' + cache: maven + + - name: Cache Ghidra installation + id: cache-ghidra + uses: actions/cache@v4 + with: + path: /tmp/ghidra + key: ghidra-12.0.3-PUBLIC-20260210 + + - name: Download Ghidra + if: steps.cache-ghidra.outputs.cache-hit != 'true' + run: | + echo "Downloading Ghidra 12.0.3..." + curl -sL -o /tmp/ghidra.zip \ + "https://github.com/NationalSecurityAgency/ghidra/releases/download/Ghidra_12.0.3_build/ghidra_12.0.3_PUBLIC_20260210.zip" + mkdir -p /tmp/ghidra + unzip -q /tmp/ghidra.zip -d /tmp/ghidra + rm /tmp/ghidra.zip + + - name: Install Ghidra JARs to Maven local repository + run: | + GHIDRA_DIR=$(find /tmp/ghidra -maxdepth 1 -type d -name 'ghidra_*' | head -1) + GHIDRA_VERSION="12.0.3" + echo "Using Ghidra directory: $GHIDRA_DIR" + + # Install Framework JARs + mvn -q install:install-file -Dfile="$GHIDRA_DIR/Ghidra/Framework/Generic/lib/Generic.jar" \ + -DgroupId=ghidra -DartifactId=Generic -Dversion=$GHIDRA_VERSION -Dpackaging=jar + mvn -q install:install-file -Dfile="$GHIDRA_DIR/Ghidra/Framework/SoftwareModeling/lib/SoftwareModeling.jar" \ + -DgroupId=ghidra -DartifactId=SoftwareModeling -Dversion=$GHIDRA_VERSION -Dpackaging=jar + mvn -q install:install-file -Dfile="$GHIDRA_DIR/Ghidra/Framework/Project/lib/Project.jar" \ + -DgroupId=ghidra -DartifactId=Project -Dversion=$GHIDRA_VERSION -Dpackaging=jar + mvn -q install:install-file -Dfile="$GHIDRA_DIR/Ghidra/Framework/Docking/lib/Docking.jar" \ + -DgroupId=ghidra -DartifactId=Docking -Dversion=$GHIDRA_VERSION -Dpackaging=jar + mvn -q install:install-file -Dfile="$GHIDRA_DIR/Ghidra/Framework/Utility/lib/Utility.jar" \ + -DgroupId=ghidra -DartifactId=Utility -Dversion=$GHIDRA_VERSION -Dpackaging=jar + mvn -q install:install-file -Dfile="$GHIDRA_DIR/Ghidra/Framework/Gui/lib/Gui.jar" \ + -DgroupId=ghidra -DartifactId=Gui -Dversion=$GHIDRA_VERSION -Dpackaging=jar + mvn -q install:install-file -Dfile="$GHIDRA_DIR/Ghidra/Framework/FileSystem/lib/FileSystem.jar" \ + -DgroupId=ghidra -DartifactId=FileSystem -Dversion=$GHIDRA_VERSION -Dpackaging=jar + mvn -q install:install-file -Dfile="$GHIDRA_DIR/Ghidra/Framework/Graph/lib/Graph.jar" \ + -DgroupId=ghidra -DartifactId=Graph -Dversion=$GHIDRA_VERSION -Dpackaging=jar + mvn -q install:install-file -Dfile="$GHIDRA_DIR/Ghidra/Framework/DB/lib/DB.jar" \ + -DgroupId=ghidra -DartifactId=DB -Dversion=$GHIDRA_VERSION -Dpackaging=jar + mvn -q install:install-file -Dfile="$GHIDRA_DIR/Ghidra/Framework/Emulation/lib/Emulation.jar" \ + -DgroupId=ghidra -DartifactId=Emulation -Dversion=$GHIDRA_VERSION -Dpackaging=jar + mvn -q install:install-file -Dfile="$GHIDRA_DIR/Ghidra/Framework/Help/lib/Help.jar" \ + -DgroupId=ghidra -DartifactId=Help -Dversion=$GHIDRA_VERSION -Dpackaging=jar + + # Install Feature JARs + mvn -q install:install-file -Dfile="$GHIDRA_DIR/Ghidra/Features/Base/lib/Base.jar" \ + -DgroupId=ghidra -DartifactId=Base -Dversion=$GHIDRA_VERSION -Dpackaging=jar + mvn -q install:install-file -Dfile="$GHIDRA_DIR/Ghidra/Features/Decompiler/lib/Decompiler.jar" \ + -DgroupId=ghidra -DartifactId=Decompiler -Dversion=$GHIDRA_VERSION -Dpackaging=jar + mvn -q install:install-file -Dfile="$GHIDRA_DIR/Ghidra/Features/PDB/lib/PDB.jar" \ + -DgroupId=ghidra -DartifactId=PDB -Dversion=$GHIDRA_VERSION -Dpackaging=jar + mvn -q install:install-file -Dfile="$GHIDRA_DIR/Ghidra/Features/FunctionID/lib/FunctionID.jar" \ + -DgroupId=ghidra -DartifactId=FunctionID -Dversion=$GHIDRA_VERSION -Dpackaging=jar + + echo "āœ… Installed Ghidra JARs to Maven local repository" + + - name: Build with Maven + run: mvn clean package assembly:single -q -DskipTests + + - name: Verify build artifacts + run: | + echo "āœ… Java compilation successful" + ls -la target/GhidraMCP-*.zip 2>/dev/null || echo "No zip artifact (assembly may use different name)" + ls -la target/*.jar 2>/dev/null | head -5 + # Note: All Java tests (EndpointRegistrationTest, GhidraMCPPluginTest) are integration + # tests that require a running Ghidra instance with the plugin loaded. They cannot run + # in CI. Compilation verification is the CI gate for Java changes. + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v4 + with: + name: java-test-results + path: target/surefire-reports/ + + python-tests: + name: Python Tests (pytest) + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [ '3.10', '3.11', '3.12', '3.13' ] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + cache: 'pip' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -q -r requirements-test.txt 2>/dev/null || echo "requirements-test.txt not found" + pip install -q -r requirements.txt 2>/dev/null || echo "requirements.txt not found" + + - name: Run Python unit tests + run: | + # Run only unit tests (integration tests require a running MCP server) + # Includes: tool function tests, endpoint catalog consistency, response schema validation + pytest tests/unit/ -v --no-cov --tb=short + + - name: Upload coverage + if: always() + uses: codecov/codecov-action@v5 + with: + files: ./coverage.xml + flags: unittests + fail_ci_if_error: false + + code-quality: + name: Code Quality Checks + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.10' + + - name: Install quality tools + run: | + pip install -q pylint flake8 black isort 2>/dev/null || true + + - name: Run flake8 + run: flake8 bridge_mcp_ghidra.py --max-line-length=120 --ignore=E501,W503 || true + + - name: Check formatting with black + run: black --check bridge_mcp_ghidra.py 2>/dev/null || echo "black check skipped" + + markdown-lint: + name: Documentation Quality + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Lint markdown + uses: DavidAnson/markdownlint-cli2-action@v19 + with: + globs: '**/*.md' + config: '.markdownlintrc' + continue-on-error: true + + build-status: + name: Build Status + runs-on: ubuntu-latest + needs: [ java-build, python-tests ] + if: always() + + steps: + - name: Report Status + run: | + if [ "${{ needs.java-build.result }}" = "success" ] && [ "${{ needs.python-tests.result }}" = "success" ]; then + echo "āœ… All tests passed" + exit 0 + else + echo "āŒ Some tests failed" + exit 1 + fi diff --git a/.gitignore b/.gitignore index 2bdf632f..4841be97 100644 --- a/.gitignore +++ b/.gitignore @@ -1,54 +1,500 @@ -# Maven target directory +# ============================================================================= +# PRODUCTION BUILD ARTIFACTS +# ============================================================================= + +# Maven target directory and build artifacts /target/ +*.jar +*.zip +*.war +*.ear +*.nar # Compiled class files *.class -# Logs +# Build directories +/build/ +/out/ +/dist/ + +# ============================================================================= +# PYTHON ENVIRONMENT AND CACHE +# ============================================================================= + +# Python bytecode +__pycache__/ +*.py[cod] +*$py.class +*.so + +# Virtual environments +.venv/ +venv/ +env/ +ENV/ +.env/ + +# Python distribution / packaging +.Python +build/ +develop-eggs/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +*.manifest +*.spec + +# ============================================================================= +# TESTING AND DEVELOPMENT +# ============================================================================= + +# Test artifacts +.pytest_cache/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +.benchmarks/ +htmlcov/ +.nyc_output +coverage.xml +*.cover +*.py,cover +.hypothesis/ + +# Test reports and logs +test-results/ +test-reports/ +*.xml +*.html + +# ============================================================================= +# LOGS AND RUNTIME FILES +# ============================================================================= + +# Application logs *.log +logs/*.log +logs/*.json +logs/production_deploy_*.log +logs/advanced_dev_cycle_*.log +logs/comprehensive_mcp_test_*.json +logs/documentation_evaluation_*.json -# IDE files -# IntelliJ +# Keep log directory structure but ignore contents +logs/* +!logs/.gitkeep +!logs/README.md + +# Runtime and temporary files +*.tmp +*.temp +*.swp +*.swo +*~ +.DS_Store +._.DS_Store +.Trashes +.fuse_hidden* + +# ============================================================================= +# IDE AND EDITOR FILES +# ============================================================================= + +# IntelliJ IDEA .idea/ *.iml *.iws +*.ipr out/ # Eclipse .project .classpath .settings/ +.metadata/ bin/ +tmp/ # VS Code .vscode/ +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +# NetBeans +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +# Sublime Text +*.tmlanguage.cache +*.tmPreferences.cache +*.stTheme.cache +*.sublime-workspace +*.sublime-project + +# Vim +*.swp +*.swo +*~ + +# Emacs +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + +# ============================================================================= +# SYSTEM FILES +# ============================================================================= + +# Windows +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db +*.stackdump +[Dd]esktop.ini +$RECYCLE.BIN/ +*.cab +*.msi +*.msix +*.msm +*.msp +*.lnk # macOS .DS_Store .AppleDouble .LSOverride - -# Thumbnails +Icon ._* - -# macOS metadata files .Spotlight-V100 .Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent +.fseventsd +.TemporaryItems +.apdisk + +# Linux +*~ +.directory +.fuse_hidden* +.nfs* + +# ============================================================================= +# ENVIRONMENT AND CONFIGURATION +# ============================================================================= + +# Environment files +.env +.env.* +!.env.template +.envrc + +# Configuration overrides +config/local.properties +application-local.yml +application-local.yaml + +# ============================================================================= +# SECURITY AND SENSITIVE DATA +# ============================================================================= + +# Keys and certificates +*.key +*.pem +*.crt +*.p12 +*.pfx +secrets/ +private/ +.ghidra-cred + +# Database files +*.db +*.sqlite +*.sqlite3 + +# ============================================================================= +# MAVEN AND JAVA +# ============================================================================= # Maven Wrapper .mvn/ !/.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ mvnw mvnw.cmd -# Environment files -.env -.env.* - -# Java crash logs (if any) +# Java crash logs hs_err_pid* replay_pid* +# ============================================================================= +# GHIDRA SPECIFIC +# ============================================================================= + +# Ghidra project files +*.gpr +*.rep/ +*.lock + +# Ghidra analysis files +*.gzf + +# ============================================================================= +# DEPLOYMENT AND PRODUCTION +# ============================================================================= + +# Deployment artifacts +deploy/ +release/ +staging/ + +# Docker +.dockerignore +Dockerfile.local +docker-compose.override.yml + +# Kubernetes +*.local.yaml +*.local.yml + +# Cloud provider configs +.aws/ +.azure/ +.gcp/ + +# ============================================================================= +# DOCUMENTATION GENERATION +# ============================================================================= + +# Generated documentation +docs/_build/ +docs/build/ +site/ +.mkdocs/ + +# ============================================================================= +# NODE.JS (if used for tooling) +# ============================================================================= + +# Dependency directories +node_modules/ +jspm_packages/ + +# npm +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Coverage directory used by tools like istanbul +coverage/ +*.lcov + +# nyc test coverage +.nyc_output + +# ============================================================================= +# PROJECT SPECIFIC EXCLUSIONS +# ============================================================================= + # Third party JAR files from Ghidra lib/*.jar +# Temporary development files +*.backup +*.bak +*.orig +*.rej +.merge_file_* +*.txt + +# Archive files +*.7z +*.dmg +*.gz +*.iso +*.rar +*.tar +*.zip + +# Runtime configuration +.claude/ +.benchmarks/ + +# Migration and temporary scripts +migrate_*.py.bak +*_backup.* +temp_* + +# Test outputs and reports +test_output/ +test-output/ +allure-results/ +allure-report/ +junit/ +reports/ + +# Performance and profiling +*.prof +*.trace +*.mem + +# ============================================================================= +# FINAL CATCH-ALL PATTERNS +# ============================================================================= + +# Any directory named 'build' at any level +**/build/ + +# Any directory named 'dist' at any level +**/dist/ + +# Any directory named 'target' at any level +**/target/ + +# Temporary directories +tmp/ +temp/ +.tmp/ +.temp/ + +# ============================================================================= +# ORDINAL FIX LOGS (Temporary - not part of repo) +# ============================================================================= + +# Ordinal fix log files (historical logs from automated fixing) +ordinal_fix_log*.txt +ordinal_fix_log.txt + +# ============================================================================= +# GENERATED GHIDRA SCRIPTS (Auto-created during function documentation) +# ============================================================================= + +# Address-specific fix/recreate scripts created by Claude during documentation +# These are one-time use scripts and should not be committed +# Note: FixFunctionParameters.java and FixFunctionParametersHeadless.java are legitimate scripts +ghidra_scripts/RecreateFunction*.java +ghidra_scripts/RecreateFUN_*.java +ghidra_scripts/RecreateFun*.java +ghidra_scripts/RecreateFunc*.java +ghidra_scripts/Recreate_*.java +ghidra_scripts/FixFunction6*.java +ghidra_scripts/FixFUN_*.java +ghidra_scripts/FixFun6*.java +ghidra_scripts/FixFunc6*.java +ghidra_scripts/Fix6fc*.java +ghidra_scripts/CreateFunctionAt*.java +ghidra_scripts/SimpleDisasm*.java +ghidra_scripts/SimpleFix*.java +ghidra_scripts/SimpleRecreate*.java +ghidra_scripts/AggressiveFix*.java +ghidra_scripts/ClearAndRecreate*.java +ghidra_scripts/ExpandFunc*.java +ghidra_scripts/ExpandFunction*.java +ghidra_scripts/CheckInstr*.java +ghidra_scripts/Debug6*.java +ghidra_scripts/DisassembleAt*.java +ghidra_scripts/InspectAddress*.java +ghidra_scripts/InspectListing*.java +ghidra_scripts/MinimalFix*.java +ghidra_scripts/QuickFix*.java +ghidra_scripts/TestSimple.java + + +# ============================================================================= +# FUNCTION HASH INDEX AND PROGRESS TRACKING +# ============================================================================= + +# Function hash index (user-specific, regenerated per binary) +function_hash_index.json + +# Completeness tracking state (local analysis state) +completeness-tracking.json + +# Worker progress files (parallel processing state) +functions-progress-worker*.json + +# ============================================================================= +# WORKFLOW LOCAL STATE FILES +# ============================================================================= + +# RE loop runtime state (project-specific, regenerated per session) +workflows/loop_state.json +workflows/learnings.md +workflows/proposals.json +workflows/community_names.json +workflows/community/*.csv +workflows/survey_*.json + +# Ghidra manager config (contains local paths) +workflows/.ghidra_manager_config.json + +# Improvement loop state (session-specific) +workflows/.improvement_state.json +workflows/.self_improvement_state.json + +# Session and quality history +workflows/.session_history.json +workflows/.quality_history.json + +# Workflow logs and reports +workflows/logs/ +workflows/reports/ + +# ============================================================================= +# TEST OUTPUT DIRECTORIES +# ============================================================================= + +# Quality reports from automated testing +quality-reports/ + +# Model comparison test output +model-comparison-output/ + +# Global data analysis reports (regenerated) +global_data_analysis_report.md + +# Windows NUL file artifacts +nul + +# ============================================================================= +# PERSONAL MEMORY (Total Recall) +# ============================================================================= + +CLAUDE.local.md diff --git a/.markdownlintrc b/.markdownlintrc new file mode 100644 index 00000000..364f6eb5 --- /dev/null +++ b/.markdownlintrc @@ -0,0 +1,7 @@ +{ + "default": true, + "MD013": false, + "MD033": false, + "MD041": false, + "MD024": { "siblings_only": true } +} diff --git a/.mcp.json b/.mcp.json new file mode 100644 index 00000000..360df454 --- /dev/null +++ b/.mcp.json @@ -0,0 +1,13 @@ +{ + "mcpServers": { + "ghidra-mcp": { + "command": "python", + "args": [ + "c:/Users/benam/source/mcp/ghidra-mcp/bridge_mcp_ghidra.py" + ], + "env": { + "GHIDRA_SERVER_URL": "http://127.0.0.1:8089/" + } + } + } +} diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..b39016e7 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,43 @@ +# AGENTS.md — ghidra-mcp Project + +You are a coding agent working on **ghidra-mcp**, a Model Context Protocol server that bridges Ghidra's reverse engineering capabilities with AI tools. + +## Project Context + +- **Repo**: https://github.com/bethington/ghidra-mcp +- **Version**: 4.2.0 +- **Language**: Java (Ghidra extension) + Python (MCP bridge) +- **Key feature**: 193 MCP tools for binary analysis, knowledge database, BSim integration, headless server support, AI documentation workflows + +## Directory Structure + +- `src/` — Java source for Ghidra extension and headless server +- `bridge_mcp_ghidra.py` — Python MCP bridge (main entry point) +- `docs/` — Documentation and workflow prompts +- `tests/` — Python unit tests and endpoint catalog +- `CHANGELOG.md` — Version history + +## Current Priorities + +1. Maintain headless server parity with GUI plugin endpoints +2. Keep `tests/endpoints.json` in sync with Java endpoint registrations +3. Maintain CI/CD pipeline health +4. Community PR reviews + +## Guidelines + +- Run tests before committing: `pytest tests/unit/ -v --no-cov` +- Build: `mvn clean package assembly:single -DskipTests` +- Quick compile check: `mvn clean compile -q` +- Follow existing code style +- Update CHANGELOG.md for user-facing changes +- Create PRs for review (don't push directly to main) +- Use `bump-version.ps1 -New X.Y.Z` to bump version across all files atomically + +## Commands + +- Build: `mvn clean package assembly:single -DskipTests` +- Quick compile: `mvn clean compile -q` +- Test (Python): `pytest tests/unit/ -v --no-cov` +- Deploy: `.\ghidra-mcp-setup.ps1` +- Version bump: `.\bump-version.ps1 -New X.Y.Z` diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..f3989d11 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,810 @@ +# Changelog - Ghidra MCP Server + +Complete version history for the Ghidra MCP Server project. + +--- + +## v4.2.0 - 2026-03-02 + +### Knowledge Database Integration + BSim + Bug Fixes + +#### Knowledge Database (5 new MCP tools) +- **`store_function_knowledge`** -- Store documented function data (name, prototype, comments, score) to PostgreSQL knowledge DB with fire-and-forget semantics +- **`query_knowledge_context`** -- Keyword search across documented functions using PostgreSQL `ILIKE`/`tsvector` full-text search. Returns relevant prior documentation to inform new function analysis +- **`store_ordinal_mapping`** -- Store ordinal-to-name mappings per binary version (e.g., D2Common.dll ordinal 10375 = GetUnitPosition) +- **`get_ordinal_mapping`** -- Look up known ordinal names by binary, version, and ordinal number +- **`export_system_knowledge`** -- Generate markdown export of documented functions grouped by game system, suitable for book chapters and content creation +- **Graceful degradation**: All knowledge tools return `{"available": false}` when DB is unreachable. Circuit breaker disables DB after 3 consecutive failures for the session. RE loop proceeds without knowledge DB. +- **Connection pool**: `psycopg2.ThreadedConnectionPool` with configurable DB host/port/credentials via `.env` file +- **Schema**: 3 new tables (`ordinal_mappings`, `documented_functions`, `propagation_log`) with full-text search indexes and `updated_at` triggers + +#### BSim Cross-Version Matching (4 new Ghidra scripts) +- **`BSimIngestProgram.java`** -- Ingest all functions from current program into BSim PostgreSQL DB. One-time per binary version. +- **`BSimQueryAndPropagate.java`** -- Query BSim for cross-version matches of a specific function, returns JSON sorted by similarity score +- **`BSimBulkQuery.java`** -- Bulk query all undocumented (FUN_*) functions against BSim DB for batch propagation +- **`BSimTestConnection.java`** -- Verify BSim PostgreSQL connectivity and return DB metadata +- **3-tier matching cascade** in RE loop: exact opcode hash (fastest) -> BSim LSH similarity (medium) -> fuzzy instruction pattern (slowest) + +#### Bug Fixes +- **Fix #44**: Enum value parsing -- Gson parses JSON integers as `Double` (0 -> 0.0), causing `Long.parseLong("0.0")` to fail silently. Replaced hand-rolled parser with `JsonHelper.parseJson()` + `Number.longValue()`. Hex strings (`0x1F`) now also accepted. +- **Improved error messages**: Enum creation with empty/invalid values now returns descriptive errors instead of silent failures + +#### Dead Code Cleanup +- Removed ~243KB of deprecated workflow modules superseded by the RE loop skill +- Deleted deprecated slash commands (`auto-document.md`, `improve-cycle.md`, `fix-issues.md`, `improve.md`) + +#### Migration Scripts +- **`scripts/apply_schema.py`** -- Apply knowledge DB schema to PostgreSQL (idempotent, handles "already exists" gracefully) +- **`scripts/migrate_learnings.py`** -- One-time migration from flat files (learnings.md, loop_state.json, community_names.json) to knowledge DB tables + +#### Counts +- 193 MCP tools, 175 GUI endpoints, 183 headless endpoints + +--- + +## v4.1.0 - 2026-03-01 + +### Parallel Multi-Binary Support + +#### Universal `program` Parameter +- **Every program-scoped MCP tool now accepts an optional `program` parameter** -- Pass `program="D2Client.dll"` to any tool to target a specific open program without calling `switch_program` first +- **Eliminates race conditions** -- Parallel requests targeting different programs no longer contend on shared `currentProgram` state +- **Backward compatible** -- Omitting `program` falls back to the current/default program, preserving existing workflows +- **Full stack coverage**: Bridge helpers (5), 136 MCP tools, 130+ GUI endpoints, 130+ headless endpoints, and all 9 service classes updated + +#### Service Layer Changes +- All service methods now accept `String programName` and resolve via `getProgramOrError(programName)` +- Backward-compatible overloads (`method(args)` delegates to `method(args, null)`) preserve internal callers +- Services updated: FunctionService, CommentService, DataTypeService, SymbolLabelService, XrefCallGraphService, DocumentationHashService, AnalysisService, MalwareSecurityService, ProgramScriptService + +#### Bridge Changes +- `safe_get`, `safe_get_json`, `safe_post`, `safe_post_json`, `make_request` all accept `program=` kwarg +- GET helpers inject `program` into query params; POST helpers append `?program=X` to URL +- `switch_program` docstring updated: now documented as setting the default fallback, with explicit `program=` recommended for parallel workflows + +#### Counts +- 188 MCP tools, 169 GUI endpoints, 173 headless endpoints + +--- + +## v4.0.0 - 2026-02-28 + +### Major Release -- Service Layer Architecture Refactor + +#### Architecture Refactor +- **Monolith decomposition**: Extracted shared business logic from `GhidraMCPPlugin.java` (16,945 lines) into 12 focused service classes under `com.xebyte.core/` +- **Plugin reduced 69%**: `GhidraMCPPlugin.java` went from 16,945 to 5,273 lines (server lifecycle, HTTP wiring, and GUI-only endpoints remain) +- **Headless reduced 67%**: `HeadlessEndpointHandler.java` went from 6,452 to 2,153 lines by delegating to the same shared services +- **Zero breaking changes**: All HTTP endpoint paths, parameter names, and JSON response formats are unchanged. The MCP bridge and all clients work without modification + +#### New Service Classes +- `ServiceUtils` -- shared static utilities (escapeJson, paginateList, resolveDataType, convertNumber) +- `ListingService` -- listing/enumeration endpoints (list_methods, list_functions, list_classes, etc.) +- `FunctionService` -- decompilation, rename, prototype, variable management, batch operations +- `CommentService` -- decompiler/disassembly/plate comments +- `SymbolLabelService` -- labels, data rename, globals, external locations +- `XrefCallGraphService` -- cross-references, call graphs +- `DataTypeService` -- struct/enum/union CRUD, validation, field analysis +- `AnalysisService` -- completeness analysis, control flow, similarity, analyzers +- `DocumentationHashService` -- function hashing, cross-binary documentation +- `MalwareSecurityService` -- anti-analysis detection, IOCs, malware behaviors +- `ProgramScriptService` -- program management, scripts, memory, bookmarks, metadata + +#### New Feature +- **Auto-analyze on open_program**: `open_program` endpoint now accepts optional `auto_analyze=true` parameter to trigger Ghidra's auto-analysis after opening a program (inspired by PR #42 from @heeen) + +#### Counts +- 184 MCP tools, 169 GUI endpoints, 173 headless endpoints + +#### Design Decisions +- Instance-based services with constructor injection (`ProgramProvider` + `ThreadingStrategy`) +- GUI mode uses `GuiProgramProvider` + `SwingThreadingStrategy`; headless uses `HeadlessProgramProvider` + `DirectThreadingStrategy` +- Services return JSON strings (same as before); `Response` sealed interface deferred to v5.0 +- Existing `createContext()` endpoint registration pattern preserved (grep-friendly, proven) + +--- + +## v3.2.0 - 2026-02-27 + +### Bug Fixes + Version Management + +#### Bug Fixes (Cherry-picked from PR #38) +- **Fixed trailing slash in DEFAULT_GHIDRA_SERVER** -- `urljoin` path resolution was broken when the base URL ended with `/` +- **Fixed fuzzy match JSON parsing** -- `find_similar_functions_fuzzy` and `bulk_fuzzy_match` now use `safe_get_json` instead of `safe_get`, which was splitting JSON responses on newlines and destroying structure +- **Fixed OSGi class cache collisions for inline scripts** -- Inline scripts now use unique class names (`Mcp_`) per invocation instead of the fixed `_mcp_inline_` prefix, which caused the OSGi bundle resolver to cache stale classloaders + +#### Bug Fixes +- **Fixed multi-window port collision (#35)** -- Opening a second CodeBrowser window no longer crashes with "Address already in use". The HTTP server is now a static singleton shared across all plugin instances, with reference counting for clean shutdown + +#### Completeness Checker Improvements +- **New `batch_analyze_completeness` endpoint** -- Analyze multiple functions in a single call, avoiding per-function HTTP overhead. Accepts JSON array of addresses, returns all scores at once +- **Thunk comment density fix** -- Thunk stubs are no longer penalized for low inline comment density (thunks are single JMP instructions with no code to comment) +- **Thunk comment density recommendations** -- `generateWorkflowRecommendations` no longer suggests adding inline comments to thunk functions +- **Ordinal_ auto-generated name detection** -- `isAutoGeneratedName()` helper now covers FUN_, Ordinal_, thunk_FUN_, thunk_Ordinal_ prefixes across all checker endpoints +- **Callee-based ordinal detection** -- `undocumented_ordinals` now uses `func.getCalledFunctions()` instead of text scanning, eliminating false positives from self-references and caller mentions in plate comments +- **Thunk variable skip** -- Thunks with no local variables skip all body-projected decompiler artifacts +- **Relaxed thunk plate comment validation** -- Thunks only need to identify as forwarding stubs, not include full Algorithm/Parameters/Returns sections + +#### Infrastructure +- **Fixed ENDPOINT_COUNT** -- Corrected from 146 to 149 to match actual `createContext` registration count +- **Centralized version in extension.properties** -- Description now uses `${project.version}` Maven filtering instead of hardcoded version string +- **Expanded bump-version.ps1** -- Now covers 11 files (up from 7): added README badge, AGENTS.md, docs/releases/README.md. Extension.properties is now Maven-dynamic. +- **Version consistency audit** -- Fixed stale 3.0.0 references across ghidra-mcp-setup.ps1, tests/endpoints.json, README.md, AGENTS.md, and docs/releases/README.md + +--- + +## v3.1.0 - 2026-02-26 + +### Feature Release -- Server Control Menu + Completeness Checker Fixes + +#### New Features +- **Tools > GhidraMCP server control menu** -- Start/stop/restart the HTTP server from Ghidra's Tools menu with status indicator +- **Deployment automation** -- TCD auto-activation patches tool config for plugin auto-enable; AutoOpen launches project on Ghidra startup; ServerPassword auto-fills server auth dialog +- **Batch workflow improvements** -- Strengthened dispatch prompt with explicit storage type resolution instructions; added practical note for p-prefix pointer pattern + +#### Bug Fixes +- **Completeness checker: register-only SSA variables** -- Variables with `unique:` storage that can't be renamed/retyped via Ghidra API are now tracked as unfixable, boosting `effective_score` accordingly +- **Completeness checker: ordinal PRE_COMMENT detection** -- Ordinals documented via `set_decompiler_comment` appear on the line above the code in decompiled output; checker now checks previous line for PRE_COMMENT +- **Completeness checker: Hungarian notation types** -- Added `dword`/`uint` (dw), `word`/`ushort` (w), `qword`/`ulonglong` (qw), `BOOL` (f) to expected prefix mappings +- **CI Help.jar fix** -- Added Help.jar dependency to all CI workflow configurations (build.yml, release.yml, tests.yml) +- **Dropped Python 3.8/3.9** -- CI matrix now targets Python 3.10+ only + +--- + +## v3.0.0 - 2026-02-23 + +### Major Release — Headless Server Parity + New Tool Categories + +#### šŸ–„ļø Headless Server Expansion +- **Full headless parity**: Ported 50+ endpoints from GUI plugin to headless server +- All analysis, batch operation, and documentation endpoints now available without Ghidra GUI +- Script execution (`run_ghidra_script`, `run_script_inline`) works headlessly via `GhidraScriptUtil` +- New `exitServer()` endpoint for graceful headless shutdown + +#### šŸ“ Project Lifecycle (New Category) +- `create_project` — create a new Ghidra project programmatically +- `delete_project` — delete a project by path +- `list_projects` — enumerate Ghidra projects in a directory +- `open_project` / `close_project` — now exposed as MCP tools + +#### šŸ—‚ļø Project Organization (New Category) +- `create_folder` — create folders in project tree +- `move_file` / `move_folder` — reorganize project contents +- `delete_file` — remove domain files from project + +#### šŸ”— Server Connection (New Category) +- `connect_server` / `disconnect_server` — manage Ghidra Server connections +- `server_status` — check server connectivity +- `list_repositories` / `create_repository` — repository management + +#### šŸ“Œ Version Control (New Category) +- `checkout_file` / `checkin_file` — file version control operations +- `undo_checkout` / `add_to_version_control` — checkout management + +#### šŸ“œ Version History (New Category) +- `get_version_history` — full version history for a file +- `get_checkouts` — active checkout status +- `get_specific_version` — open a specific historical version + +#### šŸ‘¤ Admin (New Category) +- `terminate_checkout` — admin checkout termination +- `list_server_users` — enumerate server users +- `set_user_permissions` — manage user access levels + +#### āš™ļø Analysis Control (New Category) +- `list_analyzers` — enumerate available Ghidra analyzers +- `configure_analyzer` — enable/disable and configure analyzers +- `run_analysis` — trigger analysis programmatically + +#### šŸ”§ Infrastructure +- **`bump-version.ps1`**: Single-command version bump across all 7 project files +- **`tests/unit/`**: New unit test suite — endpoint catalog consistency, MCP tool functions, response schemas +- **`.markdownlintrc`**: Markdown lint config for CI quality gate +- **`mcp-config.json`**: Fixed env key to match bridge (`GHIDRA_SERVER_URL`) +- Tool count: 179 MCP tools (up from 110), 147 GUI endpoints, 172 headless endpoints + +#### šŸ”Œ GUI Plugin Additions +- `/get_function_count` — quick function count without full listing +- `/search_strings` — regex/substring search over defined strings, returns JSON +- `/list_analyzers` — enumerate all analyzers with enabled/disabled state +- `/run_analysis` — trigger Ghidra auto-analysis programmatically +- `get_function_count` MCP bridge tool added + +--- + +## v2.0.2 - 2026-02-20 + +### Patch Release - Ghidra 12.0.3 Support, Pagination for Large Functions + +#### šŸš€ Ghidra 12.0.3 Support (PR #29) +- **Full compatibility** with Ghidra 12.0.3 (released Feb 11, 2026) +- Updated `pom.xml` target version +- Updated Docker build configuration +- Updated all GitHub Actions workflows +- Updated documentation and setup scripts +- Fixes issue #14 for users on latest Ghidra + +#### šŸ“„ Pagination for Large Functions (PR #30) +- **New `offset` and `limit` parameters** for `decompile_function()` and `disassemble_function()` +- Prevents LLM context overflow when working with large functions +- Pagination metadata header shows total lines and next offset +- Backward compatible — only applies when parameters are specified +- Fixes issue #7 + +**Example usage:** +```python +# Get first 100 lines +code = decompile_function(address='0x401000', offset=0, limit=100) + +# Get next chunk +code = decompile_function(address='0x401000', offset=100, limit=100) +``` + +**Response includes metadata:** +```c +/* PAGINATION: lines 1-100 of 523 (use offset=100 for next chunk) */ +``` + +--- + +## v2.0.1 - 2026-02-19 + +### Patch Release - CI Fixes, Documentation, PowerShell Improvements + +#### šŸ”§ CI/Build Fixes +- **Fixed CI workflow**: Ghidra JARs now properly installed to Maven repository instead of just copied to lib/ (PR #23) +- **Proper Maven dependency management**: Works correctly with pom.xml changes from v2.0.0 +- **Version as single source of truth**: `ghidra.version` now uses Maven filtering from pom.xml (PR #20) +- **Endpoint count updated**: Correctly reports 144 endpoints + +#### šŸ“ Documentation +- **New troubleshooting section**: Comprehensive guide for common setup issues (PR #22) +- **Verification steps**: Added curl commands to verify server is working +- **Better error guidance**: Covers 500 errors, 404s, missing menus, and installation issues + +#### šŸ–„ļø PowerShell Setup Script +- **Fixed version sorting bug**: Now uses semantic version sorting instead of string sorting (PR #21) +- **Correct Ghidra detection**: Properly selects `ghidra_12.0.2_PUBLIC` over `ghidra_12.0_PUBLIC` +- Fixes issue #19 + +#### 🐳 Docker Integration +- Added as submodule to [re-universe](https://github.com/bethington/re-universe) platform +- Enables AI-assisted analysis alongside BSim similarity matching + +--- + +## v2.0.0 - 2026-02-03 + +### Major Release - Security, Ghidra 12.0.2, Enhanced Documentation + +#### šŸ”’ Security +- **Localhost binding**: HTTP server now binds to `127.0.0.1` instead of `0.0.0.0` in both GUI plugin and headless server — prevents accidental network exposure on shared networks +- Addresses the same concern as [LaurieWired/GhidraMCP#125](https://github.com/LaurieWired/GhidraMCP/issues/125) + +#### āš™ļø Configurable Decompile Timeout +- New optional `timeout` parameter on `/decompile_function` endpoint +- Defaults to 60s — no behavior change for existing callers +- Allows longer timeouts for complex functions (e.g., `?timeout=300`) + +#### šŸ·ļø Label Deletion Endpoints +- **New `delete_label` tool**: Delete individual labels at specified addresses +- **New `batch_delete_labels` tool**: Efficiently delete multiple labels in a single atomic operation +- Essential for cleaning up orphan labels after applying array types to pointer tables + +#### šŸ”§ Environment Configuration +- New `.env.template` with `GHIDRA_PATH` and other environment-specific settings +- Deploy script reads `.env` file — no more hardcoded paths +- Auto-detection of Ghidra installation from common paths +- Python bridge respects `GHIDRA_SERVER_URL` environment variable + +#### šŸš€ Ghidra 12.0.2 Support +- Updated all dependencies and paths for Ghidra 12.0.2 +- Updated library dependency documentation (14 required JARs) + +#### šŸ› ļø Tool Count +- **Total MCP Tools**: 110 fully implemented +- **Java REST Endpoints**: 133 (includes internal endpoints) +- **New tools added**: 2 (delete_label, batch_delete_labels) + +#### šŸ“š Documentation +- Complete README rewrite with full tool listing organized by category +- Added architecture overview, library dependency table, and project structure +- Reorganized API documentation by category +- Added comprehensive contributing guidelines + +#### 🧪 Testing +- New unit tests for bridge utilities (`test_bridge_utils.py`) +- New unit tests for MCP tools (`test_mcp_tools.py`) +- Updated CI workflow to latest GitHub Actions versions + +#### 🧹 Cleanup +- Removed superseded files: `cross_version_matcher.py`, `cross_version_verifier.py` (replaced by hash index system in v1.9.4) +- Removed stale data files: `hash_matches_*.json`, `string_anchors.json`, `docs/KNOWN_ORDINALS.md` +- Refactored workflow engine (`continuous_improvement.py`, `ghidra_manager.py`) + +--- + +## v1.9.4 - 2025-12-03 + +### Function Hash Index Release + +#### šŸ”— Cross-Binary Documentation Propagation +- **Function Hash Index System**: Hash-based matching of identical functions across different binaries +- **New Java Endpoints**: + - `GET /get_function_hash` - Compute SHA-256 hash of normalized function opcodes + - `GET /get_bulk_function_hashes` - Paginated bulk hashing with filter (documented/undocumented/all) + - `GET /get_function_documentation` - Export complete function documentation (name, prototype, plate comment, parameters, locals, comments, labels) + - `POST /apply_function_documentation` - Import documentation to target function +- **New Python MCP Tools**: + - `get_function_hash` - Single function hash retrieval + - `get_bulk_function_hashes` - Bulk hashing with pagination + - `get_function_documentation` - Export function docs as JSON + - `apply_function_documentation` - Apply docs to target function + - `build_function_hash_index` - Build persistent JSON index from programs + - `lookup_function_by_hash` - Find matching functions in index + - `propagate_documentation` - Apply docs to all matching instances + +#### 🧮 Hash Normalization Algorithm +- Normalizes opcodes for position-independent matching across different base addresses +- **Internal jumps**: `REL+offset` (relative to function start) +- **External calls**: `CALL_EXT` placeholder +- **External data refs**: `DATA_EXT` placeholder +- **Small immediates** (<0x10000): Preserved as `IMM:value` +- **Large immediates**: Normalized to `IMM_LARGE` +- **Registers**: Preserved (part of algorithm logic) + +#### āœ… Verified Cross-Version Matching +- Tested D2Client.dll 1.07 → 1.08: **1,313 undocumented functions** match documented functions +- Successfully propagated `ConcatenatePathAndWriteFile` documentation across versions +- Identical functions produce matching hashes despite different base addresses + +#### šŸ›  Tool Count +- **Total MCP Tools**: 118 (112 implemented + 6 ROADMAP v2.0) +- **New tools added**: 7 (4 Java endpoints + 3 Python index management tools) + +--- + +## v1.9.3 - 2025-11-14 + +### Documentation & Workflow Enhancement Release + +#### šŸ“š Documentation Organization +- **Organized scattered markdown files**: Moved release files to proper `docs/releases/` structure +- **Created comprehensive navigation**: Added `docs/README.md` with complete directory structure +- **Enhanced release documentation**: Added `docs/releases/README.md` with version index +- **Streamlined project structure**: Moved administrative docs to `docs/project-management/` + +#### šŸ”§ Hungarian Notation Improvements +- **Enhanced pointer type coverage**: Added comprehensive double pointer types (`void **` → `pp`, `char **` → `pplpsz`) +- **Added const pointer support**: New rules for `const char *` → `lpcsz`, `const void *` → `pc` +- **Windows SDK integration**: Added mappings for `LPVOID`, `LPCSTR`, `LPWSTR`, `PVOID` +- **Fixed spacing standards**: Corrected `char **` notation (removed spaces) +- **Array vs pointer clarity**: Distinguished stack arrays from pointer parameters + +#### šŸŽÆ Variable Renaming Workflow +- **Comprehensive variable identification**: Mandated examining both decompiled and assembly views +- **Eliminated pre-filtering**: Attempt renaming ALL variables regardless of name patterns +- **Enhanced failure handling**: Use `variables_renamed` count as sole reliability indicator +- **Improved documentation**: Better comment examples for non-renameable variables + +#### šŸ›  Build & Development +- **Fixed Ghidra script issues**: Resolved class name mismatches and deprecated API usage +- **Improved workflow efficiency**: Streamlined function documentation processes +- **Enhanced type mapping**: More precise Hungarian notation type-to-prefix mapping + +--- + +## v1.9.2 - 2025-11-07 + +### Documentation & Organization Release + +**Focus**: Project organization, documentation standardization, and production release preparation + +#### šŸŽÆ Major Improvements + +**Documentation Organization:** +- āœ… Created comprehensive `PROJECT_STRUCTURE.md` documenting entire project layout +- āœ… Consolidated `DOCUMENTATION_INDEX.md` merging duplicate indexes +- āœ… Enhanced `scripts/README.md` with categorization and workflows +- āœ… Established markdown naming standards (`MARKDOWN_NAMING.md`) +- āœ… Organized 40+ root-level files into clear categories + +**Project Structure:** +- āœ… Categorized all files by purpose (core, build, data, docs, scripts, tools) +- āœ… Created visual directory trees with emoji icons for clarity +- āœ… Defined clear guidelines for adding new files +- āœ… Documented access patterns and usage workflows +- āœ… Prepared 3-phase reorganization plan for future improvements + +**Standards & Conventions:** +- āœ… Established markdown file naming best practices (kebab-case) +- āœ… Defined special file naming rules (README.md, CHANGELOG.md, etc.) +- āœ… Created quick reference guides and checklists +- āœ… Documented directory-specific naming patterns +- āœ… Set up migration strategy for existing files + +**Release Preparation:** +- āœ… Created comprehensive release checklist (`RELEASE_CHECKLIST_v1.9.2.md`) +- āœ… Verified version consistency across project (pom.xml 1.9.2) +- āœ… Updated all documentation references +- āœ… Prepared release notes and changelog +- āœ… Ensured production-ready state + +#### šŸ“š New Documentation Files + +| File | Purpose | Lines | +|------|---------|-------| +| `PROJECT_STRUCTURE.md` | Complete project organization guide | 450+ | +| `DOCUMENTATION_INDEX.md` | Consolidated master index | 300+ | +| `ORGANIZATION_SUMMARY.md` | Documentation of organization work | 350+ | +| `MARKDOWN_NAMING.md` | Quick reference for naming standards | 120+ | +| `.github/MARKDOWN_NAMING_GUIDE.md` | Comprehensive naming guide | 320+ | +| `scripts/README.md` (enhanced) | Scripts directory documentation | 400+ | +| `RELEASE_CHECKLIST_v1.9.2.md` | Release preparation checklist | 300+ | + +#### šŸ”§ Infrastructure Updates + +- āœ… Version consistency verification across all files +- āœ… Build configuration validated (Maven 3.9+, Java 21) +- āœ… Plugin deployment verified with Ghidra 11.4.2 +- āœ… Python dependencies current (`requirements.txt`) +- āœ… All core functionality tested and working + +#### āœ… Quality Metrics + +- **Documentation coverage**: 100% (all directories documented) +- **Version consistency**: Verified (pom.xml 1.9.2 is source of truth) +- **Build success rate**: 100% (clean builds passing) +- **API tool count**: 111 tools (108 analysis + 3 lifecycle) +- **Test coverage**: 53/53 read-only tools verified functional + +#### šŸ“Š Organization Achievements + +**Before November 2025:** +- 50+ files cluttered in root directory +- 2 separate documentation indexes (duplicate) +- Unclear file categorization +- No scripts directory documentation +- Difficult navigation and discovery + +**After November 2025:** +- 40 organized root files with clear categories +- 1 consolidated master documentation index +- Complete project structure documentation +- Comprehensive scripts README with categorization +- Task-based navigation with multiple entry points +- Visual directory trees for clarity +- Established naming conventions and standards + +#### šŸš€ Production Readiness + +- āœ… **Build System**: Maven clean package succeeds +- āœ… **Plugin Deployment**: Loads successfully in Ghidra 11.4.2 +- āœ… **API Endpoints**: All 111 tools functional +- āœ… **Documentation**: 100% coverage with cross-references +- āœ… **Testing**: Core functionality verified +- āœ… **Organization**: Well-structured and maintainable + +--- + +## v1.8.4 - 2025-10-26 + +### Bug Fixes & Improvements - Read-Only Tools Testing + +**Critical Fixes:** +- āœ… **Fixed silent failures in `get_xrefs_to` and `get_xrefs_from`** + - Previously returned empty output when no xrefs found + - Now returns descriptive message: "No references found to/from address: 0x..." + - Affects: Java plugin endpoints (lines 3120-3167) + +- āœ… **Completed `get_assembly_context` implementation** + - Replaced placeholder response with actual assembly instruction retrieval + - Returns context_before/context_after arrays with surrounding instructions + - Adds mnemonic field and pattern detection (data_access, comparison, arithmetic, etc.) + - Affects: Java plugin getAssemblyContext() method (lines 7223-7293) + +- āœ… **Completed `batch_decompile_xref_sources` usage extraction** + - Replaced placeholder "usage_line" with actual code line extraction + - Returns usage_lines array showing how target address is referenced in decompiled code + - Adds xref_addresses array showing specific instruction addresses + - Affects: Java plugin batchDecompileXrefSources() method (lines 7362-7411) + +**Quality Improvements:** +- āœ… **Improved `list_strings` filtering** + - Added minimum length filter (4+ characters) + - Added printable ratio requirement (80% printable ASCII) + - Filters out single-byte hex strings like "\x83" + - Returns meaningful message when no quality strings found + - Affects: Java plugin listDefinedStrings() and new isQualityString() method (lines 3217-3272) + +- āœ… **Fixed `list_data_types` category filtering** + - Previously only matched category paths (file names like "crtdefs.h") + - Now also matches data type classifications (struct, enum, union, typedef, pointer, array) + - Added new getDataTypeName() helper to determine type classification + - Searching for "struct" now correctly returns Structure data types + - Affects: Java plugin listDataTypes() and getDataTypeName() methods (lines 4683-4769) + +### Testing +- Systematically tested all **53 read-only MCP tools** against D2Client.dll +- **100% success rate** across 6 categories: + - Metadata & Connection (3 tools) + - Listing (14 tools) + - Get/Query (10 tools) + - Analysis (12 tools) + - Search (5 tools) + - Advanced Analysis (9 tools) + +### Impact +- More robust error handling with descriptive messages instead of silent failures +- Completion of previously stubbed implementations +- Better string detection quality (fewer false positives) +- Type-based data type filtering now works as expected +- All read-only tools verified functional and returning valid data + +--- + +## v1.8.3 - 2025-10-26 + +### Removed Tools - API Cleanup +- āŒ **Removed 3 redundant/non-functional MCP tools** (108 → 105 tools) + - `analyze_function_complexity` - Never implemented, returned placeholder JSON only + - `analyze_data_types` - Superseded by comprehensive `analyze_data_region` tool + - `auto_create_struct_from_memory` - Low-quality automated output, better workflow exists + +### Rationale +- **analyze_function_complexity**: Marked "not yet implemented" for multiple versions, no demand +- **analyze_data_types**: Basic 18-line implementation completely replaced by `analyze_data_region` (200+ lines, comprehensive batch operation with xref mapping, boundary detection, stride analysis) +- **auto_create_struct_from_memory**: Naive field inference produced generic field_0, field_4 names without context; better workflow is `analyze_data_region` → manual `create_struct` with meaningful names + +### Impact +- Cleaner API surface with less confusion +- Removed dead code from both Python bridge and Java plugin +- No breaking changes for active users (tools were redundant or non-functional) +- Total MCP tools: **105 analysis + 6 script lifecycle = 111 tools** + +--- + +## v1.8.2 - 2025-10-26 + +### New External Location Management Tools +- āœ… **Three New MCP Tools** - External location management for ordinal import fixing + - `list_external_locations()` - List all external locations (imports, ordinal imports) + - `get_external_location()` - Get details about specific external location + - `rename_external_location()` - Rename ordinal imports to actual function names + - Enables mass fixing of broken ordinal-based imports when DLL functions change + +### New Documentation +- āœ… **`EXTERNAL_LOCATION_TOOLS.md`** - Complete API reference for external location tools + - Full tool signatures and parameters + - Use cases and examples + - Integration with ordinal restoration workflow + - Performance considerations and error handling +- āœ… **`EXTERNAL_LOCATION_WORKFLOW.md`** - Quick-start workflow guide + - Step-by-step workflow (5-15 minutes) + - Common patterns and code examples + - Troubleshooting guide + - Performance tips for large binaries + +### Implementation Details +- Added `listExternalLocations()` method to Java plugin (lines 10479-10509) +- Added `getExternalLocationDetails()` method to Java plugin (lines 10511-10562) +- Added `renameExternalLocation()` method to Java plugin (lines 10567-10626) +- Added corresponding HTTP endpoints for each method +- Fixed Ghidra API usage for ExternalLocationIterator and namespace retrieval +- All operations use Swing EDT for thread-safe Ghidra API access + +**Impact**: Complete workflow for fixing ordinal-based imports - essential for binary analysis when external DLL functions change or ordinals shift + +--- + +## v1.8.1 - 2025-10-25 + +### Documentation Reorganization +- āœ… **Project Structure Overhaul** - Cleaned and reorganized entire documentation + - Consolidated prompts: 12 files → 8 focused workflow files + - Created `docs/examples/` with punit/ and diablo2/ subdirectories + - Moved structure discovery guides to `docs/guides/` + - Created comprehensive `START_HERE.md` with multiple learning paths + - Updated `DOCUMENTATION_INDEX.md` to reflect new structure + - Removed ~70 obsolete files (old reports, duplicates, summaries) + +### New Calling Convention +- āœ… **__d2edicall Convention** - Diablo II EDI-based context passing + - Documented in `docs/conventions/D2CALL_CONVENTION_REFERENCE.md` + - Applied to BuildNearbyRoomsList function + - Installed in x86win.cspec + +### Bug Fixes +- āœ… **Fixed DocumentFunctionWithClaude.java** - Windows compatibility + - Resolved "claude: CreateProcess error=2" + - Now uses full path: `%APPDATA%\npm\claude.cmd` + - Changed keybinding from Ctrl+Shift+D to Ctrl+Shift+P + +### New Files & Tools +- āœ… **ghidra_scripts/** - Example Ghidra scripts + - `DocumentFunctionWithClaude.java` - AI-assisted function documentation + - `ClearCallReturnOverrides.java` - Clean orphaned flow overrides +- āœ… **mcp-config.json** - Claude MCP configuration template +- āœ… **mcp_function_processor.py** - Batch function processing automation +- āœ… **scripts/hybrid-function-processor.ps1** - Automated analysis workflows + +### Enhanced Documentation +- āœ… **examples/punit/** - Complete UnitAny structure case study (8 files) +- āœ… **examples/diablo2/** - Diablo II structure references (2 files) +- āœ… **conventions/** - Calling convention documentation (5 files) +- āœ… **guides/** - Structure discovery methodology (4 files) + +### Cleanup +- āŒ Removed obsolete implementation/completion reports +- āŒ Removed duplicate function documentation workflows +- āŒ Removed old D2-specific installation guides +- āŒ Removed temporary Python scripts and cleanup utilities + +**Impact**: Better organization, easier navigation, reduced duplication, comprehensive examples + +**See**: Tag [v1.8.1](https://github.com/bethington/ghidra-mcp/releases/tag/v1.8.1) + +--- + +## v1.8.0 - 2025-10-16 + +### Major Features +- āœ… **6 New Structure Field Analysis Tools** - Comprehensive struct field reverse engineering + - `analyze_struct_field_usage` - Analyze field access patterns across functions + - `get_field_access_context` - Get assembly/decompilation context for specific field offsets + - `suggest_field_names` - AI-assisted field naming based on usage patterns + - `inspect_memory_content` - Read raw bytes with string detection heuristics + - `get_bulk_xrefs` - Batch xref retrieval for multiple addresses + - `get_assembly_context` - Get assembly instructions with context for xref sources + +### Documentation Suite +- āœ… **6 Comprehensive Reverse Engineering Guides** (in `docs/guides/`) + - CALL_RETURN_OVERRIDE_CLEANUP.md - Flow override debugging + - EBP_REGISTER_REUSE_SOLUTIONS.md - Register reuse pattern analysis + - LIST_DATA_BY_XREFS_GUIDE.md - Data analysis workflow + - NORETURN_FIX_GUIDE.md - Non-returning function fixes + - ORPHANED_CALL_RETURN_OVERRIDES.md - Orphaned override detection + - REGISTER_REUSE_FIX_GUIDE.md - Complete register reuse fix workflow + +- āœ… **Enhanced Prompt Templates** (in `docs/prompts/`) + - PLATE_COMMENT_EXAMPLES.md - Real-world examples + - PLATE_COMMENT_FORMAT_GUIDE.md - Best practices + - README.md - Prompt documentation index + - OPTIMIZED_FUNCTION_DOCUMENTATION.md - Enhanced workflow + +### Utility Scripts +- āœ… **9 Reverse Engineering Scripts** (in `scripts/`) + - ClearCallReturnOverrides.java - Clear orphaned flow overrides + - b_extract_data_with_xrefs.py - Bulk data extraction + - create_d2_typedefs.py - Type definition generation + - populate_d2_structs.py - Structure population automation + - test_data_xrefs_tool.py - Unit tests for xref tools + - data-extract.ps1, data-process.ps1, function-process.ps1, functions-extract.ps1 - PowerShell automation + +### Project Organization +- āœ… **Restructured Documentation** + - Release notes → `docs/releases/v1.7.x/` + - Code reviews → `docs/code-reviews/` + - Analysis data → `docs/analysis/` + - Guides consolidated in `docs/guides/` + +### Changed Files +- `bridge_mcp_ghidra.py` (+585 lines) - 6 new MCP tools, enhanced field analysis +- `src/main/java/com/xebyte/GhidraMCPPlugin.java` (+188 lines) - Struct analysis endpoints +- `pom.xml` (Version 1.7.3 → 1.8.0) +- `.gitignore` - Added `*.txt` for temporary files + +**See**: Tag [v1.8.0](https://github.com/bethington/ghidra-mcp/releases/tag/v1.8.0) + +--- + +## v1.7.3 - 2025-10-13 + +### Critical Bug Fix +- āœ… **Fixed disassemble_bytes transaction commit** - Added missing `success = true` flag assignment before transaction commit, ensuring disassembled instructions are properly persisted to Ghidra database + +### Impact +- **High** - All `disassemble_bytes` operations now correctly save changes +- Resolves issue where API reported success but changes were rolled back + +### Testing +- āœ… Verified with test case at address 0x6fb4ca14 (21 bytes) +- āœ… Transaction commits successfully and persists across server restarts +- āœ… Complete verification documented in `DISASSEMBLE_BYTES_VERIFICATION.md` + +### Changed Files +- `src/main/java/com/xebyte/GhidraMCPPlugin.java` (Line 9716: Added `success = true`) +- `pom.xml` (Version 1.7.2 → 1.7.3) +- `src/main/resources/extension.properties` (Version 1.7.2 → 1.7.3) + +**See**: [v1.7.3 Release Notes](V1.7.3_RELEASE_NOTES.md) + +--- + +## v1.7.2 - 2025-10-12 + +### Critical Bug Fix +- āœ… **Fixed disassemble_bytes connection abort** - Added explicit response flushing and enhanced error logging to prevent HTTP connection abort errors + +### Documentation +- āœ… Comprehensive code review documented in `CODE_REVIEW_2025-10-13.md` +- āœ… Overall rating: 4/5 (Very Good) - Production-ready with minor improvements identified + +**See**: [v1.7.2 Release Notes](V1.7.2_RELEASE_NOTES.md) + +--- + +## v1.7.0 - 2025-10-11 + +### Major Features +- āœ… **Variable storage control** - `set_variable_storage` endpoint for fixing register reuse issues +- āœ… **Ghidra script automation** - `run_script` and `list_scripts` endpoints +- āœ… **Forced decompilation** - `force_decompile` endpoint for cache clearing +- āœ… **Flow override control** - `clear_instruction_flow_override` and `set_function_no_return` endpoints + +### Capabilities +- **Register reuse fixes** - Resolve EBP and other register conflicts +- **Automated analysis** - Execute Python/Java Ghidra scripts programmatically +- **Flow analysis control** - Fix incorrect CALL_TERMINATOR overrides + +**See**: [v1.7.0 Release Notes](V1.7.0_RELEASE_NOTES.md) + +--- + +## v1.6.0 - 2025-10-10 + +### New Features +- āœ… **7 New MCP Tools**: Validation, batch operations, and comprehensive analysis + - `validate_function_prototype` - Pre-flight validation for function prototypes + - `validate_data_type_exists` - Check if types exist before using them + - `can_rename_at_address` - Determine address type and suggest operations + - `batch_rename_variables` - Atomic multi-variable renaming with partial success + - `analyze_function_complete` - Single-call comprehensive analysis (5+ calls → 1) + - `document_function_complete` - Atomic all-in-one documentation (15-20 calls → 1) + - `search_functions_enhanced` - Advanced search with filtering, regex, sorting + +### Documentation +- āœ… **Reorganized structure**: Created `docs/guides/`, `docs/releases/v1.6.0/` +- āœ… **Renamed**: `RELEASE_NOTES.md` → `CHANGELOG.md` +- āœ… **Moved utility scripts** to `tools/` directory +- āœ… **Removed redundancy**: 8 files consolidated or archived +- āœ… **New prompt**: `FUNCTION_DOCUMENTATION_WORKFLOW.md` + +### Performance +- **93% API call reduction** for complete function documentation +- **Atomic transactions** with rollback support +- **Pre-flight validation** prevents errors before execution + +### Quality +- **Implementation verification**: 99/108 Python tools (91.7%) have Java endpoints +- **100% documentation coverage**: All 108 tools documented +- **Professional structure**: Industry-standard organization + +**See**: [v1.6.0 Release Notes](docs/releases/v1.6.0/RELEASE_NOTES.md) + +--- + +## v1.5.1 - 2025-01-10 + +### Critical Bug Fixes +- āœ… **Fixed batch_set_comments JSON parsing error** - Eliminated ClassCastException that caused 90% of batch operation failures +- āœ… **Added missing AtomicInteger import** - Resolved compilation issue + +### New Features +- āœ… **batch_create_labels endpoint** - Create multiple labels in single atomic transaction +- āœ… **Enhanced JSON parsing** - Support for nested objects and arrays in batch operations +- āœ… **ROADMAP v2.0 documentation** - All 10 placeholder tools clearly marked with implementation plans + +### Performance Improvements +- āœ… **91% reduction in API calls** - Function documentation workflow: 57 calls → 5 calls +- āœ… **Atomic transactions** - All-or-nothing semantics for batch operations +- āœ… **Eliminated user interruption issues** - Batch operations prevent hook triggers + +### Documentation Enhancements +- āœ… **Improved rename_data documentation** - Clear explanation of "defined data" requirement +- āœ… **Comprehensive ROADMAP** - Transparent status for all placeholder tools +- āœ… **Organized documentation structure** - New docs/ subdirectories for better navigation + +--- + +For older release details, see the [docs/releases/](docs/releases/) directory. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..3d70dbf9 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,165 @@ +# Ghidra MCP - Claude Code Project Guide + +## Project Overview + +Ghidra MCP is a production-ready Model Context Protocol (MCP) server that bridges Ghidra's reverse engineering capabilities with AI tools. It provides **193 MCP tools** for binary analysis automation. + +- **Package**: `com.xebyte` +- **Version**: 4.2.0 (see `pom.xml`) +- **License**: Apache 2.0 +- **Java**: 21 LTS +- **Ghidra**: 12.0.3 + +## Architecture + +``` +AI/Automation Tools <-> MCP Bridge (bridge_mcp_ghidra.py) <-> Ghidra Plugin (GhidraMCP.jar) +``` + +### Key Components + +| Component | Location | Purpose | +|-----------|----------|---------| +| Ghidra Plugin | `src/main/java/com/xebyte/GhidraMCPPlugin.java` | HTTP server + endpoint wiring (~5,270 lines), delegates to services | +| MCP Bridge | `bridge_mcp_ghidra.py` | Translates MCP protocol to HTTP calls (193 tools) | +| Headless Server | `src/main/java/com/xebyte/headless/` | Standalone server without Ghidra GUI (173 endpoints) | +| Service Layer | `src/main/java/com/xebyte/core/` | 12 shared service classes with business logic (~15K lines) | + +### Service Layer (v4.0.0) + +Business logic is in `com.xebyte.core/` service classes, shared between GUI and headless modes: + +| Service | Lines | Responsibility | +|---------|-------|----------------| +| `ServiceUtils` | ~670 | Shared static utilities (escapeJson, paginateList, convertNumber) | +| `ListingService` | ~720 | Listing/enumeration endpoints | +| `FunctionService` | ~2,400 | Decompilation, rename, prototype, batch operations | +| `CommentService` | ~430 | Decompiler/disassembly/plate comments | +| `SymbolLabelService` | ~815 | Labels, data rename, globals, external locations | +| `XrefCallGraphService` | ~1,260 | Cross-references, call graphs | +| `DataTypeService` | ~2,580 | Struct/enum/union CRUD, validation | +| `AnalysisService` | ~2,510 | Completeness, control flow, similarity | +| `DocumentationHashService` | ~1,130 | Function hashing, cross-binary docs | +| `MalwareSecurityService` | ~940 | Anti-analysis detection, IOCs | +| `ProgramScriptService` | ~1,340 | Program management, scripts, memory | +| `BinaryComparisonService` | ~1,050 | Cross-binary comparison (static methods) | + +Services use constructor injection: `ProgramProvider` + `ThreadingStrategy`. GUI uses `GuiProgramProvider` + `SwingThreadingStrategy`; headless uses `HeadlessProgramProvider` + `DirectThreadingStrategy`. + +## Build Commands + +```powershell +# Build and deploy (recommended — handles Maven, deps, and Ghidra restart) +.\ghidra-mcp-setup.ps1 -Deploy -GhidraPath "C:\ghidra_12.0.3_PUBLIC" + +# Build only (no deploy) +.\ghidra-mcp-setup.ps1 -BuildOnly + +# First-time dependency setup (install Ghidra JARs into local Maven repo) +.\ghidra-mcp-setup.ps1 -SetupDeps -GhidraPath "C:\ghidra_12.0.3_PUBLIC" +``` + +> **Note (Windows):** Maven (`mvn`) must be in your PATH or invoked via the setup script. +> Maven is at `C:\Users\\tools\apache-maven-3.9.6\bin\mvn.cmd` if installed by the setup script. + +## Running the MCP Server + +```bash +# Stdio transport (recommended for AI tools) +python bridge_mcp_ghidra.py + +# SSE transport (web/HTTP clients) +python bridge_mcp_ghidra.py --transport sse --mcp-host 127.0.0.1 --mcp-port 8081 + +# Default Ghidra HTTP endpoint +http://127.0.0.1:8089 +``` + +## Project Structure + +``` +ghidra-mcp/ +ā”œā”€ā”€ src/main/java/com/xebyte/ +│ ā”œā”€ā”€ GhidraMCPPlugin.java # Main plugin with all endpoints +│ ā”œā”€ā”€ core/ # Shared service layer (12 services) +│ └── headless/ # Headless server implementation +ā”œā”€ā”€ bridge_mcp_ghidra.py # MCP protocol bridge +ā”œā”€ā”€ ghidra_scripts/ # Ghidra scripts (Java) +ā”œā”€ā”€ docs/ +│ ā”œā”€ā”€ prompts/ # Analysis workflow prompts +│ ā”œā”€ā”€ releases/ # Release documentation +│ └── project-management/ # Project-level docs +ā”œā”€ā”€ ghidra-mcp-setup.ps1 # Deployment script +└── functions-process.ps1 # Batch function processing +``` + +## Key Documentation + +- **API Reference**: See README.md for complete tool listing (193 MCP tools) +- **Workflow Prompts**: `docs/prompts/FUNCTION_DOC_WORKFLOW_V5.md` - Function documentation workflow (V5) +- **Batch Processing**: `docs/prompts/FUNCTION_DOC_WORKFLOW_V5_BATCH.md` - Multi-function parallel documentation +- **Data Analysis**: `docs/prompts/DATA_TYPE_INVESTIGATION_WORKFLOW.md` +- **Tool Guide**: `docs/prompts/TOOL_USAGE_GUIDE.md` +- **String Labeling**: `docs/prompts/STRING_LABELING_CONVENTION.md` - Hungarian notation for string labels + +## Development Conventions + +### Code Style +- Java package: `com.xebyte` +- All endpoints return JSON +- Use batch operations where possible (93% API call reduction) +- Transactions must be committed for Ghidra database changes + +### Adding New Endpoints +1. Add handler method in `GhidraMCPPlugin.java` (GUI plugin) and/or `HeadlessEndpointHandler.java` +2. Register in `createContextsForServer()` (GUI) and/or `registerEndpoints()` (headless) +3. Add corresponding MCP tool in `bridge_mcp_ghidra.py` +4. Add entry to `tests/endpoints.json` with path, method, category, description +5. Update `total_endpoints` count in `tests/endpoints.json` + +### Testing +- Tests: `src/test/java/com/xebyte/` +- Python tests: `tests/` +- Run with: `mvn test` or `pytest tests/` + +## Ghidra Scripts + +Located in `ghidra_scripts/`. Execute via: +- `mcp_ghidra_run_script` MCP tool +- Ghidra Script Manager UI +- `analyzeHeadless` command line + +## Common Tasks + +### Function Documentation Workflow +1. Use `list_functions` to enumerate functions +2. Use `decompile_function` to get pseudocode +3. Apply naming via `rename_function`, `rename_variable` +4. Add comments via `set_plate_comment`, `set_decompiler_comment` + +### Data Type Analysis +1. Use `list_data_types` to see existing types +2. Create structures with `create_struct` +3. Apply with `apply_data_type` + +## Troubleshooting + +- **Plugin not loading**: Check `docs/troubleshooting/TROUBLESHOOTING_PLUGIN_LOAD.md` +- **Connection issues**: Verify Ghidra is running with plugin enabled on port 8089 +- **Build failures**: Install Ghidra JARs to local Maven repo (run `ghidra-mcp-setup.ps1 -SetupDeps`) + +## Version History + +See `CHANGELOG.md` for complete history. Key releases: +- v4.2.0: Knowledge database integration, BSim cross-version matching, enum fix (#44), 193 MCP tools, 175 GUI endpoints, 183 headless endpoints +- v4.1.0: Parallel multi-binary support via universal `program` parameter, 188 MCP tools, 169 GUI endpoints, 173 headless endpoints +- v4.0.0: Service layer architecture refactor (12 shared services), 69% plugin reduction, 188 MCP tools, 169 GUI endpoints, 173 headless endpoints +- v3.2.0: Completeness checker overhaul, batch_analyze_completeness endpoint, multi-window fix (#35), 180 MCP tools, 149 GUI endpoints +- v3.1.0: Tools > GhidraMCP server control menu, deployment automation, completeness checker accuracy +- v3.0.0: Headless parity, 8 new tool categories, 179 MCP tools, 147 GUI endpoints, 172 headless endpoints +- v2.0.2: Ghidra 12.0.3 support, pagination for large functions +- v2.0.0: Label deletion endpoints, documentation updates +- v1.9.4: Function Hash Index for cross-binary documentation +- v1.7.x: Transaction fixes, variable storage control +- v1.6.x: Validation tools, enhanced analysis +- v1.5.x: Batch operations, workflow optimization diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..7e604b95 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,509 @@ +# Contributing to Ghidra MCP + +Thank you for your interest in contributing to Ghidra MCP! This guide explains how to contribute tools, fixes, and improvements. + +## Quick Links + +- **Issues**: [GitHub Issues](https://github.com/bethington/ghidra-mcp/issues) +- **Discussions**: [GitHub Discussions](https://github.com/bethington/ghidra-mcp/discussions) +- **Documentation**: [DOCUMENTATION_INDEX.md](DOCUMENTATION_INDEX.md) +- **Tools Reference**: [docs/TOOL_REFERENCE.md](docs/TOOL_REFERENCE.md) + +--- + +## Types of Contributions + +### 1. Bug Reports +**When**: You found something broken + +**How**: +1. Check [existing issues](https://github.com/bethington/ghidra-mcp/issues) first +2. Create new issue with: + - Clear title: "Connection timeout when decompiling large functions" + - Environment: OS, Ghidra version, binary size + - Steps to reproduce + - Expected vs actual behavior + - Error message or logs + +**Example**: +``` +Title: Decompile timeout on binary > 10MB + +Environment: +- OS: Windows 11 +- Ghidra: 12.0.3 +- Binary: 12MB x86-64 + +Steps: +1. Load 12MB binary in Ghidra +2. Wait for analysis +3. Call decompile_function("main") + +Error: RequestTimeout after 30 seconds + +Expected: Decompilation completes or returns gracefully +``` + +--- + +### 2. Feature Requests +**When**: You want a new MCP tool or capability + +**How**: +1. Search [existing discussions](https://github.com/bethington/ghidra-mcp/discussions) +2. Open Discussion or Issue with: + - Use case: Why do you need this? + - Proposed solution + - Alternative approaches considered + - Priority (critical/high/medium/low) + +**Example**: +``` +Title: Add tool to analyze register usage patterns + +Use Case: +Need to find functions that don't follow calling convention +for obfuscation analysis + +Proposed Solution: +New tool: analyze_register_usage(function_name) +Returns: {"register_changes": {...}, "violations": [...]} + +Priority: Medium - helpful for malware analysis +``` + +--- + +### 3. Code Contributions + +#### 3a. Fix a Bug +**Steps**: + +1. Fork repository + ```bash + git clone https://github.com/YOUR-USERNAME/ghidra-mcp.git + cd ghidra-mcp + ``` + +2. Create feature branch + ```bash + git checkout -b fix/connection-timeout-issue + ``` + +3. Make changes and test + ```bash + mvn clean test # Run tests + python -m pytest tests/ # Python tests + ``` + +4. Commit with clear message + ```bash + git commit -m "Fix: Increase default timeout for large binaries + + - Changed REQUEST_TIMEOUT from 30s to 60s + - Added per-endpoint timeout configuration + - Updated documentation with timeout guidelines + + Fixes #123" + ``` + +5. Push and create Pull Request + ```bash + git push origin fix/connection-timeout-issue + ``` + +#### 3b. Add a New MCP Tool + +**Requirements**: +- Solves a real problem (check discussions first) +- Follows existing code patterns +- Includes error handling +- Has docstring with parameters/return +- Tested (manual or automated) + +**Steps**: + +1. Understand tool categories in `bridge_mcp_ghidra.py`: + ```python + @mcp.tool() + def my_new_tool(param1: str, param2: int = 0) -> dict: + """ + Brief description of what tool does. + + Args: + param1: Description + param2: Description (default: 0) + + Returns: + Dictionary with results + + Use when: Specific use case + """ + # Implementation + endpoint = "/my_endpoint" + return safe_get(endpoint, {"param1": param1, "param2": param2}) + ``` + +2. Add Java endpoint in `GhidraMCPPlugin.java`: + ```java + @Override + public void processEvent(PluginEvent event) { + if (httpServer == null) return; + + // Add route handler + httpServer.createContext("/my_endpoint", exchange -> { + String param1 = getParam(exchange, "param1"); + // Implementation + sendResponse(exchange, result); + }); + } + ``` + +3. Document in `docs/TOOL_REFERENCE.md`: + ```markdown + ### my_new_tool() + + Brief description. + + ```python + result = my_new_tool(param1="value", param2=5) + # Returns: {...} + ``` + + **Use when**: Specific use case + ``` + +4. Add example in `examples/`: + ```python + # examples/use-new-tool.py + result = my_new_tool("example") + print(result) + ``` + +5. Test and commit: + ```bash + git commit -m "feat: Add my_new_tool() for analysis + + - Implements /my_endpoint in REST API + - Adds MCP tool wrapper in Python bridge + - Includes example usage + - Tested on sample binary + + Contributes to: #456" + ``` + +#### 3c. Improve Documentation + +**What to contribute**: +- Fix typos +- Add examples +- Clarify confusing sections +- Add troubleshooting steps +- Update outdated information + +**How**: +```bash +# 1. Edit documentation +vim docs/TOOL_REFERENCE.md + +# 2. Preview if possible +cat docs/TOOL_REFERENCE.md | grep "my_section" + +# 3. Commit +git commit -m "docs: Clarify batch operation performance benefits" +``` + +--- + +## Code Style & Standards + +### Java (GhidraMCPPlugin.java) + +```java +// Use clear naming +private String analyzeFunction(String functionName) { + // Comment complex logic + + // Handle errors explicitly + try { + // Implementation + } catch (Exception e) { + logger.error("Error analyzing function: " + e.getMessage()); + return null; + } +} +``` + +### Python (bridge_mcp_ghidra.py) + +```python +@mcp.tool() +def my_tool(param: str, optional: int = 0) -> dict: + """ + Clear docstring explaining purpose. + + Args: + param: Description + optional: Description (default: 0) + + Returns: + Dictionary result + """ + try: + # Validate inputs + if not param: + raise ValueError("param cannot be empty") + + # Make request + result = safe_get("/endpoint", {"param": param}) + return result + except Exception as e: + logger.error(f"Tool error: {e}") + raise +``` + +**Style Guide**: +- PEP 8 for Python +- Use type hints +- Clear variable names (not `x`, `y`, `z`) +- Comment complex logic +- Error handling with try/except +- Logging for debugging + +--- + +## Testing + +### Java Tests +```java +// src/test/java/com/xebyte/GhidraMCPPluginTest.java + +@Test +public void testDecompileFunction() { + String result = ghidra.decompile("main"); + assertNotNull(result); + assertTrue(result.contains("void")); +} +``` + +**Run tests**: +```bash +mvn test +``` + +### Python Tests +```python +# tests/test_bridge.py + +def test_list_functions(): + functions = list_functions(limit=10) + assert isinstance(functions, list) + assert all("name" in f for f in functions) +``` + +**Run tests**: +```bash +pytest tests/ -v +``` + +**Add tests for**: +- New functionality +- Edge cases +- Error handling +- Performance critical paths + +--- + +## Pull Request Process + +1. **Before Submitting**: + - [ ] Fork and create feature branch + - [ ] Make changes following code style + - [ ] Run tests: `mvn test` and `pytest` + - [ ] Update documentation + - [ ] Test changes manually if possible + +2. **Create PR**: + ```markdown + ## Description + Brief summary of changes + + Fixes #123 + + ## Changes + - Change 1 + - Change 2 + + ## Testing + Describe testing performed + + ## Checklist + - [x] Tests added/updated + - [x] Documentation updated + - [x] No breaking changes + ``` + +3. **Review Process**: + - Maintainer reviews code + - May request changes + - Once approved, merges to main + - Included in next release + +--- + +## Contribution Ideas + +### Quick Wins (1-2 hours) +- [ ] Fix typos in documentation +- [ ] Add error handling example to docs +- [ ] Create unit test for existing tool +- [ ] Add tool to TOOL_REFERENCE.md if missing +- [ ] Update example scripts with new features + +### Medium Tasks (4-8 hours) +- [ ] Write comprehensive example script +- [ ] Add performance benchmarks +- [ ] Create troubleshooting guide section +- [ ] Improve error messages +- [ ] Add logging to problematic areas + +### Larger Features (1-2 weeks) +- [ ] Implement new MCP tool +- [ ] Add comprehensive test suite +- [ ] Create web dashboard UI +- [ ] Implement auto-update system +- [ ] Add Docker support + +--- + +## Development Setup + +### Prerequisites +- Java 21 LTS +- Apache Maven 3.9+ +- Python 3.8+ +- Ghidra 12.0.3 + +### Local Development +```bash +# 1. Clone repository +git clone https://github.com/YOUR-USERNAME/ghidra-mcp.git +cd ghidra-mcp + +# 2. Install Ghidra libraries to local Maven repo +.\ghidra-mcp-setup.ps1 -SetupDeps -GhidraPath "C:\path\to\ghidra" # Windows + +# 3. Build plugin +mvn clean package + +# 4. Install Python dependencies +pip install -r requirements.txt +pip install -r requirements-test.txt + +# 5. Run MCP server +python bridge_mcp_ghidra.py + +# 6. Run tests +mvn test +pytest tests/ -v +``` + +### Building Documentation +```bash +# Tools are auto-documented from docstrings +# Manually update docs/ folder + +# Preview markdown +cat docs/TOOL_REFERENCE.md | more + +# Check for linting errors (optional) +markdownlint docs/ +``` + +--- + +## Commit Message Convention + +``` +(): + + + +