chore: import upstream snapshot with attribution
Deploy Docs / deploy-docs (push) Failing after 1s
Conformance Tests / client-conformance (push) Failing after 3s
Conformance Tests / server-conformance (push) Failing after 1s
GitHub Actions Security Analysis / zizmor (push) Failing after 1s
CI / checks (push) Failing after 59m20s
CI / all-green (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 12:10:27 +08:00
commit 49b9bb6724
992 changed files with 161690 additions and 0 deletions
+245
View File
@@ -0,0 +1,245 @@
import threading
from typing import Any
import pytest
from mcp_types import (
ElicitRequest,
ElicitRequestFormParams,
EmbeddedResource,
InputRequiredResult,
TextContent,
TextResourceContents,
)
from mcp.server.mcpserver import Context
from mcp.server.mcpserver.prompts.base import AssistantMessage, Message, Prompt, UserMessage
class TestRenderPrompt:
@pytest.mark.anyio
async def test_basic_fn(self):
def fn() -> str:
return "Hello, world!"
prompt = Prompt.from_function(fn)
assert await prompt.render(None, Context()) == [
UserMessage(content=TextContent(type="text", text="Hello, world!"))
]
@pytest.mark.anyio
async def test_async_fn(self):
async def fn() -> str:
return "Hello, world!"
prompt = Prompt.from_function(fn)
assert await prompt.render(None, Context()) == [
UserMessage(content=TextContent(type="text", text="Hello, world!"))
]
@pytest.mark.anyio
async def test_fn_with_args(self):
async def fn(name: str, age: int = 30) -> str:
return f"Hello, {name}! You're {age} years old."
prompt = Prompt.from_function(fn)
assert await prompt.render({"name": "World"}, Context()) == [
UserMessage(content=TextContent(type="text", text="Hello, World! You're 30 years old."))
]
@pytest.mark.anyio
async def test_fn_with_invalid_kwargs(self):
async def fn(name: str, age: int = 30) -> str: # pragma: no cover
return f"Hello, {name}! You're {age} years old."
prompt = Prompt.from_function(fn)
with pytest.raises(ValueError):
await prompt.render({"age": 40}, Context())
@pytest.mark.anyio
async def test_fn_returns_message(self):
async def fn() -> UserMessage:
return UserMessage(content="Hello, world!")
prompt = Prompt.from_function(fn)
assert await prompt.render(None, Context()) == [
UserMessage(content=TextContent(type="text", text="Hello, world!"))
]
@pytest.mark.anyio
async def test_fn_returns_assistant_message(self):
async def fn() -> AssistantMessage:
return AssistantMessage(content=TextContent(type="text", text="Hello, world!"))
prompt = Prompt.from_function(fn)
assert await prompt.render(None, Context()) == [
AssistantMessage(content=TextContent(type="text", text="Hello, world!"))
]
@pytest.mark.anyio
async def test_fn_returns_multiple_messages(self):
expected: list[Message] = [
UserMessage("Hello, world!"),
AssistantMessage("How can I help you today?"),
UserMessage("I'm looking for a restaurant in the center of town."),
]
async def fn() -> list[Message]:
return expected
prompt = Prompt.from_function(fn)
assert await prompt.render(None, Context()) == expected
@pytest.mark.anyio
async def test_fn_returns_list_of_strings(self):
expected = [
"Hello, world!",
"I'm looking for a restaurant in the center of town.",
]
async def fn() -> list[str]:
return expected
prompt = Prompt.from_function(fn)
assert await prompt.render(None, Context()) == [UserMessage(t) for t in expected]
@pytest.mark.anyio
async def test_fn_returns_resource_content(self):
"""Test returning a message with resource content."""
async def fn() -> UserMessage:
return UserMessage(
content=EmbeddedResource(
type="resource",
resource=TextResourceContents(
uri="file://file.txt",
text="File contents",
mime_type="text/plain",
),
)
)
prompt = Prompt.from_function(fn)
assert await prompt.render(None, Context()) == [
UserMessage(
content=EmbeddedResource(
type="resource",
resource=TextResourceContents(
uri="file://file.txt",
text="File contents",
mime_type="text/plain",
),
)
)
]
@pytest.mark.anyio
async def test_fn_returns_mixed_content(self):
"""Test returning messages with mixed content types."""
async def fn() -> list[Message]:
return [
UserMessage(content="Please analyze this file:"),
UserMessage(
content=EmbeddedResource(
type="resource",
resource=TextResourceContents(
uri="file://file.txt",
text="File contents",
mime_type="text/plain",
),
)
),
AssistantMessage(content="I'll help analyze that file."),
]
prompt = Prompt.from_function(fn)
assert await prompt.render(None, Context()) == [
UserMessage(content=TextContent(type="text", text="Please analyze this file:")),
UserMessage(
content=EmbeddedResource(
type="resource",
resource=TextResourceContents(
uri="file://file.txt",
text="File contents",
mime_type="text/plain",
),
)
),
AssistantMessage(content=TextContent(type="text", text="I'll help analyze that file.")),
]
@pytest.mark.anyio
async def test_fn_returns_dict_with_resource(self):
"""Test returning a dict with resource content."""
async def fn() -> dict[str, Any]:
return {
"role": "user",
"content": {
"type": "resource",
"resource": {
"uri": "file://file.txt",
"text": "File contents",
"mimeType": "text/plain",
},
},
}
prompt = Prompt.from_function(fn)
assert await prompt.render(None, Context()) == [
UserMessage(
content=EmbeddedResource(
type="resource",
resource=TextResourceContents(
uri="file://file.txt",
text="File contents",
mime_type="text/plain",
),
)
)
]
@pytest.mark.anyio
async def test_sync_fn_runs_in_worker_thread():
"""Sync prompt functions must run in a worker thread, not the event loop."""
main_thread = threading.get_ident()
fn_thread: list[int] = []
def blocking_fn() -> str:
fn_thread.append(threading.get_ident())
return "hello"
prompt = Prompt.from_function(blocking_fn)
messages = await prompt.render(None, Context())
assert messages == [UserMessage(content=TextContent(type="text", text="hello"))]
assert fn_thread[0] != main_thread
@pytest.mark.anyio
async def test_render_passes_input_required_result_through_unchanged():
"""Prompt.render returns the InputRequiredResult the function returned, bypassing
message conversion entirely (SEP-2322 multi-round-trip pass-through)."""
sentinel = InputRequiredResult(
input_requests={
"who": ElicitRequest(
params=ElicitRequestFormParams(
message="Who is this for?",
requested_schema={
"type": "object",
"properties": {"name": {"type": "string"}},
"required": ["name"],
},
)
)
}
)
def asking_prompt() -> InputRequiredResult:
return sentinel
prompt = Prompt.from_function(asking_prompt)
result = await prompt.render(None, Context())
assert result is sentinel