better file return

This commit is contained in:
Daniel O'Connell 2025-06-04 03:10:50 +02:00
parent 7ac16031bb
commit f8090634c7
2 changed files with 61 additions and 11 deletions

View File

@ -148,6 +148,8 @@ services:
POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password
QDRANT_URL: http://qdrant:6333 QDRANT_URL: http://qdrant:6333
secrets: [postgres_password] secrets: [postgres_password]
volumes:
- ./memory_files:/app/memory_files:rw
healthcheck: healthcheck:
test: ["CMD-SHELL", "curl -fs http://localhost:8000/health || exit 1"] test: ["CMD-SHELL", "curl -fs http://localhost:8000/health || exit 1"]
interval: 15s interval: 15s

View File

@ -5,6 +5,7 @@ MCP tools for the epistemic sparring partner system.
import logging import logging
import pathlib import pathlib
from datetime import datetime, timezone from datetime import datetime, timezone
import mimetypes
from mcp.server.fastmcp import FastMCP from mcp.server.fastmcp import FastMCP
from pydantic import BaseModel from pydantic import BaseModel
@ -385,20 +386,67 @@ async def note_files(path: str = "/"):
@mcp.tool() @mcp.tool()
def fetch_file(filename: str): def fetch_file(filename: str) -> dict:
""" """
Read file content from user's storage. Read file content with automatic type detection.
Use when you need to access specific content of a file that's been referenced. Returns dict with content, mime_type, is_text, file_size.
Text content as string, binary as base64.
Args:
filename: Path to file (e.g., "/notes/project.md", "/documents/report.pdf")
Path should start with "/" and use forward slashes
Returns: Raw bytes content (decode as UTF-8 for text files)
Raises FileNotFoundError if file doesn't exist.
""" """
path = settings.FILE_STORAGE_DIR / filename.lstrip("/") path = settings.FILE_STORAGE_DIR / filename.lstrip("/")
if not path.exists(): if not path.exists():
raise FileNotFoundError(f"File not found: {filename}") raise FileNotFoundError(f"File not found: {filename}")
return path.read_bytes() mime_type, _ = mimetypes.guess_type(str(path))
mime_type = mime_type or "application/octet-stream"
text_extensions = {
".md",
".txt",
".py",
".js",
".html",
".css",
".json",
".xml",
".yaml",
".yml",
".toml",
".ini",
".cfg",
".conf",
}
text_mimes = {
"application/json",
"application/xml",
"application/javascript",
"application/x-yaml",
"application/yaml",
}
is_text = (
mime_type.startswith("text/")
or mime_type in text_mimes
or path.suffix.lower() in text_extensions
)
try:
content = (
path.read_text(encoding="utf-8")
if is_text
else __import__("base64").b64encode(path.read_bytes()).decode("ascii")
)
except UnicodeDecodeError:
import base64
content = base64.b64encode(path.read_bytes()).decode("ascii")
is_text = False
mime_type = (
"application/octet-stream" if mime_type.startswith("text/") else mime_type
)
return {
"content": content,
"mime_type": mime_type,
"is_text": is_text,
"file_size": path.stat().st_size,
"filename": filename,
}