Forward ghidra()/ghidra_tools() to the shared read-only Ghidra MCP server

Every agent reaches GhidrAssistMCP through Harbor's own MCP server, so no
per-host configuration is needed. Configured by ghidra_url in [reverse];
long decompiles are polled; also 'harbor re ghidra <tool> <json>'.
This commit is contained in:
KeelrLeek committed 2026-10-05 12:27:19 -05:00
1 parent 3f6df88f95
commit 7ed914ebdb
4 files changed
+186 -6

No files matched your search

+12 -5
View File
@@ -255,8 +255,9 @@ def build_parser():
p = sub.add_parser("who", help="who has worked on a scope (notes, reviews, claims, messages)")
p.add_argument("scope")
p = sub.add_parser("re", help="reverse-engineering lookups from the project's image and annotations")
p.add_argument("action", choices=["disasm", "xrefs", "bytes", "lookup"])
p.add_argument("target", help="an address (0x4AD850) or a name")
p.add_argument("action", choices=["disasm", "xrefs", "bytes", "lookup", "ghidra", "ghidra-tools"])
p.add_argument("target", nargs="?", default="", help="an address (0x4AD850) or a name; for ghidra, the tool")
p.add_argument("arguments", nargs="?", default="{}", help="ghidra: the tool's arguments as JSON")
p.add_argument("--max-bytes", type=int, dest="max_bytes")
p.add_argument("--count", type=int, default=16)
p.add_argument("--as", dest="as_type", default="hex", choices=["hex", "int32", "uint32", "float", "double", "string"])
@@ -673,9 +674,15 @@ def main(argv=None):
r = harbor.summarize(who(), args.thread, text)
out(r, f"summary #{r['id']} pinned to {r['thread']}")
elif cmd == "re":
from .reverse import Reverse
r = Reverse(harbor.project.reverse)
if args.action == "disasm":
from .reverse import Ghidra, Reverse
r = None if args.action.startswith("ghidra") else Reverse(harbor.project.reverse)
if args.action == "ghidra-tools":
res = Ghidra(harbor.project.reverse).tools()
out(res, "\n".join(f"{t['name']:<26} {t['description'].splitlines()[0][:90]}" for t in res))
elif args.action == "ghidra":
text = Ghidra(harbor.project.reverse).call(args.target, json.loads(args.arguments))
out({"result": text}, text)
elif args.action == "disasm":
text = r.disassemble(args.target, args.max_bytes)
out({"disassembly": text}, text)
elif args.action == "xrefs":