All checks were successful
Run tests / test (pull_request) Successful in 31s
- add simple read-only MCP server for reading testdays and test results - add MCP server docs - add example testdays-mcp skill - extend tests to cover new features Fixes #108 Assisted-by: Claude Code
54 lines
2 KiB
Python
54 lines
2 KiB
Python
"""ASGI entry point for the Fedora Testdays application.
|
|
|
|
Serves the Flask WSGI app alongside the MCP server under a single
|
|
Starlette router. Gunicorn with UvicornWorker uses this as the
|
|
application target::
|
|
|
|
gunicorn asgi:application -k uvicorn.workers.UvicornWorker
|
|
"""
|
|
|
|
import logging
|
|
|
|
from asgiref.wsgi import WsgiToAsgi
|
|
from starlette.middleware.base import BaseHTTPMiddleware
|
|
from starlette.requests import Request
|
|
from starlette.responses import Response
|
|
from starlette.routing import Mount
|
|
|
|
from mcp_server import mcp
|
|
from testdays import create_app
|
|
|
|
LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
class _McpAccessLogMiddleware(BaseHTTPMiddleware):
|
|
"""Log /mcp requests in the same format as Flask's @after_request hook."""
|
|
|
|
async def dispatch(self, request: Request, call_next): # type: ignore[override]
|
|
response: Response = await call_next(request)
|
|
if request.url.path.startswith("/mcp"):
|
|
LOGGER.info(
|
|
'%s - "%s %s HTTP/%s" %s',
|
|
request.client.host if request.client else "-",
|
|
request.method,
|
|
request.url.path,
|
|
request.scope.get("http_version", "1.1"),
|
|
response.status_code,
|
|
)
|
|
return response
|
|
|
|
|
|
# Build the top-level ASGI app directly from the MCP instance.
|
|
# streamable_http_app() creates a Starlette application with the MCP
|
|
# handler at "/mcp" (the default but also set explicitly in
|
|
# mcp_server.py) We then mount the WSGI-converted Flask app at /.
|
|
# Since this happens after the "/mcp" route is set up, it will route
|
|
# everything except /mcp to the Flask app.
|
|
# The MCP instance creates its own Flask app instance (cached per-process)
|
|
# separate from the WSGI app below. They share the same config and database.
|
|
#
|
|
# Pattern adapted from: github.com/modelcontextprotocol/python-sdk/issues/1367
|
|
flask_app = create_app()
|
|
application = mcp.streamable_http_app()
|
|
application.router.routes.append(Mount("/", app=WsgiToAsgi(flask_app)))
|
|
application.add_middleware(_McpAccessLogMiddleware)
|