Skip to content

Commit fd2cc42

Browse files
Merge branch 'webb/test-fastmcp-stdio' into webb/test-mcp-streamable-http
2 parents 4715afa + 1bf6876 commit fd2cc42

1 file changed

Lines changed: 52 additions & 89 deletions

File tree

tests/integrations/fastmcp/test_fastmcp.py

Lines changed: 52 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,6 @@ async def __call__(self, *args, **kwargs):
7272
ReadResourceRequest = None
7373

7474

75-
try:
76-
from fastmcp import __version__ as FASTMCP_VERSION
77-
except ImportError:
78-
FASTMCP_VERSION = None
79-
80-
8175
# Collect available FastMCP implementations for parametrization
8276
fastmcp_implementations = []
8377
fastmcp_ids = []
@@ -320,24 +314,10 @@ def add_numbers(a: int, b: int) -> dict:
320314
request_id="req-123",
321315
)
322316

323-
if (
324-
isinstance(mcp, StandaloneFastMCP)
325-
and FASTMCP_VERSION is not None
326-
and FASTMCP_VERSION.startswith("2")
327-
):
328-
assert result.message.root.result["content"][0]["text"] == json.dumps(
329-
{"result": 15, "operation": "addition"}, separators=(",", ":")
330-
)
331-
elif (
332-
isinstance(mcp, StandaloneFastMCP) and FASTMCP_VERSION is not None
333-
): # Checking for None is not precise.
334-
assert result.message.root.result["content"][0]["text"] == json.dumps(
335-
{"result": 15, "operation": "addition"}
336-
)
337-
else:
338-
assert result.message.root.result["content"][0]["text"] == json.dumps(
339-
{"result": 15, "operation": "addition"}, indent=2
340-
)
317+
assert json.loads(result.message.root.result["content"][0]["text"]) == {
318+
"result": 15,
319+
"operation": "addition",
320+
}
341321

342322
(tx,) = events
343323
assert tx["type"] == "transaction"
@@ -581,41 +561,12 @@ def get_user_data(user_id: int) -> dict:
581561
request_id="req-complex",
582562
)
583563

584-
if (
585-
isinstance(mcp, StandaloneFastMCP)
586-
and FASTMCP_VERSION is not None
587-
and FASTMCP_VERSION.startswith("2")
588-
):
589-
assert result.message.root.result["content"][0]["text"] == json.dumps(
590-
{
591-
"id": 123,
592-
"name": "Alice",
593-
"nested": {"preferences": {"theme": "dark", "notifications": True}},
594-
"tags": ["admin", "verified"],
595-
},
596-
separators=(",", ":"),
597-
)
598-
elif (
599-
isinstance(mcp, StandaloneFastMCP) and FASTMCP_VERSION is not None
600-
): # Checking for None is not precise.
601-
assert result.message.root.result["content"][0]["text"] == json.dumps(
602-
{
603-
"id": 123,
604-
"name": "Alice",
605-
"nested": {"preferences": {"theme": "dark", "notifications": True}},
606-
"tags": ["admin", "verified"],
607-
}
608-
)
609-
else:
610-
assert result.message.root.result["content"][0]["text"] == json.dumps(
611-
{
612-
"id": 123,
613-
"name": "Alice",
614-
"nested": {"preferences": {"theme": "dark", "notifications": True}},
615-
"tags": ["admin", "verified"],
616-
},
617-
indent=2,
618-
)
564+
assert json.loads(result.message.root.result["content"][0]["text"]) == {
565+
"id": 123,
566+
"name": "Alice",
567+
"nested": {"preferences": {"theme": "dark", "notifications": True}},
568+
"tags": ["admin", "verified"],
569+
}
619570

620571
(tx,) = events
621572
assert tx["type"] == "transaction"
@@ -1057,24 +1008,9 @@ def stdio_tool(n: int) -> dict:
10571008
request_id="req-stdio",
10581009
)
10591010

1060-
if (
1061-
isinstance(mcp, StandaloneFastMCP)
1062-
and FASTMCP_VERSION is not None
1063-
and FASTMCP_VERSION.startswith("2")
1064-
):
1065-
assert result.message.root.result["content"][0]["text"] == json.dumps(
1066-
{"squared": 49}, separators=(",", ":")
1067-
)
1068-
elif (
1069-
isinstance(mcp, StandaloneFastMCP) and FASTMCP_VERSION is not None
1070-
): # Checking for None is not precise.
1071-
assert result.message.root.result["content"][0]["text"] == json.dumps(
1072-
{"squared": 49}
1073-
)
1074-
else:
1075-
assert result.message.root.result["content"][0]["text"] == json.dumps(
1076-
{"squared": 49}, indent=2
1077-
)
1011+
assert json.loads(result.message.root.result["content"][0]["text"]) == {
1012+
"squared": 49
1013+
}
10781014

