mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-21 21:14:17 +02:00
Ensure methods work/are documented
This commit is contained in:
parent
d26a5dffc3
commit
f495de6f3a
6 changed files with 202 additions and 54 deletions
|
|
@ -205,8 +205,8 @@ class TestToolDecorator:
|
|||
mcp = FastMCP()
|
||||
|
||||
class MyClass:
|
||||
@staticmethod
|
||||
@mcp.tool
|
||||
@staticmethod
|
||||
def add(x: int, y: int) -> int:
|
||||
return x + y
|
||||
|
||||
|
|
@ -223,6 +223,17 @@ class TestToolDecorator:
|
|||
result = await mcp._mcp_call_tool("add", {"x": 1, "y": 2})
|
||||
assert result[0].text == "3" # type: ignore[attr-defined]
|
||||
|
||||
async def test_tool_decorator_classmethod_error(self):
|
||||
mcp = FastMCP()
|
||||
|
||||
with pytest.raises(ValueError, match="To decorate a classmethod"):
|
||||
|
||||
class MyClass:
|
||||
@mcp.tool
|
||||
@classmethod
|
||||
def add(cls, y: int) -> None:
|
||||
pass
|
||||
|
||||
async def test_tool_decorator_classmethod_async_function(self):
|
||||
mcp = FastMCP()
|
||||
|
||||
|
|
@ -249,6 +260,20 @@ class TestToolDecorator:
|
|||
result = await mcp._mcp_call_tool("add", {"x": 1, "y": 2})
|
||||
assert result[0].text == "3" # type: ignore[attr-defined]
|
||||
|
||||
async def test_tool_decorator_staticmethod_order(self):
|
||||
"""Test that the recommended decorator order works for static methods"""
|
||||
mcp = FastMCP()
|
||||
|
||||
class MyClass:
|
||||
@staticmethod
|
||||
@mcp.tool
|
||||
def add_v1(x: int, y: int) -> int:
|
||||
return x + y
|
||||
|
||||
# Test that the recommended order works
|
||||
result = await mcp._mcp_call_tool("add_v1", {"x": 1, "y": 2})
|
||||
assert result[0].text == "3" # type: ignore[attr-defined]
|
||||
|
||||
async def test_tool_decorator_with_tags(self):
|
||||
"""Test that the tool decorator properly sets tags."""
|
||||
mcp = FastMCP()
|
||||
|
|
@ -480,12 +505,23 @@ class TestResourceDecorator:
|
|||
result = await client.read_resource("resource://data")
|
||||
assert result[0].text == "Class prefix: Hello, world!" # type: ignore[attr-defined]
|
||||
|
||||
async def test_resource_decorator_classmethod_error(self):
|
||||
mcp = FastMCP()
|
||||
|
||||
with pytest.raises(ValueError, match="To decorate a classmethod"):
|
||||
|
||||
class MyClass:
|
||||
@mcp.resource("resource://data")
|
||||
@classmethod
|
||||
def get_data(cls) -> None:
|
||||
pass
|
||||
|
||||
async def test_resource_decorator_staticmethod(self):
|
||||
mcp = FastMCP()
|
||||
|
||||
class MyClass:
|
||||
@staticmethod
|
||||
@mcp.resource("resource://data")
|
||||
@staticmethod
|
||||
def get_data() -> str:
|
||||
return "Static Hello, world!"
|
||||
|
||||
|
|
@ -504,6 +540,20 @@ class TestResourceDecorator:
|
|||
result = await client.read_resource("resource://data")
|
||||
assert result[0].text == "Async Hello, world!" # type: ignore[attr-defined]
|
||||
|
||||
async def test_resource_decorator_staticmethod_order(self):
|
||||
"""Test that both decorator orders work for static methods"""
|
||||
mcp = FastMCP()
|
||||
|
||||
class MyClass:
|
||||
@mcp.resource("resource://data") # type: ignore[misc] # Type checker warns but runtime works
|
||||
@staticmethod
|
||||
def get_data() -> str:
|
||||
return "Static Hello, world!"
|
||||
|
||||
async with Client(mcp) as client:
|
||||
result = await client.read_resource("resource://data")
|
||||
assert result[0].text == "Static Hello, world!" # type: ignore[attr-defined]
|
||||
|
||||
|
||||
class TestTemplateDecorator:
|
||||
async def test_template_decorator(self):
|
||||
|
|
@ -609,8 +659,8 @@ class TestTemplateDecorator:
|
|||
mcp = FastMCP()
|
||||
|
||||
class MyClass:
|
||||
@staticmethod
|
||||
@mcp.resource("resource://{name}/data")
|
||||
@staticmethod
|
||||
def get_data(name: str) -> str:
|
||||
return f"Static Data for {name}"
|
||||
|
||||
|
|
@ -783,12 +833,23 @@ class TestPromptDecorator:
|
|||
message = result.messages[0]
|
||||
assert message.content.text == "Class prefix: Hello, world!" # type: ignore[attr-defined]
|
||||
|
||||
async def test_prompt_decorator_classmethod_error(self):
|
||||
mcp = FastMCP()
|
||||
|
||||
with pytest.raises(ValueError, match="To decorate a classmethod"):
|
||||
|
||||
class MyClass:
|
||||
@mcp.prompt
|
||||
@classmethod
|
||||
def test_prompt(cls) -> None:
|
||||
pass
|
||||
|
||||
async def test_prompt_decorator_staticmethod(self):
|
||||
mcp = FastMCP()
|
||||
|
||||
class MyClass:
|
||||
@staticmethod
|
||||
@mcp.prompt
|
||||
@staticmethod
|
||||
def test_prompt() -> str:
|
||||
return "Static Hello, world!"
|
||||
|
||||
|
|
@ -881,6 +942,22 @@ class TestPromptDecorator:
|
|||
def my_function() -> str:
|
||||
return "Hello, world!"
|
||||
|
||||
async def test_prompt_decorator_staticmethod_order(self):
|
||||
"""Test that both decorator orders work for static methods"""
|
||||
mcp = FastMCP()
|
||||
|
||||
class MyClass:
|
||||
@mcp.prompt # type: ignore[misc] # Type checker warns but runtime works
|
||||
@staticmethod
|
||||
def test_prompt() -> str:
|
||||
return "Static Hello, world!"
|
||||
|
||||
async with Client(mcp) as client:
|
||||
result = await client.get_prompt("test_prompt")
|
||||
assert len(result.messages) == 1
|
||||
message = result.messages[0]
|
||||
assert message.content.text == "Static Hello, world!" # type: ignore[attr-defined]
|
||||
|
||||
|
||||
class TestResourcePrefixHelpers:
|
||||
@pytest.mark.parametrize(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue