Haiku 5.5
Native agent · Checked operation passedChecked operation <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 · local stdio MCP start + initialize + tools/list
Agent-reported scope: 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
MCP server returned: ghidra-mcp · version 1.30.0.
MCP tools returned: 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. Tool listing does not establish authenticated tool-call success.
Run details
- run
- LaurieWired--GhidraMCP-claude-haiku-5-5-1792761045110315360
- date
- Oct 23, 2026
- time to working
- 1591.4s
- product hosting / execution
- Local stdio MCP server in the guest
- recorded operation scope
- product operation
- model
- claude-haiku-5-5
- agent / version
- claude-code / 2.1.300 (Claude Code)
- platform
- linux
- reported cost
- $0.022808
- Recorded source
- https://github.com/LaurieWired/GhidraMCP
- Backend
- hyperv
- Tool transport
- mcp-assigned-vm
- Requested source pin (not an observed revision)
- {"commit": "1e980252087b2479a21b9ca6d82d5829538651a7", "url": "https://github.com/LaurieWired/GhidraMCP"}
- Test version
- readme-bdc1b9b3c0d2673aef87e076d14084a8123ddcf09d520c1ee2e364a37c3f4bb9
- revision
- 1e980252087b2479a21b9ca6d82d5829538651a7
Safety: Review signals: 2 known vulnerability, 1 outside write.
Review signals: 2 known vulnerability, 1 outside write.
OSV reports a known vulnerability in this dependency version. certifi 2 findings.
Repository processes attempted these writes outside documented output/cache paths. 18 distinct locations. 19 attributed processes.
OSV scanned supported lockfiles; unpinned dependencies and unsupported formats are outside this check.
A short run cannot establish that code is safe.
Connections show IP addresses; proxies can hide the final hostname.
Tracing covers dispatched commands and their children, not the whole OS; guest root can interfere with tracing.
Answers recorded for this run
- Ghidra MCP decompiles functions from a binary: Real input produced the expected result: return param_1 + param_2;
Source: Decompile and analyze binaries in Ghidra
Input: {"tool": "decompile_function", "arguments": {"name": "add_numbers"}}
Expected: decompiled C body of add_numbers
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"}}
Observed: 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}
- Ghidra MCP lists methods of the binary: Real input produced the expected result: add_numbers
Source: List methods, classes, imports, and exports
Input: {"tool": "list_methods", "arguments": {"offset": 0, "limit": 100}}
Expected: function names including add_numbers
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}}
Observed: 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":
Examples
- Offline repository test suite (README: tested with uv run pytest): command completed successfully
Source: README.md: The Python MCP server can be run from a checkout with `uv run ghidra-mcp`, and tested with `uv run pytest`.
Input: uv run pytest
Expected: offline tests pass, Ghidra-dependent tests skipped without GHIDRA_INSTALL_DIR
Command: <guest-path> run --python 3.13 pytest -q
Observed: .......................................... [100%] 42 passed in 68.38s (0:01:08)
- Headless integration tests with a real Ghidra install (CI command): command completed successfully
Source: .github/workflows/build.yml: uv run --extra headless pytest -v
Input: uv run --extra headless pytest -q with GHIDRA_INSTALL_DIR set
Expected: all 42 tests pass including headless Ghidra integration
Command: <guest-path> run --python 3.13 --extra headless pytest -q
Observed: .......................................... [100%] 42 passed in 72.90s (0:01:12)
Local or hosted: local
What the agent did
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
cd <guest-path> && pwd && ls -la && id -u && python3 --version && cat /etc/os-release | head -3 && git -C . status 2>&1 | head -2; ls /inputs 2>&1
cd <guest-path> && cat README.md 2>/dev/null | head -200
cd <guest-path> && cat pyproject.toml; echo ---; cat .python-version; echo ---; ls -R src tests .coldpass | head -50; echo ---; which uv java javac node npm curl git; uv --version 2>&1; java -version 2>&1 | head -2; echo ---; cat bridge_mcp_ghidra.py | head -20; ls .github/workflows && cat .github/workflows/*.yml | head -80
cd /tmp && export NODE_USE_ENV_PROXY=1; curl -LsSf https://astral.sh/uv/install.sh -o /tmp/uv-install.sh 2>&1; echo "rc=$?"; sh /tmp/uv-install.sh 2>&1 | tail -5; ls ~/.local/bin 2>/dev/null; ~/.local/bin/uv --version 2>&1
cd <guest-path> && export PATH=$HOME/.local/bin:$PATH && (git init -q && git remote add origin https://github.com/LaurieWired/GhidraMCP && git fetch -q --depth 1 origin 1e980252087b2479a21b9ca6d82d5829538651a7 && git reset -q --mixed FETCH_HEAD; echo "git rc=$?") 2>&1 | tail -3; git log --oneline -1 2>&1; git status --short | head; echo ---; uv python install 3.13 2>&1 | tail -3; echo ---; timeout 900 uv run --python 3.13 pytest --co -q 2>&1 | tail -5
cd <guest-path> && export PATH=$HOME/.local/bin:$PATH && timeout 900 uv run --python 3.13 pytest -q 2>&1 | tail -25
sudo -n true && echo SUDO_OK; apt-cache policy openjdk-21-jdk-headless 2>/dev/null | head -3; curl -sI -m 30 https://github.com/NationalSecurityAgency/ghidra/releases/download/Ghidra_12.1.4_build/ghidra_12.1.4_PUBLIC_20260921.zip | head -5; echo "rc=$?"
mkdir -p /tmp/ghidra-dl && cd /tmp/ghidra-dl && (sudo -n apt-get update -qq >/tmp/apt-update.log 2>&1; sudo -n DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openjdk-21-jdk-headless > /tmp/apt-jdk.log 2>&1; echo "apt rc=$?") ; tail -3 /tmp/apt-jdk.log; java -version 2>&1 | head -1
cd /tmp/ghidra-dl && timeout 1500 curl -L -sS -o ghidra.zip "https://github.com/NationalSecurityAgency/ghidra/releases/download/Ghidra_12.1.4_build/ghidra_12.1.4_PUBLIC_20260921.zip"; echo "rc=$?"; ls -la
cd /tmp/ghidra-dl && python3 -I -c "import zipfile;zipfile.ZipFile('ghidra.zip').extractall('/tmp/ghidra-dl/x')" && ls /tmp/ghidra-dl/x && export GHIDRA_INSTALL_DIR=/tmp/ghidra-dl/x/ghidra_12.1.4_PUBLIC && ls $GHIDRA_INSTALL_DIR | head -30 && cd <guest-path> && timeout 1500 $GHIDRA_INSTALL_DIR/support/gradle/gradlew buildExtension > /tmp/ext-build.log 2>&1; echo "rc=$?"; tail -25 /tmp/ext-build.log
export GHIDRA_INSTALL_DIR=/tmp/ghidra-dl/x/ghidra_12.1.4_PUBLIC && chmod +x $GHIDRA_INSTALL_DIR/support/gradle/gradlew && cd <guest-path> && timeout 1500 $GHIDRA_INSTALL_DIR/support/gradle/gradlew buildExtension > /tmp/ext-build.log 2>&1; echo "rc=$?"; tail -25 /tmp/ext-build.log; ls -la dist 2>/dev/null
cd <guest-path> && export PATH=$HOME/.local/bin:$PATH GHIDRA_INSTALL_DIR=/tmp/ghidra-dl/x/ghidra_12.1.4_PUBLIC && timeout 600 uv run --python 3.13 --extra headless ghidra-mcp --help 2>&1 | tail -60; echo ---; cat src/ghidra_mcp/cli.py | head -150
mkdir -p /tmp/ghidra-ext && cd /tmp/ghidra-ext && python3 -I -c "
import zipfile
z=zipfile.ZipFile('<guest-path>')
print(z.namelist())
z.extract('lib/GhidraMCP.jar','/tmp/ghidra-ext')
" && ls -la /tmp/ghidra-ext/lib; cd <guest-path> && grep -n "def \<email>\<email>" src/ghidra_mcp/server.py | head -80; cat tests/fixtures/build_fixtures.sh | head -20; ls -la tests/fixtures
cd /tmp/ghidra-ext && python3 -I -c "
import zipfile
z=zipfile.ZipFile('<guest-path>')
z.extract('GhidraMCP/lib/GhidraMCP.jar','/tmp/ghidra-ext')
" && ls -la /tmp/ghidra-ext/GhidraMCP/lib && cat <guest-path>; echo $HOME; echo "$HOME/.local/bin/uv"; ls -la $HOME/.local/bin/uv
cd <guest-path> && export PATH=<guest-path> GHIDRA_INSTALL_DIR=/tmp/ghidra-dl/x/ghidra_12.1.4_PUBLIC && { printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"smoke","version":"0"}}}' '{"jsonrpc":"2.0","method":"notifications/initialized"}' '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"search_functions_by_name","arguments":{"query":"add_numbers"}}}'; sleep 200; } | timeout 280 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 > /tmp/smoke.out 2> /tmp/smoke.err; echo "rc=$?"; cut -c1-600 /tmp/smoke.out | tail -5; echo ---; tail -15 /tmp/smoke.err | cut -c1-400
cd <guest-path> && export PATH=<guest-path> GHIDRA_INSTALL_DIR=/tmp/ghidra-dl/x/ghidra_12.1.4_PUBLIC && { printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"smoke","version":"0"}}}' '{"jsonrpc":"2.0","method":"notifications/initialized"}' '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"list_methods","arguments":{"offset":0,"limit":100}}}' '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"decompile_function","arguments":{"name":"add_numbers"}}}'; sleep 60; } | timeout 200 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 > /tmp/smoke2.out 2> /tmp/smoke2.err; echo "rc=$?"; grep '"id":2\|"id":3' /tmp/smoke2.out | cut -c1-900
G=/tmp/ghidra-dl/x/ghidra_12.1.4_PUBLIC; find $G/Ghidra/Features/Decompiler/os -type f | head; find $G -path '*/os/*' -type f \( -name decompile -o -name '*.sh' \) -exec chmod +x {} + ; find $G -type f \( -name 'decompile' -o -name 'ghidraRun' -o -name 'analyzeHeadless' -o -name 'pyghidraRun' \) -exec chmod +x {} + ; ls -la $G/Ghidra/Features/Decompiler/os/linux_x86_64/ 2>&1; cd <guest-path> && export PATH=<guest-path> GHIDRA_INSTALL_DIR=$G && { printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"smoke","version":"0"}}}' '{"jsonrpc":"2.0","method":"notifications/initialized"}' '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"decompile_function","arguments":{"name":"add_numbers"}}}'; sleep 60; } | timeout 200 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 > /tmp/smoke3.out 2> /tmp/smoke3.err; echo "rc=$?"; grep '"id":3' /tmp/smoke3.out | cut -c1-900
cd <guest-path> && export PATH=<guest-path> GHIDRA_INSTALL_DIR=/tmp/ghidra-dl/x/ghidra_12.1.4_PUBLIC && timeout 900 uv run --python 3.13 --extra headless pytest -q 2>&1 | tail -6; echo ---; grep -rniE "cron|schedul|while True|--once|--now|webhook|interval|sleep\(" src/ README.md | head -20; echo "grep rc=$?"
cd <guest-path> && UV=<guest-path> && ENV='{"GHIDRA_INSTALL_DIR":"/tmp/ghidra-dl/x/ghidra_12.1.4_PUBLIC","PATH":"<guest-path>"}' && SRV="[\"$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\"]" && cat > probe.json <<EOF
{"kind":"mcp","argv":$SRV,"cwd":"<guest-path>","env":$ENV,"tool":"decompile_function","arguments":{"name":"add_numbers"},"expected_text":"return param_1 + param_2;"}
EOF
cat > claims.json <<EOF
[
{"kind":"claim","claim":"Ghidra MCP decompiles functions from a binary","source":"Decompile and analyze binaries in Ghidra","input":"add_numbers in tests/fixtures/sample_x86_64.elf","expected":"decompiled C body of add_numbers","probe_kind":"mcp","argv":$SRV,"stdin":"","tool":"decompile_function","arguments":{"name":"add_numbers"},"expected_text":"return param_1 + param_2;","cwd":"<guest-path>","env":$ENV},
{"kind":"claim","claim":"Ghidra MCP lists methods of the binary","source":"List methods, classes, imports, and exports","input":"sample_x86_64.elf offset 0 limit 100","expected":"function names including add_numbers","probe_kind":"mcp","argv":$SRV,"stdin":"","tool":"list_methods","arguments":{"offset":0,"limit":100},"expected_text":"add_numbers","cwd":"<guest-path>","env":$ENV}
]
EOF
cat > cycles.json <<'EOF'
{"detected":false,"reason":"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.","checks":[]}
EOF
cat > examples.json <<EOF
[
{"kind":"example","claim":"Offline repository test suite (README: tested with uv run pytest)","source":"README.md: The Python MCP server can be run from a checkout with \`uv run ghidra-mcp\`, and tested with \`uv run pytest\`.","input":"uv run pytest","expected":"offline tests pass, Ghidra-dependent tests skipped without GHIDRA_INSTALL_DIR","argv":["<guest-path>","run","--python","3.13","pytest","-q"],"cwd":"<guest-path>","env":{"PATH":"<guest-path>"},"expected_text":"passed"},
{"kind":"example","claim":"Headless integration tests with a real Ghidra install (CI command)","source":".github/workflows/build.yml: uv run --extra headless pytest -v","input":"uv run --extra headless pytest -q with GHIDRA_INSTALL_DIR set","expected":"all 42 tests pass including headless Ghidra integration","argv":["<guest-path>","run","--python","3.13","--extra","headless","pytest","-q"],"cwd":"<guest-path>","env":{"GHIDRA_INSTALL_DIR":"/tmp/ghidra-dl/x/ghidra_12.1.4_PUBLIC","PATH":"<guest-path>"},"expected_text":"42 passed"}
]
EOF
python3 -I -c "import json;[json.load(open(f)) for f in ['probe.json','claims.json','cycles.json','examples.json']];print('json ok')"; ls -la
pgrep -fa "ghidra-mcp|ghidra|java" | grep -v pgrep | head -5; echo "procs-check-done"; cd <guest-path> && <env-var>=<guest-path> timeout 1500 python3 -I <guest-path> --validate --replay 2>&1 | tail -80
G=/tmp/ghidra-dl/x/ghidra_12.1.4_PUBLIC; (cd <guest-path> && timeout 120 $G/support/gradle/gradlew --stop >/dev/null 2>&1); sleep 2; pgrep -fa "GradleDaemon|ghidra-mcp" | grep -v pgrep | cut -c1-120; echo "stopped"; cd <guest-path> && cat > .coldpass/report.json <<'EOF'
{"outcome":"working","fault_owner":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.","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;')"],"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."],"stuck_step":null,"main_blocker":null,"plain_failure":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."}
EOF
python3 -I -c "import json;print(json.load(open('.coldpass/report.json'))['outcome'])"; <env-var>=<guest-path> timeout 1500 python3 -I <guest-path> --validate --replay 2>&1 | tail -c 700
cd <guest-path> && <env-var>=<guest-path> timeout 1500 python3 -I <guest-path> --validate --replay 2>&1 | grep -o '^{"valid": [a-z]*, "problems": [^,]*, "replay": {"status": "[A-Z]*"' ; pgrep -fa "ghidra-mcp|GradleDaemon" | grep -v pgrep | wc -lrun JSON · checker evidence · agent report + check · transcript excerpt unavailable · error excerpt unavailable