Skip to content

Commit cc4a19d

Browse files
merge and simplify assertions
2 parents 2df9629 + 8f57fcd commit cc4a19d

2 files changed

Lines changed: 63 additions & 129 deletions

File tree

tests/conftest.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -673,7 +673,10 @@ def stdio(
673673
get_initialized_notification_payload,
674674
get_mcp_command_payload,
675675
):
676-
async def inner(server, method: str, params, request_id: str):
676+
async def inner(server, method: str, params, request_id: str | None = None):
677+
if request_id is None:
678+
request_id = "1"
679+
677680
read_stream_writer, read_stream = create_memory_object_stream(0) # type: ignore
678681
write_stream, write_stream_reader = create_memory_object_stream(0) # type: ignore
679682

@@ -714,9 +717,6 @@ async def simulate_client(tg, result):
714717
@pytest.fixture()
715718
def json_rpc():
716719
def inner(app, method: str, params, request_id: str):
717-
if request_id is None:
718-
request_id = "1" # arbitrary
719-
720720
with TestClient(app) as client: # type: ignore
721721
init_response = client.post(
722722
"/mcp/",

tests/integrations/fastmcp/test_fastmcp.py

Lines changed: 59 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,6 @@ async def __call__(self, *args, **kwargs):
7676
GetPromptRequest = None
7777
ReadResourceRequest = None
7878

79-
try:
80-
from fastmcp import __version__ as FASTMCP_VERSION
81-
except ImportError:
82-
FASTMCP_VERSION = None
83-
8479

8580
# Collect available FastMCP implementations for parametrization
8681
fastmcp_implementations = []
@@ -324,24 +319,10 @@ def add_numbers(a: int, b: int) -> dict:
324319
request_id="req-123",
325320
)
326321

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

346327
(tx,) = events
347328
assert tx["type"] == "transaction"
@@ -416,26 +397,10 @@ async def multiply_numbers(x: int, y: int) -> dict:
416397
request_id="req-456",
417398
)
418399

419-
if (
420-
isinstance(mcp, StandaloneFastMCP)
421-
and FASTMCP_VERSION is not None
422-
and FASTMCP_VERSION.startswith("2")
423-
):
424-
assert result.json()["result"]["structuredContent"] == {
425-
"result": 42,
426-
"operation": "multiplication",
427-
}
428-
elif (
429-
isinstance(mcp, StandaloneFastMCP) and FASTMCP_VERSION is not None
430-
): # Checking for None is not precise.
431-
assert result.json()["result"]["content"][0]["text"] == json.dumps(
432-
{"result": 42, "operation": "multiplication"},
433-
)
434-
else:
435-
assert result.json()["result"]["content"][0]["text"] == json.dumps(
436-
{"result": 42, "operation": "multiplication"},
437-
indent=2,
438-
)
400+
assert json.loads(result.json()["result"]["content"][0]["text"]) == {
401+
"result": 42,
402+
"operation": "multiplication",
403+
}
439404

440405
transactions = select_mcp_transactions(events)
441406
assert len(transactions) == 1
@@ -618,41 +583,12 @@ def get_user_data(user_id: int) -> dict:
618583
request_id="req-complex",
619584
)
620585

621-
if (
622-
isinstance(mcp, StandaloneFastMCP)
623-
and FASTMCP_VERSION is not None
624-
and FASTMCP_VERSION.startswith("2")
625-
):
626-
assert result.message.root.result["content"][0]["text"] == json.dumps(
627-
{
628-
"id": 123,
629-
"name": "Alice",
630-
"nested": {"preferences": {"theme": "dark", "notifications": True}},
631-
"tags": ["admin", "verified"],
632-
},
633-
separators=(",", ":"),
634-
)
635-
elif (
636-
isinstance(mcp, StandaloneFastMCP) and FASTMCP_VERSION is not None
637-
): # Checking for None is not precise.
638-
assert result.message.root.result["content"][0]["text"] == json.dumps(
639-
{
640-
"id": 123,
641-
"name": "Alice",
642-
"nested": {"preferences": {"theme": "dark", "notifications": True}},
643-
"tags": ["admin", "verified"],
644-
}
645-
)
646-
else:
647-
assert result.message.root.result["content"][0]["text"] == json.dumps(
648-
{
649-
"id": 123,
650-
"name": "Alice",
651-
"nested": {"preferences": {"theme": "dark", "notifications": True}},
652-
"tags": ["admin", "verified"],
653-
},
654-
indent=2,
655-
)
586+
assert json.loads(result.message.root.result["content"][0]["text"]) == {
587+
"id": 123,
588+
"name": "Alice",
589+
"nested": {"preferences": {"theme": "dark", "notifications": True}},
590+
"tags": ["admin", "verified"],
591+
}
656592

657593
(tx,) = events
658594
assert tx["type"] == "transaction"
@@ -1098,23 +1034,9 @@ def http_tool(data: str) -> dict:
10981034
request_id="req-http",
10991035
)
11001036

1101-
if (
1102-
isinstance(mcp, StandaloneFastMCP)
1103-
and FASTMCP_VERSION is not None
1104-
and FASTMCP_VERSION.startswith("2")
1105-
):
1106-
assert result.json()["result"]["structuredContent"] == {"processed": "TEST"}
1107-
elif (
1108-
isinstance(mcp, StandaloneFastMCP) and FASTMCP_VERSION is not None
1109-
): # Checking for None is not precise.
1110-
assert result.json()["result"]["content"][0]["text"] == json.dumps(
1111-
{"processed": "TEST"},
1112-
)
1113-
else:
1114-
assert result.json()["result"]["content"][0]["text"] == json.dumps(
1115-
{"processed": "TEST"},
1116-
indent=2,
1117-
)
1037+
assert json.loads(result.json()["result"]["content"][0]["text"]) == {
1038+
"processed": "TEST"
1039+
}
11181040

