Skip to main content
Glama
preview_static_server.py2.9 kB
"""Lightweight static file server with SPA-style fallback to a chosen entry file. This avoids the clean-URL behavior of the Node `serve` CLI so that explicit `.html` entry files remain accessible without redirection. """ import argparse import signal import sys from functools import partial from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer from pathlib import Path from typing import Optional from urllib.parse import unquote, urlparse class PreviewRequestHandler(SimpleHTTPRequestHandler): """Serve static files with fallback to a configured entry file.""" def __init__(self, *args, directory: Optional[str] = None, entry: str = "index.html", **kwargs): self.entry = entry super().__init__(*args, directory=directory, **kwargs) def log_message(self, format, *args): """Quiet logging to avoid noisy stdout.""" return def send_head(self): """Serve requested path or fall back to the entry file for SPA routes.""" parsed = urlparse(self.path) rel_path = unquote(parsed.path.lstrip("/")) base_dir = Path(self.directory or ".") requested_path = (base_dir / rel_path).resolve() # If the requested path does not exist, fall back to the entry file if not requested_path.exists() or not str(requested_path).startswith(str(base_dir)): fallback = (base_dir / self.entry).resolve() if fallback.exists() and str(fallback).startswith(str(base_dir)): # Rewrite to entry for SPA-style routing self.path = "/" + self.entry else: self.send_error(404, "File not found") return None return super().send_head() def run_server(host: str, port: int, root: Path, entry: str) -> None: handler = partial(PreviewRequestHandler, directory=str(root), entry=entry) httpd = ThreadingHTTPServer((host, port), handler) def _shutdown(*_): httpd.shutdown() signal.signal(signal.SIGTERM, _shutdown) signal.signal(signal.SIGINT, _shutdown) try: httpd.serve_forever() finally: httpd.server_close() def main(): parser = argparse.ArgumentParser(description="Preview static server with entry fallback") parser.add_argument("--port", type=int, required=True, help="Port to bind") parser.add_argument("--root", type=str, required=True, help="Directory to serve") parser.add_argument("--entry", type=str, default="index.html", help="Entry file for SPA fallback") parser.add_argument("--host", type=str, default="0.0.0.0", help="Host to bind") args = parser.parse_args() root = Path(args.root).resolve() if not root.exists(): sys.stderr.write(f"Root directory does not exist: {root}\n") sys.exit(1) run_server(args.host, args.port, root, args.entry) if __name__ == "__main__": main()

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/answerlink/MCP-Workspace-Server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server