When `python -m arcade_mcp_server` was executed, we would get the following Runtime Warning: ``` <frozen runpy>:128: RuntimeWarning: 'arcade_mcp_server.__main__' found in sys.modules after import of package 'arcade_mcp_server', but prior to execution of 'arcade_mcp_server.__main__'; this may result in unpredictable behaviour ``` This PR resolves this. This PR is mainly just moving existing functions to new locations; a refactor <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Primarily a module-organization refactor with minimal behavior change; main risk is import-path regressions for internal callers and stdio/CLI startup wiring. > > **Overview** > Fixes the `python -m arcade_mcp_server` runtime warning by refactoring `arcade_mcp_server.__main__` to be a thin CLI entrypoint and moving its reusable logic into import-safe modules. > > Extracts stdio execution and tool discovery into a new `arcade_mcp_server.stdio_runner` (`initialize_tool_catalog`, `run_stdio_server`) and moves `setup_logging` into `logging_utils`, updating `MCPApp`, the FastAPI `worker`, and tests to import from the new locations. Bumps package version to `1.17.3`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 210475acea7c5df44fc66be2bde06f1f0c806c4e. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
56 lines
1.7 KiB
Python
56 lines
1.7 KiB
Python
"""Shared logging utilities for MCP server."""
|
|
|
|
import logging
|
|
import sys
|
|
|
|
from loguru import logger
|
|
|
|
|
|
class LoguruInterceptHandler(logging.Handler):
|
|
"""Intercept standard logging and route to Loguru.
|
|
|
|
This handler bridges the standard Python logging module with Loguru,
|
|
ensuring all logs (from both systems) use the same formatting.
|
|
"""
|
|
|
|
def emit(self, record: logging.LogRecord) -> None:
|
|
try:
|
|
level = logger.level(record.levelname).name
|
|
except ValueError:
|
|
level = str(record.levelno)
|
|
|
|
logger.opt(exception=record.exc_info).log(level, record.getMessage())
|
|
|
|
|
|
def intercept_standard_logging() -> None:
|
|
"""Configure standard logging to route through Loguru.
|
|
|
|
This should be called after Loguru is configured to ensure all
|
|
standard logging calls are intercepted and formatted consistently.
|
|
"""
|
|
logging.basicConfig(handlers=[LoguruInterceptHandler()], level=0, force=True)
|
|
|
|
|
|
def setup_logging(level: str = "INFO", stdio_mode: bool = False) -> None:
|
|
"""Configure logging with Loguru."""
|
|
logger.remove()
|
|
|
|
# In stdio mode, use stderr (stdout is reserved for JSON-RPC)
|
|
sink = sys.stderr if stdio_mode else sys.stdout
|
|
|
|
if level == "DEBUG":
|
|
format_str = "<level>{level: <8}</level> | <green>{time:HH:mm:ss}</green> | <cyan>{name}:{line}</cyan> | <level>{message}</level>"
|
|
else:
|
|
format_str = (
|
|
"<level>{level: <8}</level> | <green>{time:HH:mm:ss}</green> | <level>{message}</level>"
|
|
)
|
|
|
|
logger.add(
|
|
sink,
|
|
format=format_str,
|
|
level=level,
|
|
colorize=(not stdio_mode),
|
|
diagnose=(level == "DEBUG"),
|
|
)
|
|
|
|
intercept_standard_logging()
|