10791015
(tx,) = events
10801016

@@ -1118,10 +1054,11 @@ def package_specific_tool(x: int) -> int:
11181054
assert tx["type"] == "transaction"
11191055

11201056

1057+
@pytest.mark.asyncio
11211058
@pytest.mark.skipif(
11221059
not HAS_STANDALONE_FASTMCP, reason="standalone fastmcp not installed"
11231060
)
1124-
def test_standalone_fastmcp_specific_features(sentry_init, capture_events):
1061+
async def test_standalone_fastmcp_specific_features(sentry_init, capture_events, stdio):
11251062
"""Test features specific to standalone fastmcp package"""
11261063
sentry_init(
11271064
integrations=[MCPIntegration()],
@@ -1139,12 +1076,19 @@ def standalone_specific_tool(message: str) -> dict:
11391076
return {"echo": message, "length": len(message)}
11401077

11411078
with start_transaction(name="standalone fastmcp tx"):
1142-
result = call_tool_through_mcp(
1143-
mcp, "standalone_specific_tool", {"message": "Hello FastMCP"}
1079+
result = await stdio(
1080+
mcp._mcp_server,
1081+
method="tools/call",
1082+
params={
1083+
"name": "standalone_specific_tool",
1084+
"arguments": {"message": "Hello FastMCP"},
1085+
},
11441086
)
11451087

1146-
assert result["echo"] == "Hello FastMCP"
1147-
assert result["length"] == 13
1088+
assert json.loads(result.message.root.result["content"][0]["text"]) == {
1089+
"echo": "Hello FastMCP",
1090+
"length": 13,
1091+
}
11481092

11491093
(tx,) = events
11501094
assert tx["type"] == "transaction"
@@ -1155,8 +1099,11 @@ def standalone_specific_tool(message: str) -> dict:
11551099
# =============================================================================
11561100

11571101

1102+
@pytest.mark.asyncio
11581103
@pytest.mark.parametrize("FastMCP", fastmcp_implementations, ids=fastmcp_ids)
1159-
def test_fastmcp_tool_with_no_arguments(sentry_init, capture_events, FastMCP):
1104+
async def test_fastmcp_tool_with_no_arguments(
1105+
sentry_init, capture_events, FastMCP, stdio
1106+
):
11601107
"""Test FastMCP tool with no arguments"""
11611108
sentry_init(
11621109
integrations=[MCPIntegration()],
@@ -1172,16 +1119,26 @@ def no_args_tool() -> str:
11721119
return "success"
11731120

11741121
with start_transaction(name="fastmcp tx"):
1175-
result = call_tool_through_mcp(mcp, "no_args_tool", {})
1122+
result = await stdio(
1123+
mcp._mcp_server,
1124+
method="tools/call",
1125+
params={
1126+
"name": "no_args_tool",
1127+
"arguments": {},
1128+
},
1129+
)
11761130

1177-
assert result["result"] == "success"
1131+
assert result.message.root.result["content"][0]["text"] == "success"
11781132

11791133
(tx,) = events
11801134
assert tx["type"] == "transaction"
11811135

11821136

1137+
@pytest.mark.asyncio
11831138
@pytest.mark.parametrize("FastMCP", fastmcp_implementations, ids=fastmcp_ids)
1184-
def test_fastmcp_tool_with_none_return(sentry_init, capture_events, FastMCP):
1139+
async def test_fastmcp_tool_with_none_return(
1140+
sentry_init, capture_events, FastMCP, stdio
1141+
):
11851142
"""Test FastMCP tool that returns None"""
11861143
sentry_init(
11871144
integrations=[MCPIntegration()],
@@ -1197,10 +1154,16 @@ def none_return_tool(action: str) -> None:
11971154
pass
11981155

11991156
with start_transaction(name="fastmcp tx"):
1200-
result = call_tool_through_mcp(mcp, "none_return_tool", {"action": "log"})
1157+
result = await stdio(
1158+
mcp._mcp_server,
1159+
method="tools/call",
1160+
params={
1161+
"name": "none_return_tool",
1162+
"arguments": {"action": "log"},
1163+
},
1164+
)
12011165

1202-
# Helper function normalizes to {"result": value} format
1203-
assert result["result"] is None
1166+
assert len(result.message.root.result["content"]) == 0
12041167

12051168
(tx,) = events
12061169
assert tx["type"] == "transaction"

0 commit comments

Comments
 (0)