|
1 | 1 | """Logging utilities for FastMCP."""
|
2 | 2 |
|
3 | 3 | import logging
|
4 |
| -from typing import Literal |
| 4 | +from collections.abc import Mapping |
| 5 | +from typing import Any, Literal |
5 | 6 |
|
6 | 7 |
|
7 | 8 | def get_logger(name: str) -> logging.Logger:
|
@@ -41,3 +42,52 @@ def configure_logging(
|
41 | 42 | format="%(message)s",
|
42 | 43 | handlers=handlers,
|
43 | 44 | )
|
| 45 | + |
| 46 | + |
| 47 | +# --------------------------------------------------------------------------- |
| 48 | +# Helper – redact sensitive data before logging |
| 49 | +# --------------------------------------------------------------------------- |
| 50 | + |
| 51 | + |
| 52 | +def redact_sensitive_data( |
| 53 | + data: Mapping[str, Any] | None, |
| 54 | + sensitive_keys: set[str] | None = None, |
| 55 | +) -> Mapping[str, Any] | None: |
| 56 | + """Return a shallow copy with sensitive values replaced by "***". |
| 57 | +
|
| 58 | + This shared helper can be used across the code-base (e.g. the transparent |
| 59 | + OAuth proxy) to ensure we treat secrets consistently. |
| 60 | +
|
| 61 | + Parameters |
| 62 | + ---------- |
| 63 | + data: |
| 64 | + Original mapping (typically request/response payload). If *None* the |
| 65 | + function simply returns *None*. |
| 66 | + sensitive_keys: |
| 67 | + Optional set of keys that should be hidden; defaults to a common list |
| 68 | + of OAuth-related secrets. |
| 69 | + """ |
| 70 | + |
| 71 | + if data is None: |
| 72 | + return None |
| 73 | + |
| 74 | + sensitive_keys = sensitive_keys or { |
| 75 | + "client_secret", |
| 76 | + "authorization", |
| 77 | + "access_token", |
| 78 | + "refresh_token", |
| 79 | + "code", |
| 80 | + } |
| 81 | + |
| 82 | + redacted: dict[str, Any] = {} |
| 83 | + for key, value in data.items(): |
| 84 | + if key.lower() in sensitive_keys: |
| 85 | + # Show a short prefix of auth codes; redact everything else |
| 86 | + if key.lower() == "code" and isinstance(value, str): |
| 87 | + redacted[key] = value[:8] + "..." if len(value) > 8 else "***" |
| 88 | + else: |
| 89 | + redacted[key] = "***" |
| 90 | + else: |
| 91 | + redacted[key] = value |
| 92 | + |
| 93 | + return redacted |
0 commit comments