102 lines
2.8 KiB
Python
102 lines
2.8 KiB
Python
"""File MCP tools - File operations with receipts."""
|
|
|
|
import json
|
|
import os
|
|
from datetime import datetime, timezone
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
import blake3
|
|
|
|
# VaultMesh root from env or default
|
|
VAULTMESH_ROOT = Path(os.environ.get("VAULTMESH_ROOT", Path(__file__).parents[3])).resolve()
|
|
RECEIPTS_ROOT = VAULTMESH_ROOT / "receipts"
|
|
FILE_RECEIPTS = RECEIPTS_ROOT / "file" / "file_operations.jsonl"
|
|
|
|
|
|
def _vmhash_blake3(data: bytes) -> str:
|
|
"""VaultMesh hash: blake3:<hex>."""
|
|
return f"blake3:{blake3.blake3(data).hexdigest()}"
|
|
|
|
|
|
def _emit_file_receipt(operation: str, file_path: str, details: dict, actor: str = "did:vm:mcp:file") -> str:
|
|
"""Emit a receipt for file operation."""
|
|
FILE_RECEIPTS.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
body = {
|
|
"operation": operation,
|
|
"file_path": file_path,
|
|
"details": details,
|
|
"actor": actor,
|
|
}
|
|
|
|
root_hash = _vmhash_blake3(json.dumps(body, sort_keys=True).encode())
|
|
|
|
receipt = {
|
|
"schema_version": "2.0.0",
|
|
"type": "file_operation",
|
|
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
"scroll": "file",
|
|
"tags": ["file", operation, "mcp"],
|
|
"root_hash": root_hash,
|
|
"body": body,
|
|
}
|
|
|
|
with open(FILE_RECEIPTS, "a") as f:
|
|
f.write(json.dumps(receipt) + "\n")
|
|
|
|
return root_hash
|
|
|
|
|
|
def file_add(
|
|
path: str,
|
|
content: str,
|
|
encoding: str = "utf-8",
|
|
actor: str = "did:vm:mcp:file",
|
|
) -> dict[str, Any]:
|
|
"""
|
|
Add (create or overwrite) a file with content.
|
|
|
|
Args:
|
|
path: File path relative to VAULTMESH_ROOT or absolute
|
|
content: File content to write
|
|
encoding: File encoding (default: utf-8)
|
|
actor: DID of actor performing operation
|
|
|
|
Returns:
|
|
Result with file hash and receipt hash
|
|
"""
|
|
try:
|
|
file_path = Path(path)
|
|
if not file_path.is_absolute():
|
|
file_path = VAULTMESH_ROOT / file_path
|
|
|
|
# Create parent directories if needed
|
|
file_path.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
# Write file
|
|
file_path.write_text(content, encoding=encoding)
|
|
|
|
# Hash the content
|
|
content_hash = _vmhash_blake3(content.encode(encoding))
|
|
|
|
details = {
|
|
"content_hash": content_hash,
|
|
"size_bytes": len(content.encode(encoding)),
|
|
"encoding": encoding,
|
|
"created": not file_path.exists(),
|
|
}
|
|
|
|
receipt_hash = _emit_file_receipt("add", str(file_path), details, actor)
|
|
|
|
return {
|
|
"success": True,
|
|
"path": str(file_path),
|
|
"content_hash": content_hash,
|
|
"receipt_hash": receipt_hash,
|
|
"size_bytes": details["size_bytes"],
|
|
}
|
|
|
|
except Exception as e:
|
|
return {"success": False, "error": str(e)}
|