@@ -192,6 +192,60 @@ async def test_mcp_invocation_crash_causes_error(caplog: pytest.LogCaptureFixtur
192192 assert "Error invoking MCP tool test_tool_1" in caplog .text
193193
194194
195+ @pytest .mark .asyncio
196+ async def test_mcp_invocation_mcp_error_reraises (caplog : pytest .LogCaptureFixture ):
197+ """Test that McpError from server.call_tool is re-raised so the FunctionTool failure
198+ pipeline (failure_error_function) can handle it.
199+
200+ When an MCP server raises McpError (e.g. upstream HTTP 4xx/5xx), invoke_mcp_tool
201+ re-raises so the configured failure_error_function shapes the model-visible error.
202+ With the default failure_error_function the FunctionTool returns a string error
203+ result; with failure_error_function=None the error is propagated to the caller.
204+ """
205+ caplog .set_level (logging .DEBUG )
206+
207+ from mcp .shared .exceptions import McpError
208+ from mcp .types import ErrorData
209+
210+ class McpErrorFakeMCPServer (FakeMCPServer ):
211+ async def call_tool (
212+ self ,
213+ tool_name : str ,
214+ arguments : dict [str , Any ] | None ,
215+ meta : dict [str , Any ] | None = None ,
216+ ):
217+ raise McpError (ErrorData (code = - 32000 , message = "upstream 422 Unprocessable Entity" ))
218+
219+ server = McpErrorFakeMCPServer ()
220+ server .add_tool ("search" , {})
221+
222+ ctx = RunContextWrapper (context = None )
223+ tool = MCPTool (name = "search" , inputSchema = {})
224+
225+ # invoke_mcp_tool itself should re-raise McpError
226+ with pytest .raises (McpError ):
227+ await MCPUtil .invoke_mcp_tool (server , tool , ctx , "{}" )
228+
229+ # Warning (not error) should be logged before re-raising
230+ assert "returned an error" in caplog .text
231+
232+ # Via FunctionTool with default failure_error_function: error becomes a string result
233+ mcp_tool = MCPTool (name = "search" , inputSchema = {})
234+ agent = Agent (name = "test-agent" )
235+ function_tool = MCPUtil .to_function_tool (
236+ mcp_tool , server , convert_schemas_to_strict = False , agent = agent
237+ )
238+ tool_context = ToolContext (
239+ context = None ,
240+ tool_name = "search" ,
241+ tool_call_id = "test_call_mcp_error" ,
242+ tool_arguments = "{}" ,
243+ )
244+ result = await function_tool .on_invoke_tool (tool_context , "{}" )
245+ assert isinstance (result , str )
246+ assert "upstream 422 Unprocessable Entity" in result or "error" in result .lower ()
247+
248+
195249@pytest .mark .asyncio
196250async def test_mcp_tool_graceful_error_handling (caplog : pytest .LogCaptureFixture ):
197251 """Test that MCP tool errors are handled gracefully when invoked via FunctionTool.
0 commit comments