From c5aa5583195e61da4b69ab171650f160b78096ee Mon Sep 17 00:00:00 2001 From: slhafzjw Date: Sun, 19 Apr 2026 17:27:27 +0800 Subject: [PATCH] fix(McpActionExecutor): handle client call failures gracefully --- .../runner/execution/McpActionExecutor.java | 9 ++++- .../execution/McpActionExecutorTest.java | 38 +++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 Partner-Core/src/test/java/work/slhaf/partner/core/action/runner/execution/McpActionExecutorTest.java diff --git a/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/execution/McpActionExecutor.java b/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/execution/McpActionExecutor.java index c4add8d1..26dde909 100644 --- a/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/execution/McpActionExecutor.java +++ b/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/execution/McpActionExecutor.java @@ -29,7 +29,14 @@ public class McpActionExecutor { .name(metaAction.getName()) .arguments(metaAction.getParams()) .build(); - McpSchema.CallToolResult callToolResult = mcpClient.callTool(callToolRequest); + McpSchema.CallToolResult callToolResult; + try { + callToolResult = mcpClient.callTool(callToolRequest); + } catch (Exception e) { + response.setOk(false); + response.setData("MCP tool call failed: " + e.getMessage()); + return response; + } Boolean error = callToolResult.isError(); response.setOk(error == null || !error); response.setData(extractResponseData(callToolResult)); diff --git a/Partner-Core/src/test/java/work/slhaf/partner/core/action/runner/execution/McpActionExecutorTest.java b/Partner-Core/src/test/java/work/slhaf/partner/core/action/runner/execution/McpActionExecutorTest.java new file mode 100644 index 00000000..3956adb3 --- /dev/null +++ b/Partner-Core/src/test/java/work/slhaf/partner/core/action/runner/execution/McpActionExecutorTest.java @@ -0,0 +1,38 @@ +package work.slhaf.partner.core.action.runner.execution; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import work.slhaf.partner.core.action.entity.MetaAction; +import work.slhaf.partner.core.action.runner.mcp.McpClientRegistry; + +import java.lang.reflect.Field; +import java.util.Map; + +class McpActionExecutorTest { + + @Test + void testRunReturnsFailureWhenClientThrows() { + McpClientRegistry clientRegistry = new McpClientRegistry(); + clientRegistry.register("broken", buildThrowingMcpClient()); + McpActionExecutor executor = new McpActionExecutor(clientRegistry); + + MetaAction metaAction = new MetaAction("demo-tool", false, null, MetaAction.Type.MCP, "broken"); + metaAction.getParams().putAll(Map.of("value", "demo")); + + var response = executor.run(metaAction); + + Assertions.assertFalse(response.isOk()); + Assertions.assertTrue(response.getData().startsWith("MCP tool call failed:")); + } + + private io.modelcontextprotocol.client.McpSyncClient buildThrowingMcpClient() { + try { + Field unsafeField = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); + unsafeField.setAccessible(true); + sun.misc.Unsafe unsafe = (sun.misc.Unsafe) unsafeField.get(null); + return (io.modelcontextprotocol.client.McpSyncClient) unsafe.allocateInstance(io.modelcontextprotocol.client.McpSyncClient.class); + } catch (Exception e) { + throw new IllegalStateException("failed to build throwing mcp client", e); + } + } +}