Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 12 additions & 10 deletions src/mcp/server/mcpserver/utilities/logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,18 @@ def configure_logging(
Args:
level: The log level to use.
"""
handlers: list[logging.Handler] = []
try:
from rich.console import Console
from rich.logging import RichHandler
logger = logging.getLogger("mcp")
if not logger.handlers:
try:
from rich.console import Console
from rich.logging import RichHandler

handlers.append(RichHandler(console=Console(stderr=True), rich_tracebacks=True))
except ImportError: # pragma: no cover
pass
handler: logging.Handler = RichHandler(console=Console(stderr=True), rich_tracebacks=True)
except ImportError: # pragma: no cover
handler = logging.StreamHandler()

if not handlers: # pragma: no cover
handlers.append(logging.StreamHandler())
handler.setFormatter(logging.Formatter("%(message)s"))
logger.addHandler(handler)

logging.basicConfig(level=level, format="%(message)s", handlers=handlers)
logger.setLevel(level)
logger.propagate = True
54 changes: 54 additions & 0 deletions tests/server/mcpserver/test_logging.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import logging
from collections.abc import Iterator

import pytest

from mcp.server.mcpserver.utilities.logging import configure_logging

LoggingState = tuple[logging.Logger, logging.Logger]


@pytest.fixture
def restore_logging_state() -> Iterator[LoggingState]:
root_logger = logging.getLogger()
mcp_logger = logging.getLogger("mcp")
mcp_handlers = list(mcp_logger.handlers)
root_level = root_logger.level
mcp_level = mcp_logger.level
mcp_propagate = mcp_logger.propagate

mcp_logger.handlers.clear()

try:
yield root_logger, mcp_logger
finally:
mcp_logger.handlers[:] = mcp_handlers
root_logger.setLevel(root_level)
mcp_logger.setLevel(mcp_level)
mcp_logger.propagate = mcp_propagate


def test_configure_logging_does_not_install_root_handler(restore_logging_state: LoggingState):
root_logger, mcp_logger = restore_logging_state
root_handlers = list(root_logger.handlers)
root_logger.setLevel(logging.WARNING)

configure_logging("INFO")

assert root_logger.handlers == root_handlers
assert root_logger.level == logging.WARNING
assert len(mcp_logger.handlers) == 1
assert mcp_logger.level == logging.INFO
assert mcp_logger.propagate is True


def test_configure_logging_reuses_mcp_handler(restore_logging_state: LoggingState):
_, mcp_logger = restore_logging_state

configure_logging("INFO")
handlers: list[logging.Handler] = list(mcp_logger.handlers)
configure_logging("DEBUG")

assert mcp_logger.handlers == handlers
assert mcp_logger.level == logging.DEBUG
assert mcp_logger.propagate is True
Loading