11191041
transactions = select_mcp_transactions(events)
11201042
assert len(transactions) == 1
@@ -1152,24 +1074,9 @@ def stdio_tool(n: int) -> dict:
11521074
request_id="req-stdio",
11531075
)
11541076

1155-
if (
1156-
isinstance(mcp, StandaloneFastMCP)
1157-
and FASTMCP_VERSION is not None
1158-
and FASTMCP_VERSION.startswith("2")
1159-
):
1160-
assert result.message.root.result["content"][0]["text"] == json.dumps(
1161-
{"squared": 49}, separators=(",", ":")
1162-
)
1163-
elif (
1164-
isinstance(mcp, StandaloneFastMCP) and FASTMCP_VERSION is not None
1165-
): # Checking for None is not precise.
1166-
assert result.message.root.result["content"][0]["text"] == json.dumps(
1167-
{"squared": 49}
1168-
)
1169-
else:
1170-
assert result.message.root.result["content"][0]["text"] == json.dumps(
1171-
{"squared": 49}, indent=2
1172-
)
1077+
assert json.loads(result.message.root.result["content"][0]["text"]) == {
1078+
"squared": 49
1079+
}
11731080

11741081
(tx,) = events
11751082

@@ -1213,10 +1120,11 @@ def package_specific_tool(x: int) -> int:
12131120
assert tx["type"] == "transaction"
12141121

12151122

1123+
@pytest.mark.asyncio
12161124
@pytest.mark.skipif(
12171125
not HAS_STANDALONE_FASTMCP, reason="standalone fastmcp not installed"
12181126
)
1219-
def test_standalone_fastmcp_specific_features(sentry_init, capture_events):
1127+
async def test_standalone_fastmcp_specific_features(sentry_init, capture_events, stdio):
12201128
"""Test features specific to standalone fastmcp package"""
12211129
sentry_init(
12221130
integrations=[MCPIntegration()],
@@ -1234,12 +1142,19 @@ def standalone_specific_tool(message: str) -> dict:
12341142
return {"echo": message, "length": len(message)}
12351143

12361144
with start_transaction(name="standalone fastmcp tx"):
1237-
result = call_tool_through_mcp(
1238-
mcp, "standalone_specific_tool", {"message": "Hello FastMCP"}
1145+
result = await stdio(
1146+
mcp._mcp_server,
1147+
method="tools/call",
1148+
params={
1149+
"name": "standalone_specific_tool",
1150+
"arguments": {"message": "Hello FastMCP"},
1151+
},
12391152
)
12401153

1241-
assert result["echo"] == "Hello FastMCP"
1242-
assert result["length"] == 13
1154+
assert json.loads(result.message.root.result["content"][0]["text"]) == {
1155+
"echo": "Hello FastMCP",
1156+
"length": 13,
1157+
}
12431158

12441159
(tx,) = events
12451160
assert tx["type"] == "transaction"
@@ -1250,8 +1165,11 @@ def standalone_specific_tool(message: str) -> dict:
12501165
# =============================================================================
12511166

12521167

1168+
@pytest.mark.asyncio
12531169
@pytest.mark.parametrize("FastMCP", fastmcp_implementations, ids=fastmcp_ids)
1254-
def test_fastmcp_tool_with_no_arguments(sentry_init, capture_events, FastMCP):
1170+
async def test_fastmcp_tool_with_no_arguments(
1171+
sentry_init, capture_events, FastMCP, stdio
1172+
):
12551173
"""Test FastMCP tool with no arguments"""
12561174
sentry_init(
12571175
integrations=[MCPIntegration()],
@@ -1267,16 +1185,26 @@ def no_args_tool() -> str:
12671185
return "success"
12681186

12691187
with start_transaction(name="fastmcp tx"):
1270-
result = call_tool_through_mcp(mcp, "no_args_tool", {})
1188+
result = await stdio(
1189+
mcp._mcp_server,
1190+
method="tools/call",
1191+
params={
1192+
"name": "no_args_tool",
1193+
"arguments": {},
1194+
},
1195+
)
12711196

1272-
assert result["result"] == "success"
1197+
assert result.message.root.result["content"][0]["text"] == "success"
12731198

12741199
(tx,) = events
12751200
assert tx["type"] == "transaction"
12761201

12771202

1203+
@pytest.mark.asyncio
12781204
@pytest.mark.parametrize("FastMCP", fastmcp_implementations, ids=fastmcp_ids)
1279-
def test_fastmcp_tool_with_none_return(sentry_init, capture_events, FastMCP):
1205+
async def test_fastmcp_tool_with_none_return(
1206+
sentry_init, capture_events, FastMCP, stdio
1207+
):
12801208
"""Test FastMCP tool that returns None"""
12811209
sentry_init(
12821210
integrations=[MCPIntegration()],
@@ -1292,10 +1220,16 @@ def none_return_tool(action: str) -> None:
12921220
pass
12931221

12941222
with start_transaction(name="fastmcp tx"):
1295-
result = call_tool_through_mcp(mcp, "none_return_tool", {"action": "log"})
1223+
result = await stdio(
1224+
mcp._mcp_server,
1225+
method="tools/call",
1226+
params={
1227+
"name": "none_return_tool",
1228+
"arguments": {"action": "log"},
1229+
},
1230+
)
12961231

1297-
# Helper function normalizes to {"result": value} format
1298-
assert result["result"] is None
1232+
assert len(result.message.root.result["content"]) == 0
12991233

13001234
(tx,) = events
13011235
assert tx["type"] == "transaction"

0 commit comments

Comments
 (0)