Spaces:
Running
Running
Jeremiah Lowin commited on
Commit ·
f6c5553
1
Parent(s): 4f92aa9
Update tests for prompts
Browse files- README.md +2 -2
- docs/servers/context.mdx +1 -1
- docs/servers/fastmcp.mdx +1 -1
- docs/servers/prompts.mdx +10 -10
- src/fastmcp/server/server.py +2 -2
- tests/client/test_client.py +1 -1
- tests/client/test_sse.py +1 -1
- tests/client/test_streamable_http.py +1 -1
- tests/deprecated/test_deprecated.py +1 -1
- tests/deprecated/test_mount_separators.py +1 -1
- tests/server/http/test_http_dependencies.py +1 -1
- tests/server/test_import_server.py +4 -4
- tests/server/test_mount.py +4 -4
- tests/server/test_proxy.py +1 -1
- tests/server/test_run_server.py +1 -1
- tests/server/test_server.py +4 -4
- tests/server/test_server_interactions.py +15 -12
- tests/test_servers/fastmcp_server.py +1 -1
README.md
CHANGED
|
@@ -173,10 +173,10 @@ Learn more in the [**Resources & Templates Documentation**](https://gofastmcp.co
|
|
| 173 |
|
| 174 |
### Prompts
|
| 175 |
|
| 176 |
-
Prompts define reusable message templates to guide LLM interactions. Decorate functions with `@mcp.prompt
|
| 177 |
|
| 178 |
```python
|
| 179 |
-
@mcp.prompt
|
| 180 |
def summarize_request(text: str) -> str:
|
| 181 |
"""Generate a prompt asking for a summary."""
|
| 182 |
return f"Please summarize the following text:\n\n{text}"
|
|
|
|
| 173 |
|
| 174 |
### Prompts
|
| 175 |
|
| 176 |
+
Prompts define reusable message templates to guide LLM interactions. Decorate functions with `@mcp.prompt`. Return strings or `Message` objects.
|
| 177 |
|
| 178 |
```python
|
| 179 |
+
@mcp.prompt
|
| 180 |
def summarize_request(text: str) -> str:
|
| 181 |
"""Generate a prompt asking for a summary."""
|
| 182 |
return f"Please summarize the following text:\n\n{text}"
|
docs/servers/context.mdx
CHANGED
|
@@ -71,7 +71,7 @@ async def get_user_profile(user_id: str, ctx: Context) -> dict:
|
|
| 71 |
<VersionBadge version="2.2.5" />
|
| 72 |
|
| 73 |
```python
|
| 74 |
-
@mcp.prompt
|
| 75 |
async def data_analysis_request(dataset: str, ctx: Context) -> str:
|
| 76 |
"""Generate a request to analyze data with contextual information."""
|
| 77 |
# Context is available as the ctx parameter
|
|
|
|
| 71 |
<VersionBadge version="2.2.5" />
|
| 72 |
|
| 73 |
```python
|
| 74 |
+
@mcp.prompt
|
| 75 |
async def data_analysis_request(dataset: str, ctx: Context) -> str:
|
| 76 |
"""Generate a request to analyze data with contextual information."""
|
| 77 |
# Context is available as the ctx parameter
|
docs/servers/fastmcp.mdx
CHANGED
|
@@ -87,7 +87,7 @@ See [Resources & Templates](/servers/resources) for detailed documentation.
|
|
| 87 |
Prompts are reusable message templates for guiding the LLM.
|
| 88 |
|
| 89 |
```python
|
| 90 |
-
@mcp.prompt
|
| 91 |
def analyze_data(data_points: list[float]) -> str:
|
| 92 |
"""Creates a prompt asking for analysis of numerical data."""
|
| 93 |
formatted_data = ", ".join(str(point) for point in data_points)
|
|
|
|
| 87 |
Prompts are reusable message templates for guiding the LLM.
|
| 88 |
|
| 89 |
```python
|
| 90 |
+
@mcp.prompt
|
| 91 |
def analyze_data(data_points: list[float]) -> str:
|
| 92 |
"""Creates a prompt asking for analysis of numerical data."""
|
| 93 |
formatted_data = ", ".join(str(point) for point in data_points)
|
docs/servers/prompts.mdx
CHANGED
|
@@ -33,13 +33,13 @@ from fastmcp.prompts.prompt import Message, PromptMessage, TextContent
|
|
| 33 |
mcp = FastMCP(name="PromptServer")
|
| 34 |
|
| 35 |
# Basic prompt returning a string (converted to user message automatically)
|
| 36 |
-
@mcp.prompt
|
| 37 |
def ask_about_topic(topic: str) -> str:
|
| 38 |
"""Generates a user message asking for an explanation of a topic."""
|
| 39 |
return f"Can you please explain the concept of '{topic}'?"
|
| 40 |
|
| 41 |
# Prompt returning a specific message type
|
| 42 |
-
@mcp.prompt
|
| 43 |
def generate_code_request(language: str, task_description: str) -> PromptMessage:
|
| 44 |
"""Generates a user message requesting code generation."""
|
| 45 |
content = f"Write a {language} function that performs the following task: {task_description}"
|
|
@@ -69,7 +69,7 @@ FastMCP intelligently handles different return types from your prompt function:
|
|
| 69 |
```python
|
| 70 |
from fastmcp.prompts.prompt import Message
|
| 71 |
|
| 72 |
-
@mcp.prompt
|
| 73 |
def roleplay_scenario(character: str, situation: str) -> list[Message]:
|
| 74 |
"""Sets up a roleplaying scenario with initial messages."""
|
| 75 |
return [
|
|
@@ -89,7 +89,7 @@ Type annotations are important for prompts. They:
|
|
| 89 |
from pydantic import Field
|
| 90 |
from typing import Literal, Optional
|
| 91 |
|
| 92 |
-
@mcp.prompt
|
| 93 |
def generate_content_request(
|
| 94 |
topic: str = Field(description="The main subject to cover"),
|
| 95 |
format: Literal["blog", "email", "social"] = "blog",
|
|
@@ -111,7 +111,7 @@ def generate_content_request(
|
|
| 111 |
Parameters in your function signature are considered **required** unless they have a default value.
|
| 112 |
|
| 113 |
```python
|
| 114 |
-
@mcp.prompt
|
| 115 |
def data_analysis_prompt(
|
| 116 |
data_uri: str, # Required - no default value
|
| 117 |
analysis_type: str = "summary", # Optional - has default value
|
|
@@ -154,13 +154,13 @@ FastMCP seamlessly supports both standard (`def`) and asynchronous (`async def`)
|
|
| 154 |
|
| 155 |
```python
|
| 156 |
# Synchronous prompt
|
| 157 |
-
@mcp.prompt
|
| 158 |
def simple_question(question: str) -> str:
|
| 159 |
"""Generates a simple question to ask the LLM."""
|
| 160 |
return f"Question: {question}"
|
| 161 |
|
| 162 |
# Asynchronous prompt
|
| 163 |
-
@mcp.prompt
|
| 164 |
async def data_based_prompt(data_id: str) -> str:
|
| 165 |
"""Generates a prompt based on data that needs to be fetched."""
|
| 166 |
# In a real scenario, you might fetch data from a database or API
|
|
@@ -183,7 +183,7 @@ from fastmcp import FastMCP, Context
|
|
| 183 |
|
| 184 |
mcp = FastMCP(name="PromptServer")
|
| 185 |
|
| 186 |
-
@mcp.prompt
|
| 187 |
async def generate_report_request(report_type: str, ctx: Context) -> str:
|
| 188 |
"""Generates a request for a report."""
|
| 189 |
return f"Please create a {report_type} report. Request ID: {ctx.request_id}"
|
|
@@ -207,12 +207,12 @@ mcp = FastMCP(
|
|
| 207 |
on_duplicate_prompts="error" # Raise an error if a prompt name is duplicated
|
| 208 |
)
|
| 209 |
|
| 210 |
-
@mcp.prompt
|
| 211 |
def greeting(): return "Hello, how can I help you today?"
|
| 212 |
|
| 213 |
# This registration attempt will raise a ValueError because
|
| 214 |
# "greeting" is already registered and the behavior is "error".
|
| 215 |
-
# @mcp.prompt
|
| 216 |
# def greeting(): return "Hi there! What can I do for you?"
|
| 217 |
```
|
| 218 |
|
|
|
|
| 33 |
mcp = FastMCP(name="PromptServer")
|
| 34 |
|
| 35 |
# Basic prompt returning a string (converted to user message automatically)
|
| 36 |
+
@mcp.prompt
|
| 37 |
def ask_about_topic(topic: str) -> str:
|
| 38 |
"""Generates a user message asking for an explanation of a topic."""
|
| 39 |
return f"Can you please explain the concept of '{topic}'?"
|
| 40 |
|
| 41 |
# Prompt returning a specific message type
|
| 42 |
+
@mcp.prompt
|
| 43 |
def generate_code_request(language: str, task_description: str) -> PromptMessage:
|
| 44 |
"""Generates a user message requesting code generation."""
|
| 45 |
content = f"Write a {language} function that performs the following task: {task_description}"
|
|
|
|
| 69 |
```python
|
| 70 |
from fastmcp.prompts.prompt import Message
|
| 71 |
|
| 72 |
+
@mcp.prompt
|
| 73 |
def roleplay_scenario(character: str, situation: str) -> list[Message]:
|
| 74 |
"""Sets up a roleplaying scenario with initial messages."""
|
| 75 |
return [
|
|
|
|
| 89 |
from pydantic import Field
|
| 90 |
from typing import Literal, Optional
|
| 91 |
|
| 92 |
+
@mcp.prompt
|
| 93 |
def generate_content_request(
|
| 94 |
topic: str = Field(description="The main subject to cover"),
|
| 95 |
format: Literal["blog", "email", "social"] = "blog",
|
|
|
|
| 111 |
Parameters in your function signature are considered **required** unless they have a default value.
|
| 112 |
|
| 113 |
```python
|
| 114 |
+
@mcp.prompt
|
| 115 |
def data_analysis_prompt(
|
| 116 |
data_uri: str, # Required - no default value
|
| 117 |
analysis_type: str = "summary", # Optional - has default value
|
|
|
|
| 154 |
|
| 155 |
```python
|
| 156 |
# Synchronous prompt
|
| 157 |
+
@mcp.prompt
|
| 158 |
def simple_question(question: str) -> str:
|
| 159 |
"""Generates a simple question to ask the LLM."""
|
| 160 |
return f"Question: {question}"
|
| 161 |
|
| 162 |
# Asynchronous prompt
|
| 163 |
+
@mcp.prompt
|
| 164 |
async def data_based_prompt(data_id: str) -> str:
|
| 165 |
"""Generates a prompt based on data that needs to be fetched."""
|
| 166 |
# In a real scenario, you might fetch data from a database or API
|
|
|
|
| 183 |
|
| 184 |
mcp = FastMCP(name="PromptServer")
|
| 185 |
|
| 186 |
+
@mcp.prompt
|
| 187 |
async def generate_report_request(report_type: str, ctx: Context) -> str:
|
| 188 |
"""Generates a request for a report."""
|
| 189 |
return f"Please create a {report_type} report. Request ID: {ctx.request_id}"
|
|
|
|
| 207 |
on_duplicate_prompts="error" # Raise an error if a prompt name is duplicated
|
| 208 |
)
|
| 209 |
|
| 210 |
+
@mcp.prompt
|
| 211 |
def greeting(): return "Hello, how can I help you today?"
|
| 212 |
|
| 213 |
# This registration attempt will raise a ValueError because
|
| 214 |
# "greeting" is already registered and the behavior is "error".
|
| 215 |
+
# @mcp.prompt
|
| 216 |
# def greeting(): return "Hi there! What can I do for you?"
|
| 217 |
```
|
| 218 |
|
src/fastmcp/server/server.py
CHANGED
|
@@ -796,7 +796,7 @@ class FastMCP(Generic[LifespanResultT]):
|
|
| 796 |
|
| 797 |
This decorator supports multiple calling patterns:
|
| 798 |
- @server.prompt (without parentheses)
|
| 799 |
-
- @server.prompt
|
| 800 |
- @server.prompt("custom_name") (with name as first argument)
|
| 801 |
- @server.prompt(name="custom_name") (with name as keyword argument)
|
| 802 |
- server.prompt(function, name="custom_name") (direct function call)
|
|
@@ -818,7 +818,7 @@ class FastMCP(Generic[LifespanResultT]):
|
|
| 818 |
}
|
| 819 |
]
|
| 820 |
|
| 821 |
-
@server.prompt
|
| 822 |
def analyze_with_context(table_name: str, ctx: Context) -> list[Message]:
|
| 823 |
ctx.info(f"Analyzing table {table_name}")
|
| 824 |
schema = read_table_schema(table_name)
|
|
|
|
| 796 |
|
| 797 |
This decorator supports multiple calling patterns:
|
| 798 |
- @server.prompt (without parentheses)
|
| 799 |
+
- @server.prompt (with empty parentheses)
|
| 800 |
- @server.prompt("custom_name") (with name as first argument)
|
| 801 |
- @server.prompt(name="custom_name") (with name as keyword argument)
|
| 802 |
- server.prompt(function, name="custom_name") (direct function call)
|
|
|
|
| 818 |
}
|
| 819 |
]
|
| 820 |
|
| 821 |
+
@server.prompt
|
| 822 |
def analyze_with_context(table_name: str, ctx: Context) -> list[Message]:
|
| 823 |
ctx.info(f"Analyzing table {table_name}")
|
| 824 |
schema = read_table_schema(table_name)
|
tests/client/test_client.py
CHANGED
|
@@ -53,7 +53,7 @@ def fastmcp_server():
|
|
| 53 |
return {"id": user_id, "name": f"User {user_id}", "active": True}
|
| 54 |
|
| 55 |
# Add a prompt
|
| 56 |
-
@server.prompt
|
| 57 |
def welcome(name: str) -> str:
|
| 58 |
"""Example greeting prompt."""
|
| 59 |
return f"Welcome to FastMCP, {name}!"
|
|
|
|
| 53 |
return {"id": user_id, "name": f"User {user_id}", "active": True}
|
| 54 |
|
| 55 |
# Add a prompt
|
| 56 |
+
@server.prompt
|
| 57 |
def welcome(name: str) -> str:
|
| 58 |
"""Example greeting prompt."""
|
| 59 |
return f"Welcome to FastMCP, {name}!"
|
tests/client/test_sse.py
CHANGED
|
@@ -55,7 +55,7 @@ def fastmcp_server():
|
|
| 55 |
return dict(request.headers)
|
| 56 |
|
| 57 |
# Add a prompt
|
| 58 |
-
@server.prompt
|
| 59 |
def welcome(name: str) -> str:
|
| 60 |
"""Example greeting prompt."""
|
| 61 |
return f"Welcome to FastMCP, {name}!"
|
|
|
|
| 55 |
return dict(request.headers)
|
| 56 |
|
| 57 |
# Add a prompt
|
| 58 |
+
@server.prompt
|
| 59 |
def welcome(name: str) -> str:
|
| 60 |
"""Example greeting prompt."""
|
| 61 |
return f"Welcome to FastMCP, {name}!"
|
tests/client/test_streamable_http.py
CHANGED
|
@@ -55,7 +55,7 @@ def fastmcp_server():
|
|
| 55 |
return dict(request.headers)
|
| 56 |
|
| 57 |
# Add a prompt
|
| 58 |
-
@server.prompt
|
| 59 |
def welcome(name: str) -> str:
|
| 60 |
"""Example greeting prompt."""
|
| 61 |
return f"Welcome to FastMCP, {name}!"
|
|
|
|
| 55 |
return dict(request.headers)
|
| 56 |
|
| 57 |
# Add a prompt
|
| 58 |
+
@server.prompt
|
| 59 |
def welcome(name: str) -> str:
|
| 60 |
"""Example greeting prompt."""
|
| 61 |
return f"Welcome to FastMCP, {name}!"
|
tests/deprecated/test_deprecated.py
CHANGED
|
@@ -133,7 +133,7 @@ def test_mount_prompt_separator_deprecation_warning():
|
|
| 133 |
main_app.mount("sub", sub_app, prompt_separator="-")
|
| 134 |
|
| 135 |
# Verify the separator is ignored and the default is used
|
| 136 |
-
@sub_app.prompt
|
| 137 |
def test_prompt():
|
| 138 |
return "test"
|
| 139 |
|
|
|
|
| 133 |
main_app.mount("sub", sub_app, prompt_separator="-")
|
| 134 |
|
| 135 |
# Verify the separator is ignored and the default is used
|
| 136 |
+
@sub_app.prompt
|
| 137 |
def test_prompt():
|
| 138 |
return "test"
|
| 139 |
|
tests/deprecated/test_mount_separators.py
CHANGED
|
@@ -53,7 +53,7 @@ def test_mount_prompt_separator_deprecation_warning():
|
|
| 53 |
main_app.mount("sub", sub_app, prompt_separator="-")
|
| 54 |
|
| 55 |
# Verify the separator is ignored and the default is used
|
| 56 |
-
@sub_app.prompt
|
| 57 |
def test_prompt():
|
| 58 |
return "test"
|
| 59 |
|
|
|
|
| 53 |
main_app.mount("sub", sub_app, prompt_separator="-")
|
| 54 |
|
| 55 |
# Verify the separator is ignored and the default is used
|
| 56 |
+
@sub_app.prompt
|
| 57 |
def test_prompt():
|
| 58 |
return "test"
|
| 59 |
|
tests/server/http/test_http_dependencies.py
CHANGED
|
@@ -28,7 +28,7 @@ def fastmcp_server():
|
|
| 28 |
return dict(request.headers)
|
| 29 |
|
| 30 |
# Add a prompt
|
| 31 |
-
@server.prompt
|
| 32 |
def get_headers_prompt() -> str:
|
| 33 |
"""Get the HTTP headers from the request."""
|
| 34 |
request = get_http_request()
|
|
|
|
| 28 |
return dict(request.headers)
|
| 29 |
|
| 30 |
# Add a prompt
|
| 31 |
+
@server.prompt
|
| 32 |
def get_headers_prompt() -> str:
|
| 33 |
"""Get the HTTP headers from the request."""
|
| 34 |
request = get_http_request()
|
tests/server/test_import_server.py
CHANGED
|
@@ -130,7 +130,7 @@ async def test_import_with_prompts():
|
|
| 130 |
assistant_app = FastMCP("AssistantApp")
|
| 131 |
|
| 132 |
# Add a prompt to the assistant app
|
| 133 |
-
@assistant_app.prompt
|
| 134 |
def greeting(name: str) -> str:
|
| 135 |
return f"Hello, {name}!"
|
| 136 |
|
|
@@ -174,11 +174,11 @@ async def test_import_multiple_prompts():
|
|
| 174 |
sql_app = FastMCP("SQLApp")
|
| 175 |
|
| 176 |
# Add prompts to each app
|
| 177 |
-
@python_app.prompt
|
| 178 |
def review_python(code: str) -> str:
|
| 179 |
return f"Reviewing Python code:\n{code}"
|
| 180 |
|
| 181 |
-
@sql_app.prompt
|
| 182 |
def explain_sql(query: str) -> str:
|
| 183 |
return f"Explaining SQL query:\n{query}"
|
| 184 |
|
|
@@ -316,7 +316,7 @@ async def test_import_with_proxy_prompts():
|
|
| 316 |
main_app = FastMCP("MainApp")
|
| 317 |
api_app = FastMCP("APIApp")
|
| 318 |
|
| 319 |
-
@api_app.prompt
|
| 320 |
def greeting(name: str) -> str:
|
| 321 |
"""Example greeting prompt."""
|
| 322 |
return f"Hello, {name} from API!"
|
|
|
|
| 130 |
assistant_app = FastMCP("AssistantApp")
|
| 131 |
|
| 132 |
# Add a prompt to the assistant app
|
| 133 |
+
@assistant_app.prompt
|
| 134 |
def greeting(name: str) -> str:
|
| 135 |
return f"Hello, {name}!"
|
| 136 |
|
|
|
|
| 174 |
sql_app = FastMCP("SQLApp")
|
| 175 |
|
| 176 |
# Add prompts to each app
|
| 177 |
+
@python_app.prompt
|
| 178 |
def review_python(code: str) -> str:
|
| 179 |
return f"Reviewing Python code:\n{code}"
|
| 180 |
|
| 181 |
+
@sql_app.prompt
|
| 182 |
def explain_sql(query: str) -> str:
|
| 183 |
return f"Explaining SQL query:\n{query}"
|
| 184 |
|
|
|
|
| 316 |
main_app = FastMCP("MainApp")
|
| 317 |
api_app = FastMCP("APIApp")
|
| 318 |
|
| 319 |
+
@api_app.prompt
|
| 320 |
def greeting(name: str) -> str:
|
| 321 |
"""Example greeting prompt."""
|
| 322 |
return f"Hello, {name} from API!"
|
tests/server/test_mount.py
CHANGED
|
@@ -194,7 +194,7 @@ class TestMultipleServerMount:
|
|
| 194 |
def working_resource():
|
| 195 |
return "Working resource"
|
| 196 |
|
| 197 |
-
@working_app.prompt
|
| 198 |
def working_prompt() -> str:
|
| 199 |
return "Working prompt"
|
| 200 |
|
|
@@ -384,7 +384,7 @@ class TestPrompts:
|
|
| 384 |
main_app = FastMCP("MainApp")
|
| 385 |
assistant_app = FastMCP("AssistantApp")
|
| 386 |
|
| 387 |
-
@assistant_app.prompt
|
| 388 |
def greeting(name: str) -> str:
|
| 389 |
return f"Hello, {name}!"
|
| 390 |
|
|
@@ -409,7 +409,7 @@ class TestPrompts:
|
|
| 409 |
main_app.mount("assistant", assistant_app)
|
| 410 |
|
| 411 |
# Add a prompt after mounting
|
| 412 |
-
@assistant_app.prompt
|
| 413 |
def farewell(name: str) -> str:
|
| 414 |
return f"Goodbye, {name}!"
|
| 415 |
|
|
@@ -507,7 +507,7 @@ class TestProxyServer:
|
|
| 507 |
# Create original server
|
| 508 |
original_server = FastMCP("OriginalServer")
|
| 509 |
|
| 510 |
-
@original_server.prompt
|
| 511 |
def welcome(name: str) -> str:
|
| 512 |
return f"Welcome, {name}!"
|
| 513 |
|
|
|
|
| 194 |
def working_resource():
|
| 195 |
return "Working resource"
|
| 196 |
|
| 197 |
+
@working_app.prompt
|
| 198 |
def working_prompt() -> str:
|
| 199 |
return "Working prompt"
|
| 200 |
|
|
|
|
| 384 |
main_app = FastMCP("MainApp")
|
| 385 |
assistant_app = FastMCP("AssistantApp")
|
| 386 |
|
| 387 |
+
@assistant_app.prompt
|
| 388 |
def greeting(name: str) -> str:
|
| 389 |
return f"Hello, {name}!"
|
| 390 |
|
|
|
|
| 409 |
main_app.mount("assistant", assistant_app)
|
| 410 |
|
| 411 |
# Add a prompt after mounting
|
| 412 |
+
@assistant_app.prompt
|
| 413 |
def farewell(name: str) -> str:
|
| 414 |
return f"Goodbye, {name}!"
|
| 415 |
|
|
|
|
| 507 |
# Create original server
|
| 508 |
original_server = FastMCP("OriginalServer")
|
| 509 |
|
| 510 |
+
@original_server.prompt
|
| 511 |
def welcome(name: str) -> str:
|
| 512 |
return f"Welcome, {name}!"
|
| 513 |
|
tests/server/test_proxy.py
CHANGED
|
@@ -61,7 +61,7 @@ def fastmcp_server():
|
|
| 61 |
|
| 62 |
# --- Prompts ---
|
| 63 |
|
| 64 |
-
@server.prompt
|
| 65 |
def welcome(name: str) -> str:
|
| 66 |
return f"Welcome to FastMCP, {name}!"
|
| 67 |
|
|
|
|
| 61 |
|
| 62 |
# --- Prompts ---
|
| 63 |
|
| 64 |
+
@server.prompt
|
| 65 |
def welcome(name: str) -> str:
|
| 66 |
return f"Welcome to FastMCP, {name}!"
|
| 67 |
|
tests/server/test_run_server.py
CHANGED
|
@@ -53,7 +53,7 @@
|
|
| 53 |
|
| 54 |
# # --- Prompts ---
|
| 55 |
|
| 56 |
-
# @server.prompt
|
| 57 |
# def welcome(name: str) -> str:
|
| 58 |
# return f"Welcome to FastMCP, {name}!"
|
| 59 |
|
|
|
|
| 53 |
|
| 54 |
# # --- Prompts ---
|
| 55 |
|
| 56 |
+
# @server.prompt
|
| 57 |
# def welcome(name: str) -> str:
|
| 58 |
# return f"Welcome to FastMCP, {name}!"
|
| 59 |
|
tests/server/test_server.py
CHANGED
|
@@ -659,7 +659,7 @@ class TestPromptDecorator:
|
|
| 659 |
async def test_prompt_decorator(self):
|
| 660 |
mcp = FastMCP()
|
| 661 |
|
| 662 |
-
@mcp.prompt
|
| 663 |
def fn() -> str:
|
| 664 |
return "Hello, world!"
|
| 665 |
|
|
@@ -720,7 +720,7 @@ class TestPromptDecorator:
|
|
| 720 |
async def test_prompt_decorator_with_parameters(self):
|
| 721 |
mcp = FastMCP()
|
| 722 |
|
| 723 |
-
@mcp.prompt
|
| 724 |
def test_prompt(name: str, greeting: str = "Hello") -> str:
|
| 725 |
return f"{greeting}, {name}!"
|
| 726 |
|
|
@@ -789,7 +789,7 @@ class TestPromptDecorator:
|
|
| 789 |
|
| 790 |
class MyClass:
|
| 791 |
@staticmethod
|
| 792 |
-
@mcp.prompt
|
| 793 |
def test_prompt() -> str:
|
| 794 |
return "Static Hello, world!"
|
| 795 |
|
|
@@ -802,7 +802,7 @@ class TestPromptDecorator:
|
|
| 802 |
async def test_prompt_decorator_async_function(self):
|
| 803 |
mcp = FastMCP()
|
| 804 |
|
| 805 |
-
@mcp.prompt
|
| 806 |
async def test_prompt() -> str:
|
| 807 |
return "Async Hello, world!"
|
| 808 |
|
|
|
|
| 659 |
async def test_prompt_decorator(self):
|
| 660 |
mcp = FastMCP()
|
| 661 |
|
| 662 |
+
@mcp.prompt
|
| 663 |
def fn() -> str:
|
| 664 |
return "Hello, world!"
|
| 665 |
|
|
|
|
| 720 |
async def test_prompt_decorator_with_parameters(self):
|
| 721 |
mcp = FastMCP()
|
| 722 |
|
| 723 |
+
@mcp.prompt
|
| 724 |
def test_prompt(name: str, greeting: str = "Hello") -> str:
|
| 725 |
return f"{greeting}, {name}!"
|
| 726 |
|
|
|
|
| 789 |
|
| 790 |
class MyClass:
|
| 791 |
@staticmethod
|
| 792 |
+
@mcp.prompt
|
| 793 |
def test_prompt() -> str:
|
| 794 |
return "Static Hello, world!"
|
| 795 |
|
|
|
|
| 802 |
async def test_prompt_decorator_async_function(self):
|
| 803 |
mcp = FastMCP()
|
| 804 |
|
| 805 |
+
@mcp.prompt
|
| 806 |
async def test_prompt() -> str:
|
| 807 |
return "Async Hello, world!"
|
| 808 |
|
tests/server/test_server_interactions.py
CHANGED
|
@@ -1091,7 +1091,7 @@ class TestPrompts:
|
|
| 1091 |
"""Test that the prompt decorator registers prompts correctly."""
|
| 1092 |
mcp = FastMCP()
|
| 1093 |
|
| 1094 |
-
@mcp.prompt
|
| 1095 |
def fn() -> str:
|
| 1096 |
return "Hello, world!"
|
| 1097 |
|
|
@@ -1133,20 +1133,23 @@ class TestPrompts:
|
|
| 1133 |
content = await prompt.render()
|
| 1134 |
assert content[0].content.text == "Hello, world!" # type: ignore[attr-defined]
|
| 1135 |
|
| 1136 |
-
def
|
| 1137 |
-
"""Test error when decorator is used incorrectly."""
|
| 1138 |
mcp = FastMCP()
|
| 1139 |
-
with pytest.raises(TypeError, match="decorator was used incorrectly"):
|
| 1140 |
|
| 1141 |
-
|
| 1142 |
-
|
| 1143 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1144 |
|
| 1145 |
async def test_list_prompts(self):
|
| 1146 |
"""Test listing prompts through MCP protocol."""
|
| 1147 |
mcp = FastMCP()
|
| 1148 |
|
| 1149 |
-
@mcp.prompt
|
| 1150 |
def fn(name: str, optional: str = "default") -> str:
|
| 1151 |
return f"Hello, {name}! {optional}"
|
| 1152 |
|
|
@@ -1169,7 +1172,7 @@ class TestPrompts:
|
|
| 1169 |
"""Test getting a prompt through MCP protocol."""
|
| 1170 |
mcp = FastMCP()
|
| 1171 |
|
| 1172 |
-
@mcp.prompt
|
| 1173 |
def fn(name: str) -> str:
|
| 1174 |
return f"Hello, {name}!"
|
| 1175 |
|
|
@@ -1185,7 +1188,7 @@ class TestPrompts:
|
|
| 1185 |
"""Test getting a prompt that returns resource content."""
|
| 1186 |
mcp = FastMCP()
|
| 1187 |
|
| 1188 |
-
@mcp.prompt
|
| 1189 |
def fn() -> PromptMessage:
|
| 1190 |
return PromptMessage(
|
| 1191 |
role="user",
|
|
@@ -1220,7 +1223,7 @@ class TestPrompts:
|
|
| 1220 |
"""Test error when required arguments are missing."""
|
| 1221 |
mcp = FastMCP()
|
| 1222 |
|
| 1223 |
-
@mcp.prompt
|
| 1224 |
def prompt_fn(name: str) -> str:
|
| 1225 |
return f"Hello, {name}!"
|
| 1226 |
|
|
@@ -1271,7 +1274,7 @@ class TestPromptContext:
|
|
| 1271 |
async def test_prompt_context(self):
|
| 1272 |
mcp = FastMCP()
|
| 1273 |
|
| 1274 |
-
@mcp.prompt
|
| 1275 |
def prompt_fn(name: str, ctx: Context) -> str:
|
| 1276 |
assert isinstance(ctx, Context)
|
| 1277 |
return f"Hello, {name}! {ctx.request_id}"
|
|
|
|
| 1091 |
"""Test that the prompt decorator registers prompts correctly."""
|
| 1092 |
mcp = FastMCP()
|
| 1093 |
|
| 1094 |
+
@mcp.prompt
|
| 1095 |
def fn() -> str:
|
| 1096 |
return "Hello, world!"
|
| 1097 |
|
|
|
|
| 1133 |
content = await prompt.render()
|
| 1134 |
assert content[0].content.text == "Hello, world!" # type: ignore[attr-defined]
|
| 1135 |
|
| 1136 |
+
async def test_prompt_decorator_with_parens(self):
|
|
|
|
| 1137 |
mcp = FastMCP()
|
|
|
|
| 1138 |
|
| 1139 |
+
@mcp.prompt()
|
| 1140 |
+
def fn() -> str:
|
| 1141 |
+
return "Hello, world!"
|
| 1142 |
+
|
| 1143 |
+
prompts_dict = await mcp.get_prompts()
|
| 1144 |
+
assert len(prompts_dict) == 1
|
| 1145 |
+
prompt = prompts_dict["fn"]
|
| 1146 |
+
assert prompt.name == "fn"
|
| 1147 |
|
| 1148 |
async def test_list_prompts(self):
|
| 1149 |
"""Test listing prompts through MCP protocol."""
|
| 1150 |
mcp = FastMCP()
|
| 1151 |
|
| 1152 |
+
@mcp.prompt
|
| 1153 |
def fn(name: str, optional: str = "default") -> str:
|
| 1154 |
return f"Hello, {name}! {optional}"
|
| 1155 |
|
|
|
|
| 1172 |
"""Test getting a prompt through MCP protocol."""
|
| 1173 |
mcp = FastMCP()
|
| 1174 |
|
| 1175 |
+
@mcp.prompt
|
| 1176 |
def fn(name: str) -> str:
|
| 1177 |
return f"Hello, {name}!"
|
| 1178 |
|
|
|
|
| 1188 |
"""Test getting a prompt that returns resource content."""
|
| 1189 |
mcp = FastMCP()
|
| 1190 |
|
| 1191 |
+
@mcp.prompt
|
| 1192 |
def fn() -> PromptMessage:
|
| 1193 |
return PromptMessage(
|
| 1194 |
role="user",
|
|
|
|
| 1223 |
"""Test error when required arguments are missing."""
|
| 1224 |
mcp = FastMCP()
|
| 1225 |
|
| 1226 |
+
@mcp.prompt
|
| 1227 |
def prompt_fn(name: str) -> str:
|
| 1228 |
return f"Hello, {name}!"
|
| 1229 |
|
|
|
|
| 1274 |
async def test_prompt_context(self):
|
| 1275 |
mcp = FastMCP()
|
| 1276 |
|
| 1277 |
+
@mcp.prompt
|
| 1278 |
def prompt_fn(name: str, ctx: Context) -> str:
|
| 1279 |
assert isinstance(ctx, Context)
|
| 1280 |
return f"Hello, {name}! {ctx.request_id}"
|
tests/test_servers/fastmcp_server.py
CHANGED
|
@@ -53,6 +53,6 @@ async def get_user(user_id: str) -> dict[str, Any] | None:
|
|
| 53 |
# --- Prompts ---
|
| 54 |
|
| 55 |
|
| 56 |
-
@server.prompt
|
| 57 |
def welcome(name: str) -> str:
|
| 58 |
return f"Welcome to FastMCP, {name}!"
|
|
|
|
| 53 |
# --- Prompts ---
|
| 54 |
|
| 55 |
|
| 56 |
+
@server.prompt
|
| 57 |
def welcome(name: str) -> str:
|
| 58 |
return f"Welcome to FastMCP, {name}!"
|