Skip to content

Commit 86e588e

Browse files
committed
review: warn at config construction, per branch, and on the contradiction
1 parent c51b302 commit 86e588e

4 files changed

Lines changed: 54 additions & 21 deletions

File tree

‎docs/integrations/fastmcp.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,9 @@ FastMcpConfig(
6262
Enabled, each message is logged with its `method`, `source` and `type`, plus `duration` in
6363
nanoseconds. A message that raises is logged at exception level and the exception is re-raised.
6464

65-
`logging_turn_off_middleware` still works and keeps the behaviour its setter asked for, but it is
66-
superseded and warns: `logging_turn_off_middleware=False` turns the middleware on, `True` leaves it
67-
off.
65+
`logging_turn_off_middleware` still works but is superseded and warns:
66+
`logging_turn_off_middleware=False` turns the middleware on, `True` leaves it off. If you set both
67+
fields, `fastmcp_logging_middleware_enabled` wins and the superseded one is reported as ignored.
6868

6969
Set `health_checks_enabled=False` to omit the health route.
7070

‎docs/introduction/configuration.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ The per-MCP-message access log is **off by default**:
261261

262262
- `fastmcp_logging_middleware_enabled` - turn on the access log (default: `False`).
263263
- `logging_turn_off_middleware` - superseded by the field above and warns when set. `False` turns the
264-
middleware on, `True` leaves it off.
264+
middleware on, `True` leaves it off, and if both are set the field above wins.
265265

266266
See [the FastMCP integration guide](../integrations/fastmcp.md#logging) for what gets logged.
267267

‎lite_bootstrap/bootstrappers/fastmcp_bootstrapper.py‎

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,30 @@ class FastMcpConfig(HealthChecksConfig, LoggingConfig, PrometheusConfig, Pyrosco
8585
fastmcp_logging_middleware_enabled: bool = False
8686
logging_turn_off_middleware: bool | None = None
8787

88+
def __post_init__(self) -> None:
89+
# Not super(): the missing-dependency tests reload this module, which rebinds the global
90+
# name, so `super(FastMcpConfig, self)` would not match the instance's own class.
91+
HealthChecksConfig.__post_init__(self)
92+
if self.logging_turn_off_middleware is None:
93+
return
94+
if self.fastmcp_logging_middleware_enabled:
95+
warn_at_caller(
96+
"logging_turn_off_middleware is ignored because fastmcp_logging_middleware_enabled "
97+
"is set; drop logging_turn_off_middleware."
98+
)
99+
return
100+
if self.logging_turn_off_middleware:
101+
warn_at_caller(
102+
"logging_turn_off_middleware is superseded by fastmcp_logging_middleware_enabled, "
103+
"which is False by default; drop logging_turn_off_middleware."
104+
)
105+
return
106+
warn_at_caller(
107+
"logging_turn_off_middleware is superseded by fastmcp_logging_middleware_enabled; "
108+
"set fastmcp_logging_middleware_enabled=True instead."
109+
)
110+
object.__setattr__(self, "fastmcp_logging_middleware_enabled", True)
111+
88112

89113
@dataclasses.dataclass(kw_only=True)
90114
class FastMcpHealthChecksInstrument(HealthChecksInstrument):
@@ -134,20 +158,10 @@ class FastMcpLoggingInstrument(LoggingInstrument):
134158

135159
def bootstrap(self) -> None:
136160
super().bootstrap()
137-
if not self._middleware_enabled():
161+
if not self.bootstrap_config.fastmcp_logging_middleware_enabled:
138162
return
139163
self.bootstrap_config.application.add_middleware(FastMcpLoggingMiddleware())
140164

141-
def _middleware_enabled(self) -> bool:
142-
config = self.bootstrap_config
143-
if config.logging_turn_off_middleware is None:
144-
return config.fastmcp_logging_middleware_enabled
145-
warn_at_caller(
146-
"logging_turn_off_middleware is superseded by fastmcp_logging_middleware_enabled, "
147-
"which is False by default; set fastmcp_logging_middleware_enabled=True to log messages."
148-
)
149-
return not config.logging_turn_off_middleware
150-
151165

152166
class FastMcpBootstrapper(BaseBootstrapper["FastMCP[typing.Any]"]):
153167
__slots__ = "bootstrap_config", "instruments"

‎tests/test_fastmcp_bootstrap.py‎

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -249,14 +249,14 @@ def test_fastmcp_logging_middleware_is_mounted_when_enabled() -> None:
249249
ids=["turn_off_false_still_mounts", "turn_off_true_does_not_mount"],
250250
)
251251
def test_fastmcp_logging_turn_off_middleware_still_works(turn_off: bool, expected_count: int) -> None:
252-
"""The superseded flag keeps the behaviour its setter asked for, and says it is superseded."""
253-
config = _make_test_config(logging_turn_off_middleware=turn_off)
252+
"""The superseded flag keeps the behaviour it was set for, and says that it is superseded."""
254253
with warnings.catch_warnings(record=True) as caught:
255254
warnings.simplefilter("always")
256-
mounted = _mounted_logging_middleware(config)
255+
config = _make_test_config(logging_turn_off_middleware=turn_off)
257256

258257
assert [str(one.message) for one in caught if "logging_turn_off_middleware" in str(one.message)]
259-
assert len(mounted) == expected_count
258+
assert config.fastmcp_logging_middleware_enabled is (not turn_off)
259+
assert len(_mounted_logging_middleware(config)) == expected_count
260260

261261

262262
def test_fastmcp_logging_turn_off_middleware_warning_names_the_caller() -> None:
@@ -265,14 +265,33 @@ def test_fastmcp_logging_turn_off_middleware_warning_names_the_caller() -> None:
265265
Same reason as the config-validation warnings in test_config_cascade.py: every frame between
266266
the warn call and the user is lite-bootstrap's, and the distance is not a constant.
267267
"""
268-
config = _make_test_config(logging_turn_off_middleware=True)
269268
with warnings.catch_warnings(record=True) as caught:
270269
warnings.simplefilter("always")
271-
_mounted_logging_middleware(config)
270+
_make_test_config(logging_turn_off_middleware=True)
272271

273272
assert warning_source_files(caught, UserWarning) == [__file__]
274273

275274

275+
@pytest.mark.parametrize("overrides", [{}, {"fastmcp_logging_middleware_enabled": True}], ids=["default", "enabled"])
276+
def test_fastmcp_logging_warns_nothing_without_the_superseded_flag(overrides: dict[str, bool]) -> None:
277+
with warnings.catch_warnings(record=True) as caught:
278+
warnings.simplefilter("always")
279+
_make_test_config(**overrides)
280+
281+
assert [str(one.message) for one in caught] == []
282+
283+
284+
def test_fastmcp_logging_explicit_flag_wins_over_the_superseded_one() -> None:
285+
"""Setting both keeps the current field and says the superseded one is ignored."""
286+
with warnings.catch_warnings(record=True) as caught:
287+
warnings.simplefilter("always")
288+
config = _make_test_config(fastmcp_logging_middleware_enabled=True, logging_turn_off_middleware=True)
289+
290+
assert [one for one in caught if "is ignored because" in str(one.message)]
291+
assert config.fastmcp_logging_middleware_enabled is True
292+
assert len(_mounted_logging_middleware(config)) == 1
293+
294+
276295
@pytest.mark.parametrize(
277296
("package_name", "extra_config"),
278297
[

0 commit comments

Comments
 (0)