Skip to content

Commit 9bd26a6

Browse files
committed
address PR comments
1 parent 3b9d4fa commit 9bd26a6

File tree

4 files changed

+100
-11
lines changed

4 files changed

+100
-11
lines changed

src/mcp/server/fastmcp/prompts/manager.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,23 @@ def list_prompts(self) -> list[Prompt]:
2626

2727
def add_prompt(
2828
self,
29-
fn: AnyFunction,
29+
prompt_or_fn: Prompt | AnyFunction,
3030
name: str | None = None,
3131
description: str | None = None,
3232
) -> Prompt:
3333
"""Add a prompt to the manager.
3434
3535
Args:
36-
fn: Function to create a prompt from
37-
name: Optional name for the prompt
38-
description: Optional description of the prompt
36+
prompt_or_fn: Either a Prompt instance or a function to create a prompt from
37+
name: Optional name for the prompt (only used if prompt_or_fn is a function)
38+
description: Optional description of the prompt (only used if prompt_or_fn is a function)
3939
"""
40-
prompt = Prompt.from_function(fn, name=name, description=description)
40+
if isinstance(prompt_or_fn, Prompt):
41+
prompt = prompt_or_fn
42+
else:
43+
prompt = Prompt.from_function(
44+
prompt_or_fn, name=name, description=description
45+
)
4146

4247
# Check for duplicates
4348
existing = self._prompts.get(prompt.name)

src/mcp/server/fastmcp/server.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
)
3737
from mcp.server.fastmcp.exceptions import ResourceError
3838
from mcp.server.fastmcp.prompts import PromptManager
39+
from mcp.server.fastmcp.prompts.base import Prompt
3940
from mcp.server.fastmcp.resources import FunctionResource, Resource, ResourceManager
4041
from mcp.server.fastmcp.tools import ToolManager
4142
from mcp.server.fastmcp.utilities.logging import configure_logging, get_logger
@@ -486,18 +487,20 @@ def decorator(fn: AnyFunction) -> AnyFunction:
486487

487488
def add_prompt(
488489
self,
489-
fn: AnyFunction,
490+
prompt_or_fn: Prompt | AnyFunction,
490491
name: str | None = None,
491492
description: str | None = None,
492493
) -> None:
493494
"""Add a prompt to the server.
494495
495496
Args:
496-
fn: Function to create a prompt from
497-
name: Optional name for the prompt
498-
description: Optional description of the prompt
497+
prompt_or_fn: Either a Prompt instance or a function to create a prompt from
498+
name: Optional name for the prompt (only used if prompt_or_fn is a function)
499+
description: Optional description of the prompt (only used if prompt_or_fn is a function)
499500
"""
500-
self._prompt_manager.add_prompt(fn, name=name, description=description)
501+
self._prompt_manager.add_prompt(
502+
prompt_or_fn, name=name, description=description
503+
)
501504

502505
def prompt(
503506
self, name: str | None = None, description: str | None = None

tests/server/fastmcp/prompts/test_manager.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,35 @@ def fn() -> str:
1717
assert added.name == "fn"
1818
assert manager.get_prompt("fn") == added
1919

20+
def test_add_prompt_object(self):
21+
"""Test adding a Prompt object directly."""
22+
23+
def fn() -> str:
24+
return "Hello, world!"
25+
26+
prompt = Prompt.from_function(fn, name="test_prompt", description="Test prompt")
27+
manager = PromptManager()
28+
added = manager.add_prompt(prompt)
29+
assert added == prompt
30+
assert manager.get_prompt("test_prompt") == prompt
31+
32+
def test_add_prompt_object_ignores_name_and_description(self):
33+
"""Test that name and description args are ignored when adding a Prompt object."""
34+
35+
def fn() -> str:
36+
return "Hello, world!"
37+
38+
prompt = Prompt.from_function(
39+
fn, name="original_name", description="Original description"
40+
)
41+
manager = PromptManager()
42+
# These should be ignored
43+
added = manager.add_prompt(
44+
prompt, name="ignored_name", description="ignored_description"
45+
)
46+
assert added.name == "original_name"
47+
assert added.description == "Original description"
48+
2049
def test_add_duplicate_prompt(self, caplog):
2150
"""Test adding the same prompt twice."""
2251

tests/server/fastmcp/test_server.py

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@
88
from starlette.routing import Mount, Route
99

1010
from mcp.server.fastmcp import Context, FastMCP
11-
from mcp.server.fastmcp.prompts.base import EmbeddedResource, Message, UserMessage
11+
from mcp.server.fastmcp.prompts.base import (
12+
EmbeddedResource,
13+
Message,
14+
UserMessage,
15+
Prompt,
16+
)
1217
from mcp.server.fastmcp.resources import FileResource, FunctionResource
1318
from mcp.server.fastmcp.utilities.types import Image
1419
from mcp.shared.exceptions import McpError
@@ -851,3 +856,50 @@ def prompt_fn(name: str) -> str:
851856
async with client_session(mcp._mcp_server) as client:
852857
with pytest.raises(McpError, match="Missing required arguments"):
853858
await client.get_prompt("prompt_fn")
859+
860+
@pytest.mark.anyio
861+
async def test_add_prompt_object(self):
862+
"""Test adding a Prompt object directly to FastMCP server."""
863+
864+
def fn() -> str:
865+
return "Hello from custom prompt!"
866+
867+
mcp = FastMCP()
868+
prompt = Prompt.from_function(
869+
fn, name="custom_prompt", description="A custom prompt"
870+
)
871+
mcp.add_prompt(prompt)
872+
873+
prompts = mcp._prompt_manager.list_prompts()
874+
assert len(prompts) == 1
875+
assert prompts[0].name == "custom_prompt"
876+
assert prompts[0].description == "A custom prompt"
877+
878+
@pytest.mark.anyio
879+
async def test_add_prompt_object_through_protocol(self):
880+
"""Test that Prompt objects added directly work through MCP protocol."""
881+
882+
def fn(name: str) -> str:
883+
return f"Hello, {name}!"
884+
885+
mcp = FastMCP()
886+
prompt = Prompt.from_function(
887+
fn, name="custom_greeting", description="Custom greeting prompt"
888+
)
889+
mcp.add_prompt(prompt)
890+
891+
async with client_session(mcp._mcp_server) as client:
892+
# List prompts
893+
result = await client.list_prompts()
894+
assert len(result.prompts) == 1
895+
assert result.prompts[0].name == "custom_greeting"
896+
assert result.prompts[0].description == "Custom greeting prompt"
897+
898+
# Get prompt
899+
prompt_result = await client.get_prompt("custom_greeting", {"name": "Test"})
900+
assert len(prompt_result.messages) == 1
901+
message = prompt_result.messages[0]
902+
assert message.role == "user"
903+
content = message.content
904+
assert isinstance(content, TextContent)
905+
assert content.text == "Hello, Test!"

0 commit comments

Comments
 (0)