- collect.py: copy repo MCP bundles to ROOT/<name>/mcp (instead of ROOT/mcp/<name>); add nginx location guard to deny /<name>/mcp/ - config.py: bundle roots now point to <repo>/mcp and standards/mcp for static bundles - Rename core.py -> mcp_server.py and update imports in main.py and registry.py - Dockerfile: per-repo MCP COPYs under /app/<name>/mcp, drop blog copy; add ports 8008/8009 in .drone.yml - Restore standards/mcp/libraries.json from git for registry server
64 lines
1.9 KiB
Python
64 lines
1.9 KiB
Python
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
|