Ensure prompts return descriptions

This commit is contained in:
Jeremiah Lowin 2025-05-05 12:33:05 -04:00
commit 2eb0e7c1b3
15 changed files with 206 additions and 159 deletions

View file

@ -104,6 +104,10 @@ You can make multiple calls to the server within the same `async with` block usi
The `Client` provides methods corresponding to standard MCP requests:
<Warning>
The standard client methods return user-friendly representations that may change as the protocol evolves. For consistent access to the complete data structure, use the `*_mcp` methods described later.
</Warning>
#### Tool Operations
* **`list_tools()`**: Retrieves a list of tools available on the server.
@ -153,6 +157,10 @@ The `Client` provides methods corresponding to standard MCP requests:
The FastMCP client attempts to provide a "friendly" interface to the MCP protocol, but sometimes you may need access to the raw MCP protocol objects. Each of the main client methods that returns data has a corresponding `*_mcp` method that returns the raw MCP protocol objects directly.
<Warning>
The standard client methods (without `_mcp`) return user-friendly representations of MCP data, while `*_mcp` methods will always return the complete MCP protocol objects. As the protocol evolves, changes to these user-friendly representations may occur and could potentially be breaking. If you need consistent, stable access to the full data structure, prefer using the `*_mcp` methods.
</Warning>
```python
# Standard method - returns just the list of tools
tools = await client.list_tools()

View file

@ -28,11 +28,11 @@ The most common way to define a prompt is by decorating a Python function. The d
```python
from fastmcp import FastMCP
from fastmcp.prompts.prompt import UserMessage, AssistantMessage, Message
from fastmcp.prompts.prompt import Message, PromptMessage, TextContent
mcp = FastMCP(name="PromptServer")
# Basic prompt returning a string (converted to UserMessage)
# Basic prompt returning a string (converted to user message automatically)
@mcp.prompt()
def ask_about_topic(topic: str) -> str:
"""Generates a user message asking for an explanation of a topic."""
@ -40,10 +40,10 @@ def ask_about_topic(topic: str) -> str:
# Prompt returning a specific message type
@mcp.prompt()
def generate_code_request(language: str, task_description: str) -> UserMessage:
def generate_code_request(language: str, task_description: str) -> PromptMessage:
"""Generates a user message requesting code generation."""
content = f"Write a {language} function that performs the following task: {task_description}"
return UserMessage(content=content)
return PromptMessage(role="user", content=TextContent(type="text", text=content))
```
**Key Concepts:**
@ -61,24 +61,21 @@ Functions with `*args` or `**kwargs` are not supported as prompts. This restrict
FastMCP intelligently handles different return types from your prompt function:
- **`str`**: Automatically converted to a single `UserMessage`.
- **`Message`** (e.g., `UserMessage`, `AssistantMessage`): Used directly as provided.
- **`dict`**: Parsed as a `Message` object if it has the correct structure.
- **`list[Message]`**: Used as a sequence of messages (a conversation).
- **`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).
- **`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
@mcp.prompt()
def roleplay_scenario(character: str, situation: str) -> list[Message]:
"""Sets up a roleplaying scenario with initial messages."""
return [
UserMessage(f"Let's roleplay. You are {character}. The situation is: {situation}"),
AssistantMessage("Okay, I understand. I am ready. What happens next?")
Message(f"Let's roleplay. You are {character}. The situation is: {situation}"),
Message("Okay, I understand. I am ready. What happens next?", role="assistant")
]
@mcp.prompt()
def ask_for_feedback() -> dict:
"""Generates a user message asking for feedback."""
return {"role": "user", "content": "What did you think of my previous response?"}
```
### Type Annotations

View file

@ -286,7 +286,7 @@ class Client:
async def get_prompt(
self, name: str, arguments: dict[str, str] | None = None
) -> list[mcp.types.PromptMessage]:
) -> mcp.types.GetPromptResult:
"""Retrieve a rendered prompt message list from the server.
Args:
@ -294,13 +294,14 @@ class Client:
arguments (dict[str, str] | None, optional): Arguments to pass to the prompt. Defaults to None.
Returns:
list[mcp.types.PromptMessage]: A list of prompt messages.
mcp.types.GetPromptResult: The complete response object from the protocol,
containing the prompt messages and any additional metadata.
Raises:
RuntimeError: If called while the client is not connected.
"""
result = await self.get_prompt_mcp(name=name, arguments=arguments)
return result.messages
return result
# --- Completion ---

