Skip to content

Commit aa24afd

Browse files
author
Henry Lee
committed
fix: avoid configuring root logger in mcpserver
1 parent 3d7b311 commit aa24afd

2 files changed

Lines changed: 66 additions & 10 deletions

File tree

src/mcp/server/mcpserver/utilities/logging.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,18 @@ def configure_logging(
2424
Args:
2525
level: The log level to use.
2626
"""
27-
handlers: list[logging.Handler] = []
28-
try:
29-
from rich.console import Console
30-
from rich.logging import RichHandler
27+
logger = logging.getLogger("mcp")
28+
if not logger.handlers:
29+
try:
30+
from rich.console import Console
31+
from rich.logging import RichHandler
3132

32-
handlers.append(RichHandler(console=Console(stderr=True), rich_tracebacks=True))
33-
except ImportError: # pragma: no cover
34-
pass
33+
handler: logging.Handler = RichHandler(console=Console(stderr=True), rich_tracebacks=True)
34+
except ImportError: # pragma: no cover
35+
handler = logging.StreamHandler()
3536

36-
if not handlers: # pragma: no cover
37-
handlers.append(logging.StreamHandler())
37+
handler.setFormatter(logging.Formatter("%(message)s"))
38+
logger.addHandler(handler)
3839

39-
logging.basicConfig(level=level, format="%(message)s", handlers=handlers)
40+
logger.setLevel(level)
41+
logger.propagate = True
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import logging
2+
from collections.abc import Iterator
3+
4+
import pytest
5+
6+
from mcp.server.mcpserver.utilities.logging import configure_logging
7+
8+
LoggingState = tuple[logging.Logger, logging.Logger]
9+
10+
11+
@pytest.fixture
12+
def restore_logging_state() -> Iterator[LoggingState]:
13+
root_logger = logging.getLogger()
14+
mcp_logger = logging.getLogger("mcp")
15+
mcp_handlers = list(mcp_logger.handlers)
16+
root_level = root_logger.level
17+
mcp_level = mcp_logger.level
18+
mcp_propagate = mcp_logger.propagate
19+
20+
mcp_logger.handlers.clear()
21+
22+
try:
23+
yield root_logger, mcp_logger
24+
finally:
25+
mcp_logger.handlers[:] = mcp_handlers
26+
root_logger.setLevel(root_level)
27+
mcp_logger.setLevel(mcp_level)
28+
mcp_logger.propagate = mcp_propagate
29+
30+
31+
def test_configure_logging_does_not_install_root_handler(restore_logging_state: LoggingState):
32+
root_logger, mcp_logger = restore_logging_state
33+
root_handlers = list(root_logger.handlers)
34+
root_logger.setLevel(logging.WARNING)
35+
36+
configure_logging("INFO")
37+
38+
assert root_logger.handlers == root_handlers
39+
assert root_logger.level == logging.WARNING
40+
assert len(mcp_logger.handlers) == 1
41+
assert mcp_logger.level == logging.INFO
42+
assert mcp_logger.propagate is True
43+
44+
45+
def test_configure_logging_reuses_mcp_handler(restore_logging_state: LoggingState):
46+
_, mcp_logger = restore_logging_state
47+
48+
configure_logging("INFO")
49+
handlers: list[logging.Handler] = list(mcp_logger.handlers)
50+
configure_logging("DEBUG")
51+
52+
assert mcp_logger.handlers == handlers
53+
assert mcp_logger.level == logging.DEBUG
54+
assert mcp_logger.propagate is True

0 commit comments

Comments
 (0)