web package
This commit is contained in:
@@ -1,31 +1,7 @@
|
||||
from fastmcp import FastMCP
|
||||
from personal_mcp.mcp import mcp
|
||||
from personal_mcp.web.app import app
|
||||
|
||||
from personal_mcp.catalog.server import catalog_server
|
||||
from personal_mcp.skills.fastapi_async_sqlalchemy_modernization.server import (
|
||||
fastapi_async_sqlalchemy_modernization_server,
|
||||
)
|
||||
from personal_mcp.skills.fastapi_uv_docker.server import fastapi_uv_docker_server
|
||||
from personal_mcp.skills.nicegui.server import nicegui_server
|
||||
from personal_mcp.skills.nicegui_ui_customization.server import (
|
||||
nicegui_ui_customization_server,
|
||||
)
|
||||
from personal_mcp.skills.pytest_scaffolding.server import pytest_scaffolding_server
|
||||
from personal_mcp.skills.python_logging_dictconfig.server import (
|
||||
python_logging_dictconfig_server,
|
||||
)
|
||||
|
||||
mcp = FastMCP("personal-mcp")
|
||||
|
||||
mcp.mount(catalog_server, namespace="catalog")
|
||||
mcp.mount(
|
||||
fastapi_async_sqlalchemy_modernization_server,
|
||||
namespace="fastapi_async_sqlalchemy_modernization",
|
||||
)
|
||||
mcp.mount(nicegui_server, namespace="nicegui")
|
||||
mcp.mount(nicegui_ui_customization_server, namespace="nicegui_ui_customization")
|
||||
mcp.mount(pytest_scaffolding_server, namespace="pytest_scaffolding")
|
||||
mcp.mount(python_logging_dictconfig_server, namespace="python_logging_dictconfig")
|
||||
mcp.mount(fastapi_uv_docker_server, namespace="fastapi_uv_docker")
|
||||
__all__ = ["app", "main", "mcp"]
|
||||
|
||||
|
||||
def main() -> None:
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
from fastmcp import FastMCP
|
||||
|
||||
from personal_mcp.catalog.server import catalog_server
|
||||
from personal_mcp.skills.fastapi_async_sqlalchemy_modernization.server import (
|
||||
fastapi_async_sqlalchemy_modernization_server,
|
||||
)
|
||||
from personal_mcp.skills.fastapi_uv_docker.server import fastapi_uv_docker_server
|
||||
from personal_mcp.skills.nicegui.server import nicegui_server
|
||||
from personal_mcp.skills.nicegui_ui_customization.server import (
|
||||
nicegui_ui_customization_server,
|
||||
)
|
||||
from personal_mcp.skills.pytest_scaffolding.server import pytest_scaffolding_server
|
||||
from personal_mcp.skills.python_logging_dictconfig.server import (
|
||||
python_logging_dictconfig_server,
|
||||
)
|
||||
|
||||
mcp = FastMCP("personal-mcp")
|
||||
|
||||
mcp.mount(catalog_server, namespace="catalog")
|
||||
mcp.mount(
|
||||
fastapi_async_sqlalchemy_modernization_server,
|
||||
namespace="fastapi_async_sqlalchemy_modernization",
|
||||
)
|
||||
mcp.mount(nicegui_server, namespace="nicegui")
|
||||
mcp.mount(nicegui_ui_customization_server, namespace="nicegui_ui_customization")
|
||||
mcp.mount(pytest_scaffolding_server, namespace="pytest_scaffolding")
|
||||
mcp.mount(python_logging_dictconfig_server, namespace="python_logging_dictconfig")
|
||||
mcp.mount(fastapi_uv_docker_server, namespace="fastapi_uv_docker")
|
||||
@@ -0,0 +1 @@
|
||||
"""FastAPI web runtime for personal MCP."""
|
||||
@@ -0,0 +1,36 @@
|
||||
from fastapi import FastAPI
|
||||
|
||||
from personal_mcp.mcp import mcp
|
||||
from personal_mcp.web.config import Settings, get_settings
|
||||
from personal_mcp.web.docs_mount import mount_docs_static
|
||||
from personal_mcp.web.health import router as health_router
|
||||
|
||||
|
||||
def create_app(settings: Settings | None = None) -> FastAPI:
|
||||
runtime_settings = settings or get_settings()
|
||||
mcp_app = mcp.http_app(
|
||||
path=runtime_settings.mcp_route,
|
||||
json_response=True,
|
||||
stateless_http=True,
|
||||
transport="http",
|
||||
)
|
||||
app = FastAPI(
|
||||
debug=runtime_settings.debug,
|
||||
docs_url=None,
|
||||
redoc_url=None,
|
||||
openapi_url=None,
|
||||
lifespan=mcp_app.lifespan,
|
||||
)
|
||||
app.state.settings = runtime_settings
|
||||
|
||||
app.include_router(health_router)
|
||||
mount_docs_static(
|
||||
app,
|
||||
docs_route=runtime_settings.docs_route,
|
||||
site_dir=runtime_settings.site_dir,
|
||||
)
|
||||
app.mount("/", mcp_app, name="mcp")
|
||||
return app
|
||||
|
||||
|
||||
app = create_app()
|
||||
@@ -0,0 +1,28 @@
|
||||
from pathlib import Path
|
||||
|
||||
from pydantic import Field
|
||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
|
||||
_REPO_ROOT = Path(__file__).resolve().parents[3]
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
"""Runtime settings for the HTTP MCP and docs server."""
|
||||
|
||||
model_config = SettingsConfigDict(
|
||||
env_file=".env",
|
||||
env_prefix="PERSONAL_MCP_",
|
||||
extra="ignore",
|
||||
)
|
||||
|
||||
host: str = "127.0.0.1"
|
||||
port: int = 8000
|
||||
debug: bool = False
|
||||
log_level: str = "info"
|
||||
docs_route: str = "/docs"
|
||||
mcp_route: str = "/mcp"
|
||||
site_dir: Path = Field(default=_REPO_ROOT / "site")
|
||||
|
||||
|
||||
def get_settings() -> Settings:
|
||||
return Settings()
|
||||
@@ -0,0 +1,40 @@
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import FastAPI, Response, status
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
|
||||
|
||||
def mount_docs_static(app: FastAPI, *, docs_route: str, site_dir: Path) -> None:
|
||||
"""Mount the pre-built static docs site, or expose a clear missing-build response."""
|
||||
normalized_route = docs_route.rstrip("/") or "/docs"
|
||||
|
||||
if site_dir.is_dir():
|
||||
app.mount(
|
||||
normalized_route,
|
||||
StaticFiles(directory=site_dir, html=True),
|
||||
name="docs",
|
||||
)
|
||||
return
|
||||
|
||||
async def docs_not_built() -> Response:
|
||||
return Response(
|
||||
content=(
|
||||
"Static docs have not been built yet. "
|
||||
"Run `uv run zensical build` before using this route."
|
||||
),
|
||||
media_type="text/plain",
|
||||
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
||||
)
|
||||
|
||||
app.add_api_route(
|
||||
normalized_route,
|
||||
docs_not_built,
|
||||
methods=["GET"],
|
||||
include_in_schema=False,
|
||||
)
|
||||
app.add_api_route(
|
||||
f"{normalized_route}/{{path:path}}",
|
||||
docs_not_built,
|
||||
methods=["GET"],
|
||||
include_in_schema=False,
|
||||
)
|
||||
@@ -0,0 +1,8 @@
|
||||
from fastapi import APIRouter
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/healthz", include_in_schema=False)
|
||||
def healthz() -> dict[str, str]:
|
||||
return {"status": "ok"}
|
||||
Reference in New Issue
Block a user