diff --git a/bridge/binja_mcp_bridge.py b/bridge/binja_mcp_bridge.py index a59efe9..d6ba849 100755 --- a/bridge/binja_mcp_bridge.py +++ b/bridge/binja_mcp_bridge.py @@ -594,15 +594,25 @@ def search_functions_by_name(query: str, offset: int = 0, limit: int = 100) -> l @mcp.tool() def get_binary_status() -> str: """ - Get the current status of the loaded binary. + Get the current status of the loaded binary, including the original binary name. """ - return safe_get("status")[0] + data = get_json("status") + if not data: + return "Error: no response" + if isinstance(data, dict) and data.get("error"): + return data.get("error") + loaded = data.get("loaded", False) + if not loaded: + return "No binary loaded" + binary_name = data.get("binary_name") or "(unknown)" + filename = data.get("filename") or "(unknown)" + return f"Binary: {binary_name}\nPath: {filename}" @mcp.tool() def list_binaries() -> list: """ - List managed/open binaries known to the server with ids and active flag. + List managed/open binaries known to the server with ids, binary names, and active flag. """ data = get_json("binaries") if not data: @@ -616,9 +626,11 @@ def list_binaries() -> list: view_id = it.get("view_id") fn = it.get("filename") basename = it.get("basename") or "" + binary_name = it.get("binary_name") or "" selectors = it.get("selectors") or [] active = it.get("active") - label = basename or fn or "(unknown)" + # Use binary_name as primary label, fallback to basename or filename + label = binary_name or basename or fn or "(unknown)" full = fn or "(no filename)" selector_text = ", ".join(str(s) for s in selectors if s) mark = " *active*" if active else "" diff --git a/plugin/api/endpoints.py b/plugin/api/endpoints.py index 08c2b5d..0ba0d4c 100644 --- a/plugin/api/endpoints.py +++ b/plugin/api/endpoints.py @@ -12,11 +12,12 @@ def __init__(self, binary_ops: BinaryOperations): def get_status(self) -> dict[str, Any]: """Get the current status of the binary view""" + bv = self.binary_ops.current_view + binary_name = self.binary_ops._get_binary_name(bv) if bv else None return { - "loaded": self.binary_ops.current_view is not None, - "filename": self.binary_ops.current_view.file.filename - if self.binary_ops.current_view - else None, + "loaded": bv is not None, + "filename": bv.file.filename if bv else None, + "binary_name": binary_name, } def get_entry_points(self) -> list[dict[str, Any]]: @@ -31,11 +32,13 @@ def _format_binary_listing(self, raw: list[dict[str, Any]]) -> list[dict[str, An filename = item.get("filename") view_id = str(item.get("id") or "") basename = os.path.basename(filename) if filename else None + binary_name = item.get("binary_name") entry: dict[str, Any] = { "id": str(ordinal), "view_id": view_id, "filename": filename, "basename": basename, + "binary_name": binary_name, "active": bool(item.get("active")), } selectors: list[str] = [] @@ -44,6 +47,7 @@ def _format_binary_listing(self, raw: list[dict[str, Any]]) -> list[dict[str, An view_id, filename, basename, + binary_name, ): if candidate and candidate not in selectors: selectors.append(candidate) diff --git a/plugin/core/binary_operations.py b/plugin/core/binary_operations.py index 93f0900..1b3aaf9 100644 --- a/plugin/core/binary_operations.py +++ b/plugin/core/binary_operations.py @@ -111,6 +111,28 @@ def _prune_views(self) -> None: except Exception: self._current_view = None + def _get_binary_name(self, bv: bn.BinaryView) -> str | None: + """Get the original binary name from a BinaryView. + + For project files (.bnpr), extracts the original name from project_file.name, + stripping the .bndb suffix if present. Falls back to basename of filename. + """ + import os + + if bv and bv.file: + pf = getattr(bv.file, "project_file", None) + if pf: + name = getattr(pf, "name", None) + if name and name.endswith(".bndb"): + return name[:-5] # Strip .bndb + return name + # Fallback to basename of filename, handling missing filename safely + filename = getattr(bv.file, "filename", None) + if not filename: + return None + return os.path.basename(filename) + return None + def _register_view(self, bv: bn.BinaryView) -> str: """Add a view to the managed list if not present, return its id.""" self._prune_views() @@ -194,7 +216,8 @@ def list_open_binaries(self) -> list[dict[str, str]]: # Do NOT auto-register current_view here; UI monitor handles discovery. # This avoids re-introducing closed views via a stale strong reference. # Deduplicate by canonical filename; prefer the id mapped in _id_by_filename - entries: list[tuple[str, str, bool]] = [] # (id, filename, active) + # (id, filename, active, binary_view) + entries: list[tuple[str, str, bool, bn.BinaryView]] = [] seen: set[str] = set() for vid, w in self._views_by_id.items(): try: @@ -218,11 +241,17 @@ def list_open_binaries(self) -> list[dict[str, str]]: vb_canon = vb_canon_ref() if vb_canon_ref else vb except Exception: vb_canon = vb - entries.append((canonical_id, fn, bool(vb_canon is self._current_view))) + entries.append((canonical_id, fn, bool(vb_canon is self._current_view), vb_canon)) # Sort by filename for stable ordering entries.sort(key=lambda t: (t[1] or "")) - for cid, fn, active in entries: - items.append({"id": cid, "filename": fn, "active": active}) + for cid, fn, active, bv in entries: + binary_name = self._get_binary_name(bv) + items.append({ + "id": cid, + "filename": fn, + "binary_name": binary_name, + "active": active, + }) return items def select_view(self, ident: str) -> dict[str, str] | None: