fix(mcp): basename source_file in tool_get_drawer responses
The MCP `mempalace_get_drawer` tool returned the entire raw drawer metadata blob to any connected client, and the `source_file` field in that blob is the absolute filesystem path written by the miners (`miner.py`, `convo_miner.py` — `source_file = str(filepath)`). On a single-user local deployment this is self-disclosure, but in nested-agent or multi-server MCP topologies the client is a separate trust domain and the host's directory layout has no documented client-side use. Mirror the mitigation that `searcher.search_memories()` already applies on its own return path: reduce `source_file` to its basename via `Path(source_file).name` before handing the metadata to the client. Citations still work — the directory layout does not leak. Companion to #1 (omit palace_path from tool_status). Same threat class, different surface: - mempalace_status — palace dir path → fixed in #1 - mempalace_get_drawer — per-drawer source_file path → this PR Other read tools were audited and do not leak host paths: - mempalace_search — already basenames source_file - mempalace_list_drawers — returns wing/room/preview only - mempalace_diary_read — date/timestamp/topic/content only - mempalace_reconnect — success/message/drawers only - mempalace_kg_* — entity/predicate strings, counts - mempalace_check_duplicate — wing/room/preview only Changes: - mempalace/mcp_server.py: tool_get_drawer() now basenames metadata.source_file - tests/test_mcp_server.py: regression test asserting the absolute path and its parent directory do not appear anywhere in the response - website/reference/mcp-tools.md: clarify the documented return shape
This commit is contained in:
+12
-3
@@ -912,12 +912,21 @@ def tool_get_drawer(drawer_id: str):
|
||||
return {"error": f"Drawer not found: {drawer_id}"}
|
||||
meta = result["metadatas"][0]
|
||||
doc = result["documents"][0]
|
||||
# source_file is the absolute filesystem path written by the
|
||||
# miners. Reduce to its basename before handing it to the MCP
|
||||
# client — same threat model as the palace_path leak fix:
|
||||
# nested-agent / multi-server topologies treat the client as a
|
||||
# separate trust domain. Basename preserves citation utility.
|
||||
# Mirrors the searcher.search_memories() return shape.
|
||||
safe_meta = dict(meta) if meta else {}
|
||||
if safe_meta.get("source_file"):
|
||||
safe_meta["source_file"] = Path(safe_meta["source_file"]).name
|
||||
return {
|
||||
"drawer_id": drawer_id,
|
||||
"content": doc,
|
||||
"wing": meta.get("wing", ""),
|
||||
"room": meta.get("room", ""),
|
||||
"metadata": meta,
|
||||
"wing": safe_meta.get("wing", ""),
|
||||
"room": safe_meta.get("room", ""),
|
||||
"metadata": safe_meta,
|
||||
}
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
Reference in New Issue
Block a user