51 lines
1.6 KiB
Python
51 lines
1.6 KiB
Python
from collections.abc import Awaitable, Callable
|
|
from typing import TypeAlias
|
|
|
|
from mcp.client.session import LoggingFnT
|
|
from mcp.types import LoggingMessageNotificationParams
|
|
|
|
from fastmcp.utilities.logging import get_logger
|
|
|
|
logger = get_logger(__name__)
|
|
|
|
LogMessage: TypeAlias = LoggingMessageNotificationParams
|
|
LogHandler: TypeAlias = Callable[[LogMessage], Awaitable[None]]
|
|
|
|
|
|
async def default_log_handler(message: LogMessage) -> None:
|
|
"""Default handler that properly routes server log messages to appropriate log levels."""
|
|
msg = message.data.get("msg", str(message))
|
|
extra = message.data.get("extra", {})
|
|
|
|
# Map MCP log levels to Python logging levels
|
|
level_map = {
|
|
"debug": logger.debug,
|
|
"info": logger.info,
|
|
"notice": logger.info, # Python doesn't have 'notice', map to info
|
|
"warning": logger.warning,
|
|
"error": logger.error,
|
|
"critical": logger.critical,
|
|
"alert": logger.critical, # Map alert to critical
|
|
"emergency": logger.critical, # Map emergency to critical
|
|
}
|
|
|
|
# Get the appropriate logging function based on the message level
|
|
log_fn = level_map.get(message.level.lower(), logger.info)
|
|
|
|
# Include logger name if available
|
|
if message.logger:
|
|
msg = f"[{message.logger}] {msg}"
|
|
|
|
# Log with appropriate level and extra data
|
|
log_fn(f"Server log: {msg}", extra=extra)
|
|
|
|
|
|
def create_log_callback(handler: LogHandler | None = None) -> LoggingFnT:
|
|
if handler is None:
|
|
handler = default_log_handler
|
|
|
|
async def log_callback(params: LoggingMessageNotificationParams) -> None:
|
|
await handler(params)
|
|
|
|
return log_callback
|