|
15 | 15 | from __future__ import annotations |
16 | 16 |
|
17 | 17 | import contextlib |
| 18 | +import copy |
18 | 19 | import json |
| 20 | +import logging |
19 | 21 | import sys |
20 | 22 |
|
21 | 23 | from mcp.server.auth.middleware.auth_context import AuthContextMiddleware |
|
49 | 51 | } |
50 | 52 |
|
51 | 53 |
|
| 54 | +class HealthzAccessLogFilter(logging.Filter): |
| 55 | + """Drop noisy load-balancer health probes from uvicorn access logs.""" |
| 56 | + |
| 57 | + def filter(self, record: logging.LogRecord) -> bool: |
| 58 | + args = record.args |
| 59 | + if isinstance(args, tuple) and len(args) >= 3: |
| 60 | + method = args[1] |
| 61 | + path = str(args[2]).split("?", 1)[0] |
| 62 | + return not (method == "GET" and path == "/healthz") |
| 63 | + |
| 64 | + return "GET /healthz HTTP/" not in record.getMessage() |
| 65 | + |
| 66 | + |
52 | 67 | def _log(message: str) -> None: |
53 | 68 | print(f"[appwrite-mcp][http] {message}", file=sys.stderr, flush=True) |
54 | 69 |
|
@@ -166,7 +181,14 @@ async def lifespan(app: Starlette): |
166 | 181 |
|
167 | 182 | def run_http(*, host: str = "0.0.0.0", port: int = 8000) -> None: |
168 | 183 | import uvicorn |
| 184 | + from uvicorn.config import LOGGING_CONFIG |
169 | 185 |
|
170 | 186 | app = build_app() |
| 187 | + log_config = copy.deepcopy(LOGGING_CONFIG) |
| 188 | + log_config.setdefault("filters", {})["hide_healthz"] = { |
| 189 | + "()": "mcp_server_appwrite.http_app.HealthzAccessLogFilter" |
| 190 | + } |
| 191 | + log_config["handlers"]["access"]["filters"] = ["hide_healthz"] |
| 192 | + |
171 | 193 | _log(f"Serving on http://{host}:{port} (resource path: /mcp)") |
172 | | - uvicorn.run(app, host=host, port=port) |
| 194 | + uvicorn.run(app, host=host, port=port, log_config=log_config) |
0 commit comments