from pathlib import Path from fastmcp import FastMCP from starlette.middleware import Middleware from starlette.middleware.cors import CORSMiddleware from starlette.requests import Request from starlette.responses import JSONResponse import uvicorn ROOT_DIR = Path(__file__).resolve().parent UPLOAD_DIR = ROOT_DIR / "uploads" UPLOAD_DIR.mkdir(exist_ok=True) # Streamable HTTP MCP server. mcp = FastMCP("FilePersistenceMCP") @mcp.tool def health() -> dict: """Return basic server health information.""" return { "status": "ok", "server": "FilePersistenceMCP", "transport": "streamable-http", "uploads_dir": str(UPLOAD_DIR), } @mcp.tool def list_uploaded_files() -> dict: """List files currently stored in the uploads directory.""" files = sorted(p.name for p in UPLOAD_DIR.iterdir() if p.is_file()) return { "count": len(files), "files": files, } @mcp.tool def file_info(filename: str) -> dict: """Return metadata for one uploaded file.""" path = (UPLOAD_DIR / filename).resolve() if path.parent != UPLOAD_DIR.resolve() or not path.exists() or not path.is_file(): raise FileNotFoundError(f"File not found: {filename}") stat = path.stat() return { "filename": path.name, "size_bytes": stat.st_size, "absolute_path": str(path), } @mcp.custom_route("/health", methods=["GET"]) async def http_health(_: Request) -> JSONResponse: return JSONResponse( { "status": "ok", "server": "FilePersistenceMCP", "transport": "streamable-http", } ) if __name__ == "__main__": app = mcp.http_app( path="/mcp", middleware=[ Middleware( CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"], ) ], stateless_http=True, ) uvicorn.run(app, host="0.0.0.0", port=8001)