Skip to content

Commit 1db7a20

Browse files
committed
Address reviewer comments
1 parent b0db786 commit 1db7a20

2 files changed

Lines changed: 19 additions & 17 deletions

File tree

integrations/mcp/src/haystack_integrations/tools/mcp/mcp_tool.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,15 +63,15 @@ def _resolve_headers(headers: dict[str, str | Secret] | None) -> dict[str, str]
6363
return resolved_headers
6464

6565

66-
def extract_first_text_element(result: str) -> str | dict[str, Any]:
66+
def _extract_first_text_element(tool_call_result: str) -> str | dict[str, Any]:
6767
"""
68-
Return the first text content block from an MCP tool response.
68+
Return the first text content block from an MCP tool call result.
6969
70-
MCP tool responses may include mixed content types such as text, image, or
70+
MCP tool call results may include mixed content types such as text, image, or
7171
audio blocks. This helper extracts the first text block because the tool
7272
invoker expects a single parsed payload rather than the full content list.
7373
"""
74-
parsed: dict = json.loads(result)
74+
parsed: dict = json.loads(tool_call_result)
7575
content: list = parsed.get("content", [])
7676
for block in content:
7777
if isinstance(block, dict) and block.get("type") == "text":
@@ -1109,7 +1109,7 @@ async def invoke() -> Any:
11091109
# Parse JSON to dict only when outputs_to_state is configured.
11101110
# ToolInvoker requires dict for _merge_tool_outputs(); ToolCallResult.result expects str otherwise.
11111111
if self.outputs_to_state:
1112-
return extract_first_text_element(result)
1112+
return _extract_first_text_element(result)
11131113

11141114
return result
11151115
except (MCPError, TimeoutError) as e:
@@ -1140,7 +1140,7 @@ async def ainvoke(self, **kwargs: Any) -> str | dict[str, Any]:
11401140
# Parse JSON to dict only when outputs_to_state is configured.
11411141
# ToolInvoker requires dict for _merge_tool_outputs(); ToolCallResult.result expects str otherwise.
11421142
if self.outputs_to_state:
1143-
return extract_first_text_element(result)
1143+
return _extract_first_text_element(result)
11441144

11451145
return result
11461146
except asyncio.TimeoutError as e:

integrations/mcp/tests/test_mcp_tool.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
MCPTool,
1616
StdioServerInfo,
1717
)
18-
from haystack_integrations.tools.mcp.mcp_tool import StdioClient, extract_first_text_element
18+
from haystack_integrations.tools.mcp.mcp_tool import StdioClient, _extract_first_text_element
1919

2020
from .mcp_memory_transport import InMemoryServerInfo
2121
from .mcp_servers_fixtures import calculator_mcp, echo_mcp
@@ -27,19 +27,21 @@ def simple_haystack_tool(name: str) -> str:
2727
return f"Hello, {name}!"
2828

2929

30+
# from https://modelcontextprotocol.io/specification/draft/server/tools#output-schema
31+
EXAMPLE_MCP_TOOL_CALL_RESULT = {
32+
"content": [{"type": "text", "text": '{"temperature": 22.5, "conditions": "Partly cloudy", "humidity": 65}'}],
33+
"structuredContent": {"temperature": 22.5, "conditions": "Partly cloudy", "humidity": 65},
34+
}
35+
36+
3037
def test_extract_first_text_element():
3138
"""Test that extract_first_text skips non-text blocks and parses the first text block."""
32-
result = json.dumps(
33-
{
34-
"content": [
35-
{"type": "image", "data": "ignored"},
36-
{"type": "text", "text": '{"answer": 42}'},
37-
{"type": "text", "text": '{"answer": 7}'},
38-
]
39-
}
40-
)
39+
tool_call_result = EXAMPLE_MCP_TOOL_CALL_RESULT
40+
tool_call_result["content"].insert(0, {"type": "image", "data": "ignored"})
41+
tool_call_result["content"].insert(1, {"type": "text", "text": '{"answer": 42}'}) # target
42+
tool_call_result = json.dumps(tool_call_result)
4143

42-
extracted = extract_first_text_element(result)
44+
extracted = _extract_first_text_element(tool_call_result)
4345

4446
assert extracted == {"answer": 42}
4547

0 commit comments

Comments
 (0)