From c2b434909ef3a82b69d5cefa91ef3039d02f90b4 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 12 Aug 2026 05:21:36 +0000 Subject: [PATCH] [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 --- src/mcp/server/fastmcp/server.py | 7 +++++++ tests/server/fastmcp/test_server.py | 15 +++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/mcp/server/fastmcp/server.py b/src/mcp/server/fastmcp/server.py index e915a12bfd..9888832268 100644 --- a/src/mcp/server/fastmcp/server.py +++ b/src/mcp/server/fastmcp/server.py @@ -1087,6 +1087,13 @@ async def get_prompt(self, name: str, arguments: dict[str, Any] | None = None) - raise ValueError(str(e)) +# `Settings.lifespan` forward-references `FastMCP`, which is defined after `Settings`, +# so the annotation is unresolved when the class body executes. Rebuild the model now +# that `FastMCP` exists, otherwise settings sources may fail to resolve the field and +# pydantic-settings >= 2.15 warns about the incomplete definition on instantiation. +Settings.model_rebuild() + + class StreamableHTTPASGIApp: """ ASGI application for Streamable HTTP server transport. diff --git a/tests/server/fastmcp/test_server.py b/tests/server/fastmcp/test_server.py index b134489bc5..2f471c90bc 100644 --- a/tests/server/fastmcp/test_server.py +++ b/tests/server/fastmcp/test_server.py @@ -183,6 +183,21 @@ async def test_add_resource_decorator_incorrect_usage(self): def get_data(x: str) -> str: # pragma: no cover return f"Data: {x}" + def test_settings_model_is_fully_defined_after_import(self): + """Regression test for #3294: `Settings.lifespan` forward-references `FastMCP`, + which is defined later in the module, so `Settings` must be rebuilt once + `FastMCP` exists. An unresolved forward reference leaves the model incomplete: + settings sources may fail to resolve the field, and pydantic-settings >= 2.15 + warns (`IncompleteFieldDefinitionWarning`) on every `FastMCP()` construction. + """ + from typing import ForwardRef + + from mcp.server.fastmcp.server import Settings + + assert Settings.__pydantic_complete__ is True + lifespan = Settings.model_fields["lifespan"] + assert not isinstance(lifespan.annotation, ForwardRef) + class TestDnsRebindingProtection: """Tests for automatic DNS rebinding protection on localhost."""