From 2c9cae9a98d57d885abd9b81b8a6544e42e891c0 Mon Sep 17 00:00:00 2001 From: Jeremiah Lowin <153965+jlowin@users.noreply.github.com> Date: Sat, 17 Jan 2026 14:42:45 -0500 Subject: [PATCH] refactor: reverse visibility for get_prompt/_get_prompt methods --- src/fastmcp/server/middleware/authorization.py | 2 +- src/fastmcp/server/providers/aggregate.py | 4 ++-- src/fastmcp/server/providers/base.py | 8 ++++---- src/fastmcp/server/providers/fastmcp_provider.py | 6 +++--- src/fastmcp/server/providers/filesystem.py | 4 ++-- src/fastmcp/server/providers/local_provider.py | 2 +- src/fastmcp/server/server.py | 8 ++++---- tests/server/test_providers.py | 2 +- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/fastmcp/server/middleware/authorization.py b/src/fastmcp/server/middleware/authorization.py index 1ff33c4a3..46038f6c9 100644 --- a/src/fastmcp/server/middleware/authorization.py +++ b/src/fastmcp/server/middleware/authorization.py @@ -295,7 +295,7 @@ class AuthMiddleware(Middleware): ) # Get prompt (component auth is checked in get_prompt, raises if unauthorized) - prompt = await fastmcp.fastmcp._get_prompt(prompt_name) + prompt = await fastmcp.fastmcp.get_prompt(prompt_name) if prompt is None: raise AuthorizationError( f"Authorization failed for prompt '{prompt_name}': prompt not found" diff --git a/src/fastmcp/server/providers/aggregate.py b/src/fastmcp/server/providers/aggregate.py index bec980b14..b0a7bcf77 100644 --- a/src/fastmcp/server/providers/aggregate.py +++ b/src/fastmcp/server/providers/aggregate.py @@ -217,7 +217,7 @@ class AggregateProvider(Provider): ) return self._collect_list_results(results, "list_prompts") - async def get_prompt( + async def _get_prompt( self, name: str, version: VersionSpec | None = None ) -> Prompt | None: """Get prompt by name. @@ -228,7 +228,7 @@ class AggregateProvider(Provider): If specified, returns highest version matching the spec from any provider. """ results = await gather( - *[p._get_prompt(name, version) for p in self._providers], + *[p.get_prompt(name, version) for p in self._providers], return_exceptions=True, ) return self._get_highest_version_result(results, f"get_prompt({name!r})") # type: ignore[return-value] diff --git a/src/fastmcp/server/providers/base.py b/src/fastmcp/server/providers/base.py index a06194f51..d5797ab10 100644 --- a/src/fastmcp/server/providers/base.py +++ b/src/fastmcp/server/providers/base.py @@ -217,7 +217,7 @@ class Provider: return await chain() - async def _get_prompt( + async def get_prompt( self, name: str, version: VersionSpec | None = None ) -> Prompt | None: """Get prompt by transformed name with all transforms applied. @@ -228,7 +228,7 @@ class Provider: """ async def base(n: str, version: VersionSpec | None = None) -> Prompt | None: - return await self.get_prompt(n, version) + return await self._get_prompt(n, version) chain = base for transform in self.transforms: @@ -342,12 +342,12 @@ class Provider: """ return [] - async def get_prompt( + async def _get_prompt( self, name: str, version: VersionSpec | None = None ) -> Prompt | None: """Get a specific prompt by name. - Default implementation filters list_prompts() and picks the highest version + Default implementation filters _list_prompts() and picks the highest version matching the spec. Args: diff --git a/src/fastmcp/server/providers/fastmcp_provider.py b/src/fastmcp/server/providers/fastmcp_provider.py index ed8c8c380..78cde8121 100644 --- a/src/fastmcp/server/providers/fastmcp_provider.py +++ b/src/fastmcp/server/providers/fastmcp_provider.py @@ -578,16 +578,16 @@ class FastMCPProvider(Provider): raw_prompts = await self.server.get_prompts(run_middleware=True) return [FastMCPProviderPrompt.wrap(self.server, p) for p in raw_prompts] - async def get_prompt( + async def _get_prompt( self, name: str, version: VersionSpec | None = None ) -> Prompt | None: """Get a prompt by name as a FastMCPProviderPrompt. Passes the full VersionSpec to the nested server, which handles both - exact version matching and range filtering. Uses _get_prompt to ensure + exact version matching and range filtering. Uses get_prompt to ensure the nested server's transforms are applied. """ - raw_prompt = await self.server._get_prompt(name, version) + raw_prompt = await self.server.get_prompt(name, version) if raw_prompt is None: return None return FastMCPProviderPrompt.wrap(self.server, raw_prompt) diff --git a/src/fastmcp/server/providers/filesystem.py b/src/fastmcp/server/providers/filesystem.py index 0b9037822..2306a48a7 100644 --- a/src/fastmcp/server/providers/filesystem.py +++ b/src/fastmcp/server/providers/filesystem.py @@ -215,12 +215,12 @@ class FileSystemProvider(LocalProvider): await self._ensure_loaded() return await super()._list_prompts() - async def get_prompt( + async def _get_prompt( self, name: str, version: VersionSpec | None = None ) -> Prompt | None: """Get a prompt by name, reloading if in reload mode.""" await self._ensure_loaded() - return await super().get_prompt(name, version) + return await super()._get_prompt(name, version) def __repr__(self) -> str: return f"FileSystemProvider(root={self._root!r}, reload={self._reload})" diff --git a/src/fastmcp/server/providers/local_provider.py b/src/fastmcp/server/providers/local_provider.py index 8ba155719..506c7b4a1 100644 --- a/src/fastmcp/server/providers/local_provider.py +++ b/src/fastmcp/server/providers/local_provider.py @@ -591,7 +591,7 @@ class LocalProvider(Provider): if isinstance(v, Prompt) and self._is_component_enabled(v) ] - async def get_prompt( + async def _get_prompt( self, name: str, version: VersionSpec | None = None ) -> Prompt | None: """Get a prompt by name. diff --git a/src/fastmcp/server/server.py b/src/fastmcp/server/server.py index 8c889f82a..d293a9975 100644 --- a/src/fastmcp/server/server.py +++ b/src/fastmcp/server/server.py @@ -1421,12 +1421,12 @@ class FastMCP(Provider, Generic[LifespanResultT]): return _dedupe_with_versions(authorized, lambda p: p.name) - async def get_prompt( + async def _get_prompt( self, name: str, version: VersionSpec | None = None ) -> Prompt | None: """Get a prompt by name via aggregation from providers. - This is the raw lookup that Provider._get_prompt() wraps with transforms. + This is the raw lookup that Provider.get_prompt() wraps with transforms. Aggregates from all sub-providers and applies component-level auth. Args: @@ -1438,7 +1438,7 @@ class FastMCP(Provider, Generic[LifespanResultT]): """ # Aggregate from all sub-providers (each applies their own transforms) results = await gather( - *[p._get_prompt(name, version) for p in self._providers], + *[p.get_prompt(name, version) for p in self._providers], return_exceptions=True, ) @@ -1791,7 +1791,7 @@ class FastMCP(Provider, Generic[LifespanResultT]): with server_span( f"prompts/get {name}", "prompts/get", self.name, "prompt", name ) as span: - prompt = await self._get_prompt(name, version=version) + prompt = await self.get_prompt(name, version=version) if prompt is None: raise NotFoundError(f"Unknown prompt: {name!r}") span.set_attributes(prompt.get_span_attributes()) diff --git a/tests/server/test_providers.py b/tests/server/test_providers.py index 9751642f0..396a52c25 100644 --- a/tests/server/test_providers.py +++ b/tests/server/test_providers.py @@ -428,7 +428,7 @@ class TestProviderExecutionMethods: """Test that default render_prompt uses get_prompt and renders it.""" class PromptProvider(Provider): - async def list_prompts(self) -> Sequence[Prompt]: + async def _list_prompts(self) -> Sequence[Prompt]: return [ FunctionPrompt.from_function( fn=lambda name: f"Hello, {name}!",