diff --git a/AGENTS.md b/AGENTS.md index 93fc9b4b83..19ec663df0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -11,7 +11,7 @@ FastMCP is a comprehensive Python framework (Python ≥3.10) for building Model ```bash uv sync # Install dependencies uv run prek run --all-files # Ruff + Prettier + ty -uv run pytest -n auto # Run full test suite +uv run pytest # Run full test suite ``` **All three must pass** - this is enforced by CI. Alternative: `just build && just typecheck && just test` @@ -242,9 +242,9 @@ uv sync # Installs all deps including dev tools ### Testing -- **Standard**: `uv run pytest -n auto` -- **Integration**: `uv run pytest -n auto -m "integration"` -- **Excluding markers**: `uv run pytest -n auto -m "not integration and not client_process"` +- **Standard**: `uv run pytest` +- **Integration**: `uv run pytest -m "integration"` +- **Excluding markers**: `uv run pytest -m "not integration and not client_process"` ### CLI Usage diff --git a/docs/servers/prompts.mdx b/docs/servers/prompts.mdx index 8822a820a9..710b35ce36 100644 --- a/docs/servers/prompts.mdx +++ b/docs/servers/prompts.mdx @@ -195,14 +195,13 @@ FastMCP intelligently handles different return types from your prompt function: - **`str`**: Automatically converted to a single `PromptMessage`. - **`PromptMessage`**: Used directly as provided. (Note a more user-friendly `Message` constructor is available that can accept raw strings instead of `TextContent` objects.) - **`list[PromptMessage | str]`**: Used as a sequence of messages (a conversation). -- **`PromptResult`**: Full control over messages, description, and metadata. See [PromptResult](#promptresult) below. - **`Any`**: If the return type is not one of the above, the return value is attempted to be converted to a string and used as a `PromptMessage`. ```python -from fastmcp.prompts.prompt import Message +from fastmcp.prompts.prompt import Message, PromptResult @mcp.prompt -def roleplay_scenario(character: str, situation: str) -> list[Message]: +def roleplay_scenario(character: str, situation: str) -> PromptResult: """Sets up a roleplaying scenario with initial messages.""" return [ Message(f"Let's roleplay. You are {character}. The situation is: {situation}"), @@ -210,43 +209,6 @@ def roleplay_scenario(character: str, situation: str) -> list[Message]: ] ``` -#### PromptResult - - - -For complete control over prompt responses, return a `PromptResult` object. This lets you include metadata alongside your prompt messages, which is useful for passing runtime information to clients. - -```python -from fastmcp import FastMCP -from fastmcp.prompts import PromptResult, Message - -mcp = FastMCP(name="PromptServer") - -@mcp.prompt -def code_review(code: str) -> PromptResult: - """Returns a code review prompt with metadata.""" - return PromptResult( - messages=[ - Message(f"Please review this code:\n\n```\n{code}\n```"), - ], - description="Code review prompt", - meta={"review_type": "security", "priority": "high"} - ) -``` - -`PromptResult` accepts three fields: - -**`messages`** - A list of `PromptMessage` or `Message` objects representing the conversation to send to the LLM. - -**`description`** - Optional description of the prompt result. If not provided, defaults to the prompt's docstring. - -**`meta`** - Optional metadata dictionary that will be included in the MCP response's `_meta` field. Use this for runtime metadata like categorization, priority, or other client-specific data. - - -The `meta` field in `PromptResult` is for runtime metadata specific to this render response. This is separate from the `meta` parameter in `@mcp.prompt(meta={...})`, which provides static metadata about the prompt definition itself (returned when listing prompts). - - -You can still return plain `str`, `PromptMessage`, or lists from your prompt functions—`PromptResult` is opt-in for when you need to include metadata. ### Required vs. Optional Parameters diff --git a/src/fastmcp/prompts/__init__.py b/src/fastmcp/prompts/__init__.py index 440816289b..f230b8c64b 100644 --- a/src/fastmcp/prompts/__init__.py +++ b/src/fastmcp/prompts/__init__.py @@ -1,4 +1,4 @@ -from .prompt import Message, Prompt, PromptResult, PromptMessage +from .prompt import Prompt, PromptMessage, Message from .prompt_manager import PromptManager __all__ = [ @@ -6,5 +6,4 @@ "Prompt", "PromptManager", "PromptMessage", - "PromptResult", ] diff --git a/src/fastmcp/prompts/prompt.py b/src/fastmcp/prompts/prompt.py index c84098e808..10bf4ee01f 100644 --- a/src/fastmcp/prompts/prompt.py +++ b/src/fastmcp/prompts/prompt.py @@ -4,18 +4,15 @@ import inspect import json -import warnings from collections.abc import Awaitable, Callable, Sequence from typing import Annotated, Any import pydantic_core -from mcp import GetPromptResult from mcp.types import ContentBlock, Icon, PromptMessage, Role, TextContent from mcp.types import Prompt as MCPPrompt from mcp.types import PromptArgument as MCPPromptArgument from pydantic import Field, TypeAdapter -from fastmcp import settings from fastmcp.exceptions import PromptError from fastmcp.server.dependencies import get_context, without_injected_parameters from fastmcp.server.tasks.config import TaskConfig @@ -43,14 +40,13 @@ def Message( message_validator = TypeAdapter[PromptMessage](PromptMessage) -# Type aliases for what prompt functions can return (before conversion to PromptResult) -_SyncPromptFnReturn = ( +SyncPromptResult = ( str | PromptMessage | dict[str, Any] | Sequence[str | PromptMessage | dict[str, Any]] ) -_PromptFnReturn = _SyncPromptFnReturn | Awaitable[_SyncPromptFnReturn] +PromptResult = SyncPromptResult | Awaitable[SyncPromptResult] class PromptArgument(FastMCPBaseModel): @@ -65,51 +61,6 @@ class PromptArgument(FastMCPBaseModel): ) -class PromptResult(FastMCPBaseModel): - """Canonical result type for prompt rendering. - - This is the internal type that all prompt renders return. It wraps the - messages with optional description and metadata. - """ - - messages: list[PromptMessage] = Field(description="The prompt messages to return") - description: str | None = Field( - default=None, description="Optional description of the prompt result" - ) - meta: dict[str, Any] | None = Field( - default=None, description="Optional metadata about the prompt result" - ) - - @classmethod - def from_value( - cls, - value: list[PromptMessage] | PromptResult, - description: str | None = None, - meta: dict[str, Any] | None = None, - ) -> PromptResult: - """Convert various types to PromptResult.""" - if isinstance(value, PromptResult): - # Merge meta if provided - if meta and value.meta: - merged_meta = {**value.meta, **meta} - else: - merged_meta = meta or value.meta - return cls( - messages=value.messages, - description=description or value.description, - meta=merged_meta, - ) - return cls(messages=value, description=description, meta=meta) - - def to_mcp_prompt_result(self) -> GetPromptResult: - """Convert to MCP GetPromptResult.""" - return GetPromptResult( - description=self.description, - messages=self.messages, - _meta=self.meta, - ) - - class Prompt(FastMCPComponent): """A prompt template that can be rendered with parameters.""" @@ -162,7 +113,7 @@ def to_mcp_prompt( @staticmethod def from_function( - fn: Callable[..., _PromptFnReturn | Awaitable[_PromptFnReturn]], + fn: Callable[..., PromptResult | Awaitable[PromptResult]], name: str | None = None, title: str | None = None, description: str | None = None, @@ -195,45 +146,19 @@ def from_function( async def render( self, arguments: dict[str, Any] | None = None, - ) -> list[PromptMessage] | PromptResult: + ) -> list[PromptMessage]: """Render the prompt with arguments. This method is not implemented in the base Prompt class and must be - implemented by subclasses. The preferred return type is PromptResult, - but list[PromptMessage] is still supported for backwards compatibility. + implemented by subclasses. """ raise NotImplementedError("Subclasses must implement render()") - async def _render( - self, - arguments: dict[str, Any] | None = None, - ) -> PromptResult: - """Internal API that always returns PromptResult. - - Calls render() and wraps list[PromptMessage] in PromptResult. - This is what PromptManager calls internally. - """ - result = await self.render(arguments) - if isinstance(result, PromptResult): - return result - # Deprecated in 2.14.1: returning list[PromptMessage] from render() - if settings.deprecation_warnings: - warnings.warn( - f"Prompt.render() returning list[PromptMessage] is deprecated (since 2.14.1). " - f"Return PromptResult instead. " - f"(Prompt: {self.__class__.__name__}, Name: {self.name})", - DeprecationWarning, - stacklevel=2, - ) - return PromptResult.from_value( - result, description=self.description, meta=self.meta - ) - class FunctionPrompt(Prompt): """A prompt that is a function.""" - fn: Callable[..., _PromptFnReturn | Awaitable[_PromptFnReturn]] + fn: Callable[..., PromptResult | Awaitable[PromptResult]] task_config: Annotated[ TaskConfig, Field(description="Background task execution configuration (SEP-1686)."), @@ -242,7 +167,7 @@ class FunctionPrompt(Prompt): @classmethod def from_function( cls, - fn: Callable[..., _PromptFnReturn | Awaitable[_PromptFnReturn]], + fn: Callable[..., PromptResult | Awaitable[PromptResult]], name: str | None = None, title: str | None = None, description: str | None = None, @@ -397,7 +322,7 @@ def _convert_string_arguments(self, kwargs: dict[str, Any]) -> dict[str, Any]: async def render( self, arguments: dict[str, Any] | None = None, - ) -> PromptResult: + ) -> list[PromptMessage]: """Render the prompt with arguments.""" # Validate required arguments if self.arguments: @@ -450,11 +375,7 @@ async def render( "Could not convert prompt result to message." ) from e - return PromptResult( - messages=messages, - description=self.description, - meta=self.meta, - ) + return messages except Exception as e: logger.exception(f"Error rendering prompt {self.name}") raise PromptError(f"Error rendering prompt {self.name}.") from e diff --git a/src/fastmcp/prompts/prompt_manager.py b/src/fastmcp/prompts/prompt_manager.py index 971eb52641..1563a1831f 100644 --- a/src/fastmcp/prompts/prompt_manager.py +++ b/src/fastmcp/prompts/prompt_manager.py @@ -4,14 +4,11 @@ from collections.abc import Awaitable, Callable from typing import Any +from mcp import GetPromptResult + from fastmcp import settings from fastmcp.exceptions import NotFoundError, PromptError -from fastmcp.prompts.prompt import ( - FunctionPrompt, - Prompt, - PromptResult, - _PromptFnReturn, -) +from fastmcp.prompts.prompt import FunctionPrompt, Prompt, PromptResult from fastmcp.settings import DuplicateBehavior from fastmcp.utilities.logging import get_logger @@ -27,11 +24,7 @@ def __init__( mask_error_details: bool | None = None, ): self._prompts: dict[str, Prompt] = {} - self.mask_error_details = ( - settings.mask_error_details - if mask_error_details is None - else mask_error_details - ) + self.mask_error_details = mask_error_details or settings.mask_error_details # Default to "warn" if None is provided if duplicate_behavior is None: @@ -65,7 +58,7 @@ async def get_prompts(self) -> dict[str, Prompt]: def add_prompt_from_fn( self, - fn: Callable[..., _PromptFnReturn | Awaitable[_PromptFnReturn]], + fn: Callable[..., PromptResult | Awaitable[PromptResult]], name: str | None = None, description: str | None = None, tags: set[str] | None = None, @@ -105,17 +98,18 @@ async def render_prompt( self, name: str, arguments: dict[str, Any] | None = None, - ) -> PromptResult: + ) -> GetPromptResult: """ Internal API for servers: Finds and renders a prompt, respecting the filtered protocol path. """ prompt = await self.get_prompt(name) try: - return await prompt._render(arguments) - except PromptError: + messages = await prompt.render(arguments) + return GetPromptResult(description=prompt.description, messages=messages) + except PromptError as e: logger.exception(f"Error rendering prompt {name!r}") - raise + raise e except Exception as e: logger.exception(f"Error rendering prompt {name!r}") if self.mask_error_details: diff --git a/src/fastmcp/server/middleware/caching.py b/src/fastmcp/server/middleware/caching.py index 14b0c6c552..1f6ebdb594 100644 --- a/src/fastmcp/server/middleware/caching.py +++ b/src/fastmcp/server/middleware/caching.py @@ -17,7 +17,7 @@ from pydantic import BaseModel, Field from typing_extensions import NotRequired, Self, override -from fastmcp.prompts.prompt import Prompt, PromptResult +from fastmcp.prompts.prompt import Prompt from fastmcp.resources.resource import Resource, ResourceContent from fastmcp.server.middleware.middleware import CallNext, Middleware, MiddlewareContext from fastmcp.tools.tool import Tool, ToolResult @@ -220,10 +220,12 @@ def __init__( default_collection="resources/read", ) - self._get_prompt_cache: PydanticAdapter[PromptResult] = PydanticAdapter( - key_value=self._stats, - pydantic_model=PromptResult, - default_collection="prompts/get", + self._get_prompt_cache: PydanticAdapter[mcp.types.GetPromptResult] = ( + PydanticAdapter( + key_value=self._stats, + pydantic_model=mcp.types.GetPromptResult, + default_collection="prompts/get", + ) ) self._call_tool_cache: PydanticAdapter[CachableToolResult] = PydanticAdapter( @@ -417,8 +419,10 @@ async def on_read_resource( async def on_get_prompt( self, context: MiddlewareContext[mcp.types.GetPromptRequestParams], - call_next: CallNext[mcp.types.GetPromptRequestParams, PromptResult], - ) -> PromptResult: + call_next: CallNext[ + mcp.types.GetPromptRequestParams, mcp.types.GetPromptResult + ], + ) -> mcp.types.GetPromptResult: """Get a prompt from the cache, if caching is enabled, and the result is in the cache. Otherwise, otherwise call the next middleware and store the result in the cache if caching is enabled.""" if self._get_prompt_settings.get("enabled") is False: @@ -429,7 +433,7 @@ async def on_get_prompt( if cached_value := await self._get_prompt_cache.get(key=cache_key): return cached_value - value: PromptResult = await call_next(context=context) + value: mcp.types.GetPromptResult = await call_next(context=context) await self._get_prompt_cache.put( key=cache_key, diff --git a/src/fastmcp/server/middleware/middleware.py b/src/fastmcp/server/middleware/middleware.py index ca3d875cc1..e0a06642da 100644 --- a/src/fastmcp/server/middleware/middleware.py +++ b/src/fastmcp/server/middleware/middleware.py @@ -17,7 +17,7 @@ import mcp.types as mt from typing_extensions import TypeVar -from fastmcp.prompts.prompt import Prompt, PromptResult +from fastmcp.prompts.prompt import Prompt from fastmcp.resources.resource import Resource, ResourceContent from fastmcp.resources.template import ResourceTemplate from fastmcp.tools.tool import Tool, ToolResult @@ -170,8 +170,8 @@ async def on_read_resource( async def on_get_prompt( self, context: MiddlewareContext[mt.GetPromptRequestParams], - call_next: CallNext[mt.GetPromptRequestParams, PromptResult], - ) -> PromptResult: + call_next: CallNext[mt.GetPromptRequestParams, mt.GetPromptResult], + ) -> mt.GetPromptResult: return await call_next(context) async def on_list_tools( diff --git a/src/fastmcp/server/proxy.py b/src/fastmcp/server/proxy.py index 00cbcfbd47..dfa8b6844b 100644 --- a/src/fastmcp/server/proxy.py +++ b/src/fastmcp/server/proxy.py @@ -16,6 +16,7 @@ METHOD_NOT_FOUND, BlobResourceContents, ElicitRequestFormParams, + GetPromptResult, TextResourceContents, ) from pydantic.networks import AnyUrl @@ -27,7 +28,7 @@ from fastmcp.client.transports import ClientTransportT from fastmcp.exceptions import NotFoundError, ResourceError, ToolError from fastmcp.mcp_config import MCPConfig -from fastmcp.prompts import Prompt, PromptResult +from fastmcp.prompts import Prompt, PromptMessage from fastmcp.prompts.prompt import PromptArgument from fastmcp.prompts.prompt_manager import PromptManager from fastmcp.resources import Resource, ResourceTemplate @@ -256,7 +257,7 @@ async def render_prompt( self, name: str, arguments: dict[str, Any] | None = None, - ) -> PromptResult: + ) -> GetPromptResult: """Renders a prompt, trying local/mounted first, then proxy if not found.""" try: # First try local and mounted prompts @@ -266,12 +267,7 @@ async def render_prompt( client = await self._get_client() async with client: result = await client.get_prompt(name, arguments) - # Convert MCP GetPromptResult to PromptResult - return PromptResult( - messages=result.messages, - description=result.description, - meta=result.meta, - ) + return result class ProxyTool(Tool, MirroredComponent): @@ -528,17 +524,11 @@ def from_mcp_prompt( _mirrored=True, ) - async def render(self, arguments: dict[str, Any]) -> PromptResult: # type: ignore[override] + async def render(self, arguments: dict[str, Any]) -> list[PromptMessage]: # type: ignore[override] """Render the prompt by making a call through the client.""" async with self._client: result = await self._client.get_prompt(self.name, arguments) - # Convert GetPromptResult to PromptResult, preserving runtime meta from the result - # (not the static prompt meta which includes fastmcp tags) - return PromptResult( - messages=result.messages, - description=result.description, - meta=result.meta, - ) + return result.messages class FastMCPProxy(FastMCP): diff --git a/src/fastmcp/server/server.py b/src/fastmcp/server/server.py index 9b5bdfa9f1..e4ccc1543c 100644 --- a/src/fastmcp/server/server.py +++ b/src/fastmcp/server/server.py @@ -60,7 +60,7 @@ from fastmcp.exceptions import DisabledError, NotFoundError from fastmcp.mcp_config import MCPConfig from fastmcp.prompts import Prompt -from fastmcp.prompts.prompt import FunctionPrompt, PromptResult +from fastmcp.prompts.prompt import FunctionPrompt from fastmcp.prompts.prompt_manager import PromptManager from fastmcp.resources.resource import FunctionResource, Resource, ResourceContent from fastmcp.resources.resource_manager import ResourceManager @@ -1744,18 +1744,8 @@ async def _get_prompt_middleware( ) -> GetPromptResult: """ Applies this server's middleware and delegates the filtered call to the manager. - Converts PromptResult to GetPromptResult for MCP protocol. """ - result = await self._get_prompt_content_middleware(name, arguments) - return result.to_mcp_prompt_result() - async def _get_prompt_content_middleware( - self, name: str, arguments: dict[str, Any] | None = None - ) -> PromptResult: - """ - Applies this server's middleware and returns PromptResult. - Used internally and by parent servers for mounted prompts. - """ mw_context = MiddlewareContext( message=mcp.types.GetPromptRequestParams(name=name, arguments=arguments), source="client", @@ -1770,7 +1760,7 @@ async def _get_prompt_content_middleware( async def _get_prompt( self, context: MiddlewareContext[mcp.types.GetPromptRequestParams], - ) -> PromptResult: + ) -> GetPromptResult: name = context.message.name # Try mounted servers in reverse order (later wins) @@ -1789,7 +1779,7 @@ async def _get_prompt( if not self._should_enable_component(prompt): # Parent filter blocks this prompt, continue searching continue - return await mounted.server._get_prompt_content_middleware( + return await mounted.server._get_prompt_middleware( try_name, context.message.arguments ) except NotFoundError: diff --git a/tests/prompts/test_prompt.py b/tests/prompts/test_prompt.py index 0bd3e66320..76132b9025 100644 --- a/tests/prompts/test_prompt.py +++ b/tests/prompts/test_prompt.py @@ -16,8 +16,7 @@ def fn() -> str: return "Hello, world!" prompt = Prompt.from_function(fn) - result = await prompt.render() - assert result.messages == [ + assert await prompt.render() == [ PromptMessage( role="user", content=TextContent(type="text", text="Hello, world!") ) @@ -28,8 +27,7 @@ async def fn() -> str: return "Hello, world!" prompt = Prompt.from_function(fn) - result = await prompt.render() - assert result.messages == [ + assert await prompt.render() == [ PromptMessage( role="user", content=TextContent(type="text", text="Hello, world!") ) @@ -40,8 +38,7 @@ async def fn(name: str, age: int = 30) -> str: return f"Hello, {name}! You're {age} years old." prompt = Prompt.from_function(fn) - result = await prompt.render(arguments=dict(name="World")) - assert result.messages == [ + assert await prompt.render(arguments=dict(name="World")) == [ PromptMessage( role="user", content=TextContent( @@ -56,8 +53,7 @@ def __call__(self, name: str) -> str: return f"Hello, {name}!" prompt = Prompt.from_function(MyPrompt()) - result = await prompt.render(arguments=dict(name="World")) - assert result.messages == [ + assert await prompt.render(arguments=dict(name="World")) == [ PromptMessage( role="user", content=TextContent(type="text", text="Hello, World!") ) @@ -69,8 +65,7 @@ async def __call__(self, name: str) -> str: return f"Hello, {name}!" prompt = Prompt.from_function(MyPrompt()) - result = await prompt.render(arguments=dict(name="World")) - assert result.messages == [ + assert await prompt.render(arguments=dict(name="World")) == [ PromptMessage( role="user", content=TextContent(type="text", text="Hello, World!") ) @@ -91,8 +86,7 @@ async def fn() -> PromptMessage: ) prompt = Prompt.from_function(fn) - result = await prompt.render() - assert result.messages == [ + assert await prompt.render() == [ PromptMessage( role="user", content=TextContent(type="text", text="Hello, world!") ) @@ -105,8 +99,7 @@ async def fn() -> PromptMessage: ) prompt = Prompt.from_function(fn) - result = await prompt.render() - assert result.messages == [ + assert await prompt.render() == [ PromptMessage( role="assistant", content=TextContent(type="text", text="Hello, world!") ) @@ -126,8 +119,7 @@ async def fn() -> list[PromptMessage]: return expected prompt = Prompt.from_function(fn) - result = await prompt.render() - assert result.messages == expected + assert await prompt.render() == expected async def test_fn_returns_list_of_strings(self): expected = [ @@ -139,8 +131,7 @@ async def fn() -> list[str]: return expected prompt = Prompt.from_function(fn) - result = await prompt.render() - assert result.messages == [ + assert await prompt.render() == [ PromptMessage(role="user", content=TextContent(type="text", text=t)) for t in expected ] @@ -162,8 +153,7 @@ async def fn() -> PromptMessage: ) prompt = Prompt.from_function(fn) - result = await prompt.render() - assert result.messages == [ + assert await prompt.render() == [ PromptMessage( role="user", content=EmbeddedResource( @@ -198,8 +188,7 @@ async def fn() -> list[PromptMessage | str]: ] prompt = Prompt.from_function(fn) - result = await prompt.render() - assert result.messages == [ + assert await prompt.render() == [ PromptMessage( role="user", content=TextContent(type="text", text="Please analyze this file:"), @@ -238,8 +227,7 @@ async def fn() -> PromptMessage: ) prompt = Prompt.from_function(fn) - result = await prompt.render() - assert result.messages == [ + assert await prompt.render() == [ PromptMessage( role="user", content=EmbeddedResource( @@ -270,7 +258,7 @@ def sum_numbers(numbers: list[int]) -> str: result_from_string = await prompt.render( arguments={"numbers": "[1, 2, 3, 4, 5]"} ) - assert result_from_string.messages == [ + assert result_from_string == [ PromptMessage( role="user", content=TextContent(type="text", text="The sum is: 15") ) @@ -280,7 +268,7 @@ def sum_numbers(numbers: list[int]) -> str: result_from_list_string = await prompt.render( arguments={"numbers": "[1, 2, 3, 4, 5]"} ) - assert result_from_list_string.messages == result_from_string.messages + assert result_from_list_string == result_from_string async def test_various_type_conversions(self): """Test type conversion for various data types.""" @@ -310,7 +298,7 @@ def process_data( expected_text = ( "Alice (25): 3 scores, active=True, metadata keys=['project', 'version']" ) - assert result.messages == [ + assert result == [ PromptMessage( role="user", content=TextContent(type="text", text=expected_text) ) @@ -341,7 +329,7 @@ def data_prompt(value: int) -> str: # This should work with JSON parsing (integer as string) result1 = await prompt.render(arguments={"value": "42"}) - assert result1.messages == [ + assert result1 == [ PromptMessage( role="user", content=TextContent(type="text", text="Value: 42") ) @@ -349,7 +337,7 @@ def data_prompt(value: int) -> str: # This should work with direct validation (already an integer string) result2 = await prompt.render(arguments={"value": "123"}) - assert result2.messages == [ + assert result2 == [ PromptMessage( role="user", content=TextContent(type="text", text="Value: 123") ) @@ -370,7 +358,7 @@ def mixed_prompt(message: str, count: int) -> str: } ) - assert result.messages == [ + assert result == [ PromptMessage( role="user", content=TextContent(type="text", text="Hello world (repeated 3 times)"), diff --git a/tests/prompts/test_prompt_manager.py b/tests/prompts/test_prompt_manager.py index b9e6669269..076c272794 100644 --- a/tests/prompts/test_prompt_manager.py +++ b/tests/prompts/test_prompt_manager.py @@ -400,10 +400,10 @@ def prompt_with_context(x: int, ctx: Context) -> str: context = Context(fastmcp=mcp) async with context: - result = await prompt.render(arguments={"x": 42}) + messages = await prompt.render(arguments={"x": 42}) - assert len(result.messages) == 1 - assert result.messages[0].content.text == "42" # type: ignore[attr-defined] + assert len(messages) == 1 + assert messages[0].content.text == "42" # type: ignore[attr-defined] async def test_context_optional(self): """Test that context is optional when rendering prompts.""" @@ -420,12 +420,12 @@ def prompt_with_context(x: int, ctx: Context | None = None) -> str: context = Context(fastmcp=mcp) async with context: - result = await prompt.render( + messages = await prompt.render( arguments={"x": 42}, ) - assert len(result.messages) == 1 - assert result.messages[0].content.text == "42" # type: ignore[attr-defined] + assert len(messages) == 1 + assert messages[0].content.text == "42" # type: ignore[attr-defined] async def test_annotated_context_parameter_detection(self): """Test that annotated context parameters are properly detected in @@ -460,5 +460,5 @@ async def decorated_prompt(ctx: Context, topic: str) -> str: context = Context(fastmcp=mcp) async with context: - result = await prompt.render(arguments={"topic": "cats"}) - assert result.messages[0].content.text == "Write about cats" # type: ignore[attr-defined] + messages = await prompt.render(arguments={"topic": "cats"}) + assert messages[0].content.text == "Write about cats" # type: ignore[attr-defined] diff --git a/tests/server/test_server.py b/tests/server/test_server.py index 16e3a33e53..dfe7a645ba 100644 --- a/tests/server/test_server.py +++ b/tests/server/test_server.py @@ -848,7 +848,7 @@ def fn() -> str: assert prompt.name == "fn" # Don't compare functions directly since validate_call wraps them content = await prompt.render() - assert content.messages[0].content.text == "Hello, world!" # type: ignore[attr-defined] + assert content[0].content.text == "Hello, world!" # type: ignore[attr-defined] async def test_prompt_decorator_without_parentheses(self): mcp = FastMCP() @@ -880,7 +880,7 @@ def fn() -> str: prompt = prompts_dict["custom_name"] assert prompt.name == "custom_name" content = await prompt.render() - assert content.messages[0].content.text == "Hello, world!" # type: ignore[attr-defined] + assert content[0].content.text == "Hello, world!" # type: ignore[attr-defined] async def test_prompt_decorator_with_description(self): mcp = FastMCP() @@ -894,7 +894,7 @@ def fn() -> str: prompt = prompts_dict["fn"] assert prompt.description == "A custom description" content = await prompt.render() - assert content.messages[0].content.text == "Hello, world!" # type: ignore[attr-defined] + assert content[0].content.text == "Hello, world!" # type: ignore[attr-defined] async def test_prompt_decorator_with_parameters(self): mcp = FastMCP() diff --git a/tests/server/test_server_interactions.py b/tests/server/test_server_interactions.py index e272b1e745..8eb2d2769c 100644 --- a/tests/server/test_server_interactions.py +++ b/tests/server/test_server_interactions.py @@ -2194,7 +2194,7 @@ def fn() -> str: assert prompt.name == "fn" # Don't compare functions directly since validate_call wraps them content = await prompt.render() - assert content.messages[0].content.text == "Hello, world!" # type: ignore[attr-defined] + assert content[0].content.text == "Hello, world!" # type: ignore[attr-defined] async def test_prompt_decorator_with_name(self): """Test prompt decorator with custom name.""" @@ -2209,7 +2209,7 @@ def fn() -> str: prompt = prompts_dict["custom_name"] assert prompt.name == "custom_name" content = await prompt.render() - assert content.messages[0].content.text == "Hello, world!" # type: ignore[attr-defined] + assert content[0].content.text == "Hello, world!" # type: ignore[attr-defined] async def test_prompt_decorator_with_description(self): """Test prompt decorator with custom description.""" @@ -2224,7 +2224,7 @@ def fn() -> str: prompt = prompts_dict["fn"] assert prompt.description == "A custom description" content = await prompt.render() - assert content.messages[0].content.text == "Hello, world!" # type: ignore[attr-defined] + assert content[0].content.text == "Hello, world!" # type: ignore[attr-defined] async def test_prompt_decorator_with_parens(self): mcp = FastMCP()