View file

@ -1,4 +1,9 @@
from .prompt import Prompt, Message, UserMessage, AssistantMessage
from .prompt import Prompt, PromptMessage, Message
from .prompt_manager import PromptManager
__all__ = ["Prompt", "PromptManager", "Message", "UserMessage", "AssistantMessage"]
__all__ = [
"Prompt",
"PromptManager",
"PromptMessage",
"Message",
]

View file

@ -4,10 +4,10 @@ from __future__ import annotations as _annotations
import inspect
from collections.abc import Awaitable, Callable, Sequence
from typing import TYPE_CHECKING, Annotated, Any, Literal
from typing import TYPE_CHECKING, Annotated, Any
import pydantic_core
from mcp.types import EmbeddedResource, ImageContent, TextContent
from mcp.types import EmbeddedResource, ImageContent, PromptMessage, Role, TextContent
from mcp.types import Prompt as MCPPrompt
from mcp.types import PromptArgument as MCPPromptArgument
from pydantic import BaseModel, BeforeValidator, Field, TypeAdapter, validate_call
@ -28,32 +28,24 @@ if TYPE_CHECKING:
CONTENT_TYPES = TextContent | ImageContent | EmbeddedResource
class Message(BaseModel):
"""Base class for all prompt messages."""
role: Literal["user", "assistant"]
content: CONTENT_TYPES
def __init__(self, content: str | CONTENT_TYPES, **kwargs: Any):
if isinstance(content, str):
content = TextContent(type="text", text=content)
super().__init__(content=content, **kwargs)
def Message(
content: str | CONTENT_TYPES, role: Role | None = None, **kwargs: Any
) -> PromptMessage:
"""A user-friendly constructor for PromptMessage."""
if isinstance(content, str):
content = TextContent(type="text", text=content)
if role is None:
role = "user"
return PromptMessage(content=content, role=role, **kwargs)
def UserMessage(content: str | CONTENT_TYPES, **kwargs: Any) -> Message:
"""A message from the user."""
return Message(content=content, role="user", **kwargs)
def AssistantMessage(content: str | CONTENT_TYPES, **kwargs: Any) -> Message:
"""A message from the assistant."""
return Message(content=content, role="assistant", **kwargs)
message_validator = TypeAdapter[Message](Message)
message_validator = TypeAdapter[PromptMessage](PromptMessage)
SyncPromptResult = (
str | Message | dict[str, Any] | Sequence[str | Message | dict[str, Any]]
str
| PromptMessage
| dict[str, Any]
| Sequence[str | PromptMessage | dict[str, Any]]
)
PromptResult = SyncPromptResult | Awaitable[SyncPromptResult]
@ -156,7 +148,7 @@ class Prompt(BaseModel):
self,
arguments: dict[str, Any] | None = None,
context: Context[ServerSessionT, LifespanContextT] | None = None,
) -> list[Message]:
) -> list[PromptMessage]:
"""Render the prompt with arguments."""
# Validate required arguments
if self.arguments:
@ -182,21 +174,28 @@ class Prompt(BaseModel):
result = [result]
# Convert result to messages
messages: list[Message] = []
for msg in result: # type: ignore[reportUnknownVariableType]
messages: list[PromptMessage] = []
for msg in result:
try:
if isinstance(msg, Message):
if isinstance(msg, PromptMessage):
messages.append(msg)
elif isinstance(msg, dict):
messages.append(message_validator.validate_python(msg))
elif isinstance(msg, str):
content = TextContent(type="text", text=msg)
messages.append(Message(role="user", content=content))
messages.append(
PromptMessage(
role="user",
content=TextContent(type="text", text=msg),
)
)
else:
content = pydantic_core.to_json(
msg, fallback=str, indent=2
).decode()
messages.append(Message(role="user", content=content))
messages.append(
PromptMessage(
role="user",
content=TextContent(type="text", text=content),
)
)
except Exception:
raise ValueError(
f"Could not convert prompt result to message: {msg}"

View file

@ -5,8 +5,10 @@ from __future__ import annotations as _annotations
from collections.abc import Awaitable, Callable
from typing import TYPE_CHECKING, Any
from mcp import GetPromptResult
from fastmcp.exceptions import NotFoundError
from fastmcp.prompts.prompt import Message, Prompt, PromptResult
from fastmcp.prompts.prompt import Prompt, PromptResult
from fastmcp.settings import DuplicateBehavior
from fastmcp.utilities.logging import get_logger
@ -81,13 +83,18 @@ class PromptManager:
name: str,
arguments: dict[str, Any] | None = None,
context: Context[ServerSessionT, LifespanContextT] | None = None,
) -> list[Message]:
) -> GetPromptResult:
"""Render a prompt by name with arguments."""
prompt = self.get_prompt(name)
if not prompt:
raise NotFoundError(f"Unknown prompt: {name}")
return await prompt.render(arguments, context=context)
messages = await prompt.render(arguments, context=context)
return GetPromptResult(
description=prompt.description,
messages=messages,
)
def has_prompt(self, key: str) -> bool:
"""Check if a prompt exists."""

