Skip to content

Commit 9fb300c

Browse files
committed
fix(ci): resolve pyright errors on MCP content type union
Extract _extract_text() helper that uses hasattr() to safely access .text on MCP content items (union of TextContent, ImageContent, EmbeddedResource, etc.). Pyright now passes with 0 errors.
1 parent 063da1b commit 9fb300c

2 files changed

Lines changed: 21 additions & 11 deletions

File tree

tests/integration/conftest.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,23 @@
11
"""Shared fixtures for integration tests."""
22

33
import json
4+
from typing import Any
5+
46
import pytest
57
from fastmcp import Client
68

79
_server_initialized = False
810

911

12+
def _extract_text(result: Any) -> str:
13+
"""Extract text from MCP CallToolResult, handling content type union."""
14+
if result.content:
15+
item = result.content[0]
16+
if hasattr(item, "text"):
17+
return item.text # type: ignore[no-any-return]
18+
return "[]"
19+
20+
1021
@pytest.fixture(scope="session")
1122
def mcp_server():
1223
"""Build the full MCP server with all providers and transforms wired up.
@@ -37,31 +48,30 @@ def mcp_server():
3748
return mcp
3849

3950

40-
async def call_tool(mcp_server, tool_name: str, arguments: dict | None = None) -> dict:
51+
async def call_tool(mcp_server: Any, tool_name: str, arguments: dict | None = None) -> dict:
4152
"""Call a tool through the MCP Client layer and return parsed JSON."""
4253
async with Client(mcp_server) as client:
4354
result = await client.call_tool('call_tool', {
4455
'name': tool_name,
4556
'arguments': arguments or {},
4657
})
47-
return json.loads(result.content[0].text)
58+
return json.loads(_extract_text(result)) # type: ignore[no-any-return]
4859

4960

50-
async def discover(mcp_server, query: str) -> list[dict]:
61+
async def discover(mcp_server: Any, query: str) -> list[dict]:
5162
"""Search for tools via BM25 discover_tools and return parsed results."""
5263
async with Client(mcp_server) as client:
5364
result = await client.call_tool('discover_tools', {'query': query})
54-
# discover_tools may return results in different formats
55-
text = result.content[0].text if result.content else "[]"
65+
text = _extract_text(result)
5666
try:
5767
parsed = json.loads(text)
5868
return parsed if isinstance(parsed, list) else []
5969
except json.JSONDecodeError:
6070
return []
6171

6272

63-
async def call_direct_tool(mcp_server, tool_name: str, arguments: dict | None = None) -> dict:
73+
async def call_direct_tool(mcp_server: Any, tool_name: str, arguments: dict | None = None) -> dict:
6474
"""Call an always-visible tool directly (not through call_tool proxy)."""
6575
async with Client(mcp_server) as client:
6676
result = await client.call_tool(tool_name, arguments or {})
67-
return json.loads(result.content[0].text)
77+
return json.loads(_extract_text(result)) # type: ignore[no-any-return]

tests/integration/test_tool_scenarios.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -610,20 +610,20 @@ async def test_selective_loading_discover_tools(self, mcp_server):
610610
call_tool_name="call_tool",
611611
))
612612

613+
from tests.integration.conftest import _extract_text
614+
613615
async with Client(selective_mcp) as client:
614616
# Weather tools should NOT appear
615617
result = await client.call_tool("discover_tools", {"query": "weather forecast"})
616-
text = result.content[0].text if result.content else "[]"
617-
weather_results = json.loads(text) if text else []
618+
weather_results = json.loads(_extract_text(result))
618619
weather_names = [r["name"] for r in weather_results] if isinstance(weather_results, list) else []
619620
assert not any("wx_" in n for n in weather_names), (
620621
f"Weather tools found in selective (bank_of_canada only) server: {weather_names}"
621622
)
622623

623624
# BOC tools SHOULD appear
624625
result2 = await client.call_tool("discover_tools", {"query": "exchange rates"})
625-
text2 = result2.content[0].text if result2.content else "[]"
626-
boc_results = json.loads(text2) if text2 else []
626+
boc_results = json.loads(_extract_text(result2))
627627
boc_names = [r["name"] for r in boc_results] if isinstance(boc_results, list) else []
628628
assert any("boc_" in n for n in boc_names), (
629629
f"No BOC tools found in selective server. Got: {boc_names}"

0 commit comments

Comments
 (0)