{
  "checker": {
    "claims": [
      {
        "claim": "Ghidra MCP decompiles functions from a binary",
        "command": "<guest-path> run --python 3.13 --extra headless ghidra-mcp --headless --binary tests/fixtures/sample_x86_64.elf --extension-jar /tmp/ghidra-ext/GhidraMCP/lib/GhidraMCP.jar tools/call {\"tool\": \"decompile_function\", \"arguments\": {\"name\": \"add_numbers\"}}",
        "evidence": "return param_1 + param_2;\\\\n}\\\\n\\\\n\\\",\\n  \\\"truncated\\\": false\\n}\"}], \"structuredContent\": {\"function\": {\"name\": \"add_numbers\", \"address\": \"01001640\"}, \"code\": \"\\nint add_numbers(int param_1,int param_2)\\n\\n{\\n  return param_1 + param_2;\\n}\\n\\n\", \"truncated\": false}, \"isError\": false}",
        "expected": "decompiled C body of add_numbers",
        "input": "{\"tool\": \"decompile_function\", \"arguments\": {\"name\": \"add_numbers\"}}",
        "kind": "claim",
        "outcome": "Real input produced the expected result: return param_1 + param_2;",
        "source": "Decompile and analyze binaries in Ghidra",
        "source_checked": true,
        "source_file": "README.md",
        "verdict": "yes"
      },
      {
        "claim": "Ghidra MCP lists methods of the binary",
        "command": "<guest-path> run --python 3.13 --extra headless ghidra-mcp --headless --binary tests/fixtures/sample_x86_64.elf --extension-jar /tmp/ghidra-ext/GhidraMCP/lib/GhidraMCP.jar tools/call {\"tool\": \"list_methods\", \"arguments\": {\"offset\": 0, \"limit\": 100}}",
        "evidence": "add_numbers\"}, {\"type\": \"text\", \"text\": \"mul_numbers\"}, {\"type\": \"text\", \"text\": \"checksum\"}, {\"type\": \"text\", \"text\": \"compute\"}, {\"type\": \"text\", \"text\": \"main\"}, {\"type\": \"text\", \"text\": \"__libc_csu_init\"}, {\"type\": \"text\", \"text\": \"__libc_csu_fini\"}, {\"type\": \"text\", \"text\": \"FUN_01001820\"}, {\"type\": \"text\", \"text\": \"<EXTERNAL>::strcmp\"}, {\"type\": \"text\", \"text\": \"<EXTERNAL>::puts\"}, {\"type\": \"text\", \"text\": \"<EXTERNAL>::printf\"}, {\"type\": \"text\", \"text\": \"<EXTERNAL>::__libc_start_main\"}, {\"type\": \"text\", \"text\": \"<EXTERNAL>::strcmp\"}, {\"type\": \"text\", \"text\": \"<EXTERNAL>::puts\"}, {\"type\":",
        "expected": "function names including add_numbers",
        "input": "{\"tool\": \"list_methods\", \"arguments\": {\"offset\": 0, \"limit\": 100}}",
        "kind": "claim",
        "outcome": "Real input produced the expected result: add_numbers",
        "source": "List methods, classes, imports, and exports",
        "source_checked": true,
        "source_file": "README.md",
        "verdict": "yes"
      }
    ],
    "cycle_checks": [
      {
        "claim": "Scheduled or looping main behavior",
        "command": "",
        "evidence": "Inspected src/ghidra_mcp (cli.py, server.py, headless.py, backend.py), README.md and .github/workflows/build.yml. There is no cron, scheduler, polling loop, --once/--now flag or webhook. The server only responds to MCP tool calls over stdio or streamable-http, so there is no product cycle to trigger.",
        "expected": "identify the product trigger",
        "input": "source inspection",
        "kind": "cycle",
        "outcome": "Inspected src/ghidra_mcp (cli.py, server.py, headless.py, backend.py), README.md and .github/workflows/build.yml. There is no cron, scheduler, polling loop, --once/--now flag or webhook. The server only responds to MCP tool calls over stdio or streamable-http, so there is no product cycle to trigger.",
        "source": "repository entry points",
        "verdict": "yes"
      }
    ],
    "details": {
      "argv": [
        "<guest-path>",
        "run",
        "--python",
        "3.13",
        "--extra",
        "headless",
        "ghidra-mcp",
        "--headless",
        "--binary",
        "tests/fixtures/sample_x86_64.elf",
        "--extension-jar",
        "/tmp/ghidra-ext/GhidraMCP/lib/GhidraMCP.jar"
      ],
      "kind": "mcp",
      "scope": "product operation",
      "serverInfo": {
        "name": "ghidra-mcp",
        "version": "1.30.0"
      },
      "tool_result": {
        "content": [
          {
            "text": "{\n  \"function\": {\n    \"name\": \"add_numbers\",\n    \"address\": \"01001640\"\n  },\n  \"code\": \"\\nint add_numbers(int param_1,int param_2)\\n\\n{\\n  return param_1 + param_2;\\n}\\n\\n\",\n  \"truncated\": false\n}",
            "type": "text"
          }
        ],
        "isError": false,
        "structuredContent": {
          "code": "\nint add_numbers(int param_1,int param_2)\n\n{\n  return param_1 + param_2;\n}\n\n",
          "function": {
            "address": "01001640",
            "name": "add_numbers"
          },
          "truncated": false
        }
      },
      "tool_result_checked": true,
      "tool_schema_bytes": 13201,
      "tools": [
        "get_program_info",
        "list_functions",
        "list_methods",
        "search_functions_by_name",
        "list_classes",
        "list_namespaces",
        "list_segments",
        "list_imports",
        "list_exports",
        "list_data_items",
        "list_strings",
        "get_function_by_address",
        "decompile_function",
        "decompile_function_by_address",
        "disassemble_function",
        "get_xrefs_to",
        "get_xrefs_from",
        "get_function_xrefs",
        "get_function_calls",
        "read_memory",
        "rename_function_by_address",
        "rename_function",
        "rename_data",
        "rename_variable",
        "set_function_prototype",
        "set_local_variable_type",
        "set_decompiler_comment",
        "set_disassembly_comment"
      ],
      "working": true
    },
    "evidence_strength": "readme_checked",
    "example_checks": [
      {
        "claim": "Offline repository test suite (README: tested with uv run pytest)",
        "command": "<guest-path> run --python 3.13 pytest -q",
        "deferred": false,
        "evidence": "..........................................                               [100%]\n42 passed in 68.38s (0:01:08)",
        "expected": "offline tests pass, Ghidra-dependent tests skipped without GHIDRA_INSTALL_DIR",
        "input": "uv run pytest",
        "kind": "example",
        "outcome": "command completed successfully",
        "returncode": 0,
        "source": "README.md: The Python MCP server can be run from a checkout with `uv run ghidra-mcp`, and tested with `uv run pytest`.",
        "verdict": "yes"
      },
      {
        "claim": "Headless integration tests with a real Ghidra install (CI command)",
        "command": "<guest-path> run --python 3.13 --extra headless pytest -q",
        "deferred": false,
        "evidence": "..........................................                               [100%]\n42 passed in 72.90s (0:01:12)",
        "expected": "all 42 tests pass including headless Ghidra integration",
        "input": "uv run --extra headless pytest -q with GHIDRA_INSTALL_DIR set",
        "kind": "example",
        "outcome": "command completed successfully",
        "returncode": 0,
        "source": ".github/workflows/build.yml: uv run --extra headless pytest -v",
        "verdict": "yes"
      }
    ],
    "status": "PASS"
  },
  "deviations": [
    "Python zipfile extraction dropped the execute bit on Ghidra's support/gradle/gradlew and on the native decompile binary (Ghidra/Features/Decompiler/os/linux_x86_64/decompile). The first decompile_function call failed with 'Permission denied'. Fixed by chmod +x on those files inside the Ghidra install directory only; no product source was edited.",
    "The README's uvx --from git+https://github.com/LaurieWired/GhidraMCP form was replaced by the equivalent checkout command 'uv run --extra headless ghidra-mcp' (README: 'can be run from a checkout with uv run ghidra-mcp'), so the pinned commit was tested rather than the latest GitHub version.",
    "Ghidra GUI installation (File > Install Extensions) and the running-GUI HTTP backend were not exercised; the headless path using --extension-jar was used instead. The extension zip was built from source with Gradle, and lib/GhidraMCP.jar was taken from it.",
    "The --extension-jar flag was given the jar from the built zip; the GUI plugin was not installed into Ghidra."
  ],
  "fault_owner": null,
  "main_blocker": null,
  "operation": "Run the ghidra-mcp MCP server against a real Ghidra 12.1.4 install in headless mode, and call decompile_function and list_methods on the sample x86_64 ELF fixture",
  "operation_scope": "Linux x86_64 Ubuntu 24.04 guest, Python 3.13 via uv, JDK 21, Ghidra 12.1.4 PUBLIC release zip. GUI mode (plugin in a running Ghidra window) was not exercised; headless mode was used instead, as the README documents.",
  "outcome": "working",
  "plain_failure": null,
  "steps": [
    "git init; git remote add origin https://github.com/LaurieWired/GhidraMCP; git fetch --depth 1 origin 1e980252087b2479a21b9ca6d82d5829538651a7; git reset --mixed FETCH_HEAD",
    "curl -LsSf https://astral.sh/uv/install.sh | sh (uv 0.13.5)",
    "uv python install 3.13 (Python 3.13.17)",
    "uv run --python 3.13 pytest (19 passed, 23 skipped without Ghidra)",
    "sudo apt-get install openjdk-21-jdk-headless (JDK 21.0.12)",
    "Downloaded ghidra_12.1.4_PUBLIC_20260921.zip from the NSA GitHub release and extracted it to /tmp/ghidra-dl/x (outside the checkout)",
    "cd extension && $GHIDRA_INSTALL_DIR/support/gradle/gradlew buildExtension (BUILD SUCCESSFUL, produced extension/dist/ghidra_12.1.4_PUBLIC_20261023_GhidraMCP.zip)",
    "uv run --python 3.13 --extra headless pytest (42 passed, CI command)",
    "uv run --python 3.13 --extra headless ghidra-mcp --headless --binary tests/fixtures/sample_x86_64.elf --extension-jar /tmp/ghidra-ext/GhidraMCP/lib/GhidraMCP.jar (stdio MCP server; decompile_function add_numbers returned 'return param_1 + param_2;')"
  ],
  "stuck_step": null,
  "suggested_fix": "None for the product. For a fresh install, note that unzipping the Ghidra release with a tool that drops file permissions needs 'chmod +x' on support/gradle/gradlew and the Ghidra decompiler binaries; the README could mention this."
}