View file

@ -19,7 +19,7 @@ from pydantic.networks import AnyUrl
from fastmcp.client import Client
from fastmcp.exceptions import NotFoundError
from fastmcp.prompts import Message, Prompt
from fastmcp.prompts import Prompt, PromptMessage
from fastmcp.resources import Resource, ResourceTemplate
from fastmcp.server.context import Context
from fastmcp.server.server import FastMCP
@ -175,10 +175,10 @@ class ProxyPrompt(Prompt):
self,
arguments: dict[str, Any],
context: Context[ServerSessionT, LifespanContextT] | None = None,
) -> list[Message]:
) -> list[PromptMessage]:
async with self._client:
result = await self._client.get_prompt(self.name, arguments)
return [Message(role=m.role, content=m.content) for m in result]
return result.messages
class FastMCPProxy(FastMCP):
@ -291,4 +291,4 @@ class FastMCPProxy(FastMCP):
except NotFoundError:
async with self.client:
result = await self.client.get_prompt(name, arguments)
return GetPromptResult(messages=result)
return result

View file

@ -32,7 +32,6 @@ from mcp.types import (
EmbeddedResource,
GetPromptResult,
ImageContent,
PromptMessage,
TextContent,
ToolAnnotations,
)
@ -504,15 +503,10 @@ class FastMCP(Generic[LifespanResultT]):
"""
if self._prompt_manager.has_prompt(name):
context = self.get_context()
messages = await self._prompt_manager.render_prompt(
prompt_result = await self._prompt_manager.render_prompt(
name, arguments=arguments or {}, context=context
)
return GetPromptResult(
messages=[
PromptMessage(role=m.role, content=m.content) for m in messages
]
)
return prompt_result
else:
for server in self._mounted_servers.values():
if server.match_prompt(name):

View file

@ -5,6 +5,7 @@ from pydantic import AnyUrl
from fastmcp.client import Client
from fastmcp.client.transports import FastMCPTransport
from fastmcp.prompts.prompt import TextContent
from fastmcp.server.server import FastMCP
@ -38,6 +39,7 @@ def fastmcp_server():
# Add a prompt
@server.prompt()
def welcome(name: str) -> str:
"""Example greeting prompt."""
return f"Welcome to FastMCP, {name}!"
return server
@ -182,8 +184,9 @@ async def test_get_prompt(fastmcp_server):
result = await client.get_prompt("welcome", {"name": "Developer"})
# The result should contain our welcome message
result_str = str(result)
assert "Welcome to FastMCP, Developer!" in result_str
assert isinstance(result.messages[0].content, TextContent)
assert result.messages[0].content.text == "Welcome to FastMCP, Developer!"
assert result.description == "Example greeting prompt."
async def test_get_prompt_mcp(fastmcp_server):
@ -193,11 +196,10 @@ async def test_get_prompt_mcp(fastmcp_server):
async with client:
result = await client.get_prompt_mcp("welcome", {"name": "Developer"})
# Check that we got the raw MCP GetPromptResult object
assert hasattr(result, "messages")
assert len(result.messages) > 0
result_str = str(result.messages)
assert "Welcome to FastMCP, Developer!" in result_str
# The result should contain our welcome message
assert isinstance(result.messages[0].content, TextContent)
assert result.messages[0].content.text == "Welcome to FastMCP, Developer!"
assert result.description == "Example greeting prompt."
async def test_read_resource(fastmcp_server):

View file

@ -3,11 +3,10 @@ from mcp.types import EmbeddedResource, TextResourceContents
from pydantic import FileUrl
from fastmcp.prompts.prompt import (
AssistantMessage,
Message,
Prompt,
PromptMessage,
TextContent,
UserMessage,
)
@ -18,7 +17,9 @@ class TestRenderPrompt:
prompt = Prompt.from_function(fn)
assert await prompt.render() == [
UserMessage(content=TextContent(type="text", text="Hello, world!"))
PromptMessage(
role="user", content=TextContent(type="text", text="Hello, world!")
)
]
async def test_async_fn(self):
@ -27,7 +28,9 @@ class TestRenderPrompt:
prompt = Prompt.from_function(fn)
assert await prompt.render() == [
UserMessage(content=TextContent(type="text", text="Hello, world!"))
PromptMessage(
role="user", content=TextContent(type="text", text="Hello, world!")
)
]
async def test_fn_with_args(self):
@ -36,10 +39,11 @@ class TestRenderPrompt:
prompt = Prompt.from_function(fn)
assert await prompt.render(arguments=dict(name="World")) == [
UserMessage(
PromptMessage(
role="user",
content=TextContent(
type="text", text="Hello, World! You're 30 years old."
)
),
)
]
@ -52,33 +56,42 @@ class TestRenderPrompt:
await prompt.render(arguments=dict(age=40))
async def test_fn_returns_message(self):
async def fn() -> Message:
return UserMessage(content="Hello, world!")
prompt = Prompt.from_function(fn)
assert await prompt.render() == [
UserMessage(content=TextContent(type="text", text="Hello, world!"))
]
async def test_fn_returns_assistant_message(self):
async def fn() -> Message:
return AssistantMessage(
content=TextContent(type="text", text="Hello, world!")
async def fn() -> PromptMessage:
return PromptMessage(
role="user", content=TextContent(type="text", text="Hello, world!")
)
prompt = Prompt.from_function(fn)
assert await prompt.render() == [
AssistantMessage(content=TextContent(type="text", text="Hello, world!"))
PromptMessage(
role="user", content=TextContent(type="text", text="Hello, world!")
)
]
async def test_fn_returns_assistant_message(self):
async def fn() -> PromptMessage:
return PromptMessage(
role="assistant", content=TextContent(type="text", text="Hello, world!")
)
prompt = Prompt.from_function(fn)
assert await prompt.render() == [
PromptMessage(
role="assistant", content=TextContent(type="text", text="Hello, world!")
)
]
async def test_fn_returns_multiple_messages(self):
expected = [
UserMessage("Hello, world!"),
AssistantMessage("How can I help you today?"),
UserMessage("I'm looking for a restaurant in the center of town."),
Message(role="user", content="Hello, world!"),
Message(role="assistant", content="How can I help you today?"),
Message(
role="user",
content="I'm looking for a restaurant in the center of town.",
),
]
async def fn() -> list[Message]:
async def fn() -> list[PromptMessage]:
return expected
prompt = Prompt.from_function(fn)
@ -94,13 +107,17 @@ class TestRenderPrompt:
return expected
prompt = Prompt.from_function(fn)
assert await prompt.render() == [UserMessage(t) for t in expected]
assert await prompt.render() == [
PromptMessage(role="user", content=TextContent(type="text", text=t))
for t in expected
]
async def test_fn_returns_resource_content(self):
"""Test returning a message with resource content."""
async def fn() -> Message:
return UserMessage(
async def fn() -> PromptMessage:
return PromptMessage(
role="user",
content=EmbeddedResource(
type="resource",
resource=TextResourceContents(
@ -108,12 +125,13 @@ class TestRenderPrompt:
text="File contents",
mimeType="text/plain",
),
)
),
)
prompt = Prompt.from_function(fn)
assert await prompt.render() == [
UserMessage(
PromptMessage(
role="user",
content=EmbeddedResource(
type="resource",
resource=TextResourceContents(
@ -121,17 +139,18 @@ class TestRenderPrompt:
text="File contents",
mimeType="text/plain",
),
)
),
)
]
async def test_fn_returns_mixed_content(self):
"""Test returning messages with mixed content types."""
async def fn() -> list[Message]:
async def fn() -> list[PromptMessage | str]:
return [
UserMessage(content="Please analyze this file:"),
UserMessage(
"Please analyze this file:",
PromptMessage(
role="user",
content=EmbeddedResource(
type="resource",
resource=TextResourceContents(
@ -139,17 +158,19 @@ class TestRenderPrompt:
text="File contents",
mimeType="text/plain",
),
)
),
),
AssistantMessage(content="I'll help analyze that file."),
Message(role="assistant", content="I'll help analyze that file."),
]
prompt = Prompt.from_function(fn)
assert await prompt.render() == [
UserMessage(
content=TextContent(type="text", text="Please analyze this file:")
PromptMessage(
role="user",
content=TextContent(type="text", text="Please analyze this file:"),
),
UserMessage(
PromptMessage(
role="user",
content=EmbeddedResource(
type="resource",
resource=TextResourceContents(
@ -157,32 +178,34 @@ class TestRenderPrompt:
text="File contents",
mimeType="text/plain",
),
)
),
),
AssistantMessage(
content=TextContent(type="text", text="I'll help analyze that file.")
PromptMessage(
role="assistant",
content=TextContent(type="text", text="I'll help analyze that file."),
),
]
async def test_fn_returns_dict_with_resource(self):
async def test_fn_returns_message_with_resource(self):
"""Test returning a dict with resource content."""
async def fn() -> dict:
return {
"role": "user",
"content": {
"type": "resource",
"resource": {
"uri": FileUrl("file://file.txt"),
"text": "File contents",
"mimeType": "text/plain",
},
},
}
async def fn() -> PromptMessage:
return PromptMessage(
role="user",
content=EmbeddedResource(
type="resource",
resource=TextResourceContents(
uri=FileUrl("file://file.txt"),
text="File contents",
mimeType="text/plain",
),
),
)
prompt = Prompt.from_function(fn)
assert await prompt.render() == [
UserMessage(
PromptMessage(
role="user",
content=EmbeddedResource(
type="resource",
resource=TextResourceContents(
@ -190,6 +213,6 @@ class TestRenderPrompt:
text="File contents",
mimeType="text/plain",
),
)
),
)
]

View file

@ -7,7 +7,7 @@ from mcp.shared.context import LifespanContextT
from fastmcp import Context
from fastmcp.exceptions import NotFoundError
from fastmcp.prompts import Prompt
from fastmcp.prompts.prompt import TextContent, UserMessage
from fastmcp.prompts.prompt import PromptMessage, TextContent
from fastmcp.prompts.prompt_manager import PromptManager
@ -147,28 +147,36 @@ class TestPromptManager:
"""Test rendering a prompt."""
def fn() -> str:
"""An example prompt."""
return "Hello, world!"
manager = PromptManager()
prompt = Prompt.from_function(fn)
manager.add_prompt(prompt)
messages = await manager.render_prompt("fn")
assert messages == [
UserMessage(content=TextContent(type="text", text="Hello, world!"))
result = await manager.render_prompt("fn")
assert result.description == "An example prompt."
assert result.messages == [
PromptMessage(
role="user", content=TextContent(type="text", text="Hello, world!")
)
]
async def test_render_prompt_with_args(self):
"""Test rendering a prompt with arguments."""
def fn(name: str) -> str:
"""An example prompt."""
return f"Hello, {name}!"
manager = PromptManager()
prompt = Prompt.from_function(fn)
manager.add_prompt(prompt)
messages = await manager.render_prompt("fn", arguments={"name": "World"})
assert messages == [
UserMessage(content=TextContent(type="text", text="Hello, World!"))
result = await manager.render_prompt("fn", arguments={"name": "World"})
assert result.description == "An example prompt."
assert result.messages == [
PromptMessage(
role="user", content=TextContent(type="text", text="Hello, World!")
)
]
async def test_render_unknown_prompt(self):

View file

@ -319,14 +319,16 @@ async def test_import_with_proxy_prompts():
@api_app.prompt()
def greeting(name: str) -> str:
"""Example greeting prompt."""
return f"Hello, {name} from API!"
proxy_app = FastMCP.from_client(Client(api_app))
await main_app.import_server("api", proxy_app)
result = await main_app._mcp_get_prompt("api_greeting", {"name": "World"})
assert result.messages is not None
# Check that the message contains our greeting
assert isinstance(result.messages[0].content, TextContent)
assert result.messages[0].content.text == "Hello, World from API!"
assert result.description == "Example greeting prompt."
async def test_import_with_proxy_resources():

View file

@ -207,7 +207,7 @@ class TestPrompts:
async def test_render_prompt_calls_prompt(self, proxy_server):
async with Client(proxy_server) as client:
result = await client.get_prompt("welcome", {"name": "Alice"})
assert isinstance(result[0], mcp.types.PromptMessage)
assert result[0].role == "user"
assert isinstance(result[0].content, mcp.types.TextContent)
assert result[0].content.text == "Welcome to FastMCP, Alice!"
assert isinstance(result.messages[0], mcp.types.PromptMessage)
assert result.messages[0].role == "user"
assert isinstance(result.messages[0].content, mcp.types.TextContent)
assert result.messages[0].content.text == "Welcome to FastMCP, Alice!"

View file

@ -640,16 +640,16 @@ class TestPromptDecorator:
async with Client(mcp) as client:
result = await client.get_prompt("test_prompt", {"name": "World"})
assert len(result) == 1
message = result[0]
assert len(result.messages) == 1
message = result.messages[0]
assert isinstance(message.content, TextContent)
assert message.content.text == "Hello, World!"
result = await client.get_prompt(
"test_prompt", {"name": "World", "greeting": "Hi"}
)
assert len(result) == 1
message = result[0]
assert len(result.messages) == 1
message = result.messages[0]
assert isinstance(message.content, TextContent)
assert message.content.text == "Hi, World!"
@ -668,8 +668,8 @@ class TestPromptDecorator:
async with Client(mcp) as client:
result = await client.get_prompt("test_prompt")
assert len(result) == 1
message = result[0]
assert len(result.messages) == 1
message = result.messages[0]
assert isinstance(message.content, TextContent)
assert message.content.text == "My prefix: Hello, world!"
@ -687,8 +687,8 @@ class TestPromptDecorator:
async with Client(mcp) as client:
result = await client.get_prompt("test_prompt")
assert len(result) == 1
message = result[0]
assert len(result.messages) == 1
message = result.messages[0]
assert isinstance(message.content, TextContent)
assert message.content.text == "Class prefix: Hello, world!"
@ -703,8 +703,8 @@ class TestPromptDecorator:
async with Client(mcp) as client:
result = await client.get_prompt("test_prompt")
assert len(result) == 1
message = result[0]
assert len(result.messages) == 1
message = result.messages[0]
assert isinstance(message.content, TextContent)
assert message.content.text == "Static Hello, world!"
@ -717,8 +717,8 @@ class TestPromptDecorator:
async with Client(mcp) as client:
result = await client.get_prompt("test_prompt")
assert len(result) == 1
message = result[0]
assert len(result.messages) == 1
message = result.messages[0]
assert isinstance(message.content, TextContent)
assert message.content.text == "Async Hello, world!"

View file

@ -18,7 +18,7 @@ from pydantic import AnyUrl, Field
from fastmcp import Client, Context, FastMCP
from fastmcp.exceptions import ClientError
from fastmcp.prompts.prompt import EmbeddedResource, Message, UserMessage
from fastmcp.prompts.prompt import EmbeddedResource, PromptMessage
from fastmcp.resources import FileResource, FunctionResource
from fastmcp.utilities.types import Image
@ -1267,8 +1267,8 @@ class TestPrompts:
async with Client(mcp) as client:
result = await client.get_prompt("fn", {"name": "World"})
assert len(result) == 1
message = result[0]
assert len(result.messages) == 1
message = result.messages[0]
assert message.role == "user"
content = message.content
assert isinstance(content, TextContent)
@ -1279,8 +1279,9 @@ class TestPrompts:
mcp = FastMCP()
@mcp.prompt()
def fn() -> Message:
return UserMessage(
def fn() -> PromptMessage:
return PromptMessage(
role="user",
content=EmbeddedResource(
type="resource",
resource=TextResourceContents(
@ -1288,13 +1289,13 @@ class TestPrompts:
text="File contents",
mimeType="text/plain",
),
)
),
)
async with Client(mcp) as client:
result = await client.get_prompt("fn")
assert result[0].role == "user"
content = result[0].content
assert result.messages[0].role == "user"
content = result.messages[0].content
assert isinstance(content, EmbeddedResource)
resource = content.resource
assert isinstance(resource, TextResourceContents)
@ -1370,6 +1371,6 @@ class TestPromptContext:
async with Client(mcp) as client:
result = await client.get_prompt("prompt_fn", {"name": "World"})
assert len(result) == 1
message = result[0]
assert len(result.messages) == 1
message = result.messages[0]
assert message.role == "user"