import json from pathlib import Path from typing import Any from config import MCPBundle from mcp.server.fastmcp import FastMCP class MCPServer: """MCP server serving a pre-built documentation bundle.""" def __init__(self, bundle: MCPBundle) -> None: self.mcp_root = bundle.root self.app = FastMCP( name=f"{bundle.name}-mcp", host="0.0.0.0", port=bundle.port, ) self._register_resources() self._register_tools() # ------------------------------------------------------------------ # Helpers # ------------------------------------------------------------------ def _read_json(self, path: Path) -> Any: if not path.exists(): return {"error": "not_found", "path": str(path)} return json.loads(path.read_text(encoding="utf-8")) # ------------------------------------------------------------------ # MCP resources # ------------------------------------------------------------------ def _register_resources(self) -> None: @self.app.resource("doc://index") def index(): return self._read_json(self.mcp_root / "index.json") @self.app.resource("doc://nav") def nav(): return self._read_json(self.mcp_root / "nav.json") @self.app.resource("doc://modules/{module}") def module(module: str): return self._read_json(self.mcp_root / "modules" / f"{module}.json") # ------------------------------------------------------------------ # MCP tools # ------------------------------------------------------------------ def _register_tools(self) -> None: @self.app.tool() def ping() -> str: return "pong" # ------------------------------------------------------------------ # ASGI exposure # ------------------------------------------------------------------ @property def asgi(self): return self.app