Skip to content

Commit c2b4349

Browse files
committed
[v1.x] Rebuild FastMCP Settings once FastMCP is defined
Settings.lifespan forward-references FastMCP, which is defined later in the module, so the annotation was still an unresolved ForwardRef after import and the model stayed incomplete. Settings sources could fail to resolve the field, and pydantic-settings >= 2.15 emits IncompleteFieldDefinitionWarning on every FastMCP() construction, which breaks consumers that promote warnings to errors. Rebuild the Settings model at module scope once FastMCP exists, and add a regression test asserting the model is fully defined after import. Github-Issue: #3294 Reported-by: igorkorsunsky
1 parent 98b7159 commit c2b4349

2 files changed

Lines changed: 22 additions & 0 deletions

File tree

src/mcp/server/fastmcp/server.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1087,6 +1087,13 @@ async def get_prompt(self, name: str, arguments: dict[str, Any] | None = None) -
10871087
raise ValueError(str(e))
10881088

10891089

1090+
# `Settings.lifespan` forward-references `FastMCP`, which is defined after `Settings`,
1091+
# so the annotation is unresolved when the class body executes. Rebuild the model now
1092+
# that `FastMCP` exists, otherwise settings sources may fail to resolve the field and
1093+
# pydantic-settings >= 2.15 warns about the incomplete definition on instantiation.
1094+
Settings.model_rebuild()
1095+
1096+
10901097
class StreamableHTTPASGIApp:
10911098
"""
10921099
ASGI application for Streamable HTTP server transport.

tests/server/fastmcp/test_server.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,21 @@ async def test_add_resource_decorator_incorrect_usage(self):
183183
def get_data(x: str) -> str: # pragma: no cover
184184
return f"Data: {x}"
185185

186+
def test_settings_model_is_fully_defined_after_import(self):
187+
"""Regression test for #3294: `Settings.lifespan` forward-references `FastMCP`,
188+
which is defined later in the module, so `Settings` must be rebuilt once
189+
`FastMCP` exists. An unresolved forward reference leaves the model incomplete:
190+
settings sources may fail to resolve the field, and pydantic-settings >= 2.15
191+
warns (`IncompleteFieldDefinitionWarning`) on every `FastMCP()` construction.
192+
"""
193+
from typing import ForwardRef
194+
195+
from mcp.server.fastmcp.server import Settings
196+
197+
assert Settings.__pydantic_complete__ is True
198+
lifespan = Settings.model_fields["lifespan"]
199+
assert not isinstance(lifespan.annotation, ForwardRef)
200+
186201

187202
class TestDnsRebindingProtection:
188203
"""Tests for automatic DNS rebinding protection on localhost."""

0 commit comments

Comments
 (0)