From 0443b4e0349190988fb5ca5415158d07e206ccfb Mon Sep 17 00:00:00 2001
From: loveTsong <271667068@qq.com>
Date: Mon, 2 Mar 2026 15:24:47 +0800
Subject: [PATCH 1/7] [app-builder] refactor: replace MCP client with
LangChain4j MCP module
---
app-builder/plugins/aipp-plugin/pom.xml | 4 +-
.../jober/aipp/fel/FelComponentConfig.java | 6 +-
.../fit/jober/aipp/fel/WaterFlowAgent.java | 29 +++---
.../fit/jober/aipp/fitable/LlmComponent.java | 44 +++++----
.../jober/aipp/util/LangChain4jMcpClient.java | 92 +++++++++++++++++++
.../jober/aipp/fel/WaterFlowAgentTest.java | 45 +++++----
.../jober/aipp/fitable/LlmComponentTest.java | 73 ++++++++-------
common/dependency/pom.xml | 7 +-
8 files changed, 203 insertions(+), 97 deletions(-)
create mode 100644 app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/util/LangChain4jMcpClient.java
diff --git a/app-builder/plugins/aipp-plugin/pom.xml b/app-builder/plugins/aipp-plugin/pom.xml
index 1eeafc765c..a87acc058b 100644
--- a/app-builder/plugins/aipp-plugin/pom.xml
+++ b/app-builder/plugins/aipp-plugin/pom.xml
@@ -134,8 +134,8 @@
waterflow-graph-service
- org.fitframework.fel
- tool-mcp-client-service
+ dev.langchain4j
+ langchain4j-mcp
diff --git a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/fel/FelComponentConfig.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/fel/FelComponentConfig.java
index f0830c87c1..8baf99fe2e 100644
--- a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/fel/FelComponentConfig.java
+++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/fel/FelComponentConfig.java
@@ -9,7 +9,6 @@
import modelengine.fel.core.chat.ChatModel;
import modelengine.fel.core.chat.Prompt;
import modelengine.fel.engine.operators.patterns.AbstractAgent;
-import modelengine.fel.tool.mcp.client.McpClientFactory;
import modelengine.fel.tool.service.ToolExecuteService;
import modelengine.fit.jober.aipp.constants.AippConst;
import modelengine.fitframework.annotation.Bean;
@@ -29,12 +28,11 @@ public class FelComponentConfig {
*
* @param toolExecuteService 表示工具调用服务的 {@link ToolExecuteService}。
* @param chatModel 表示模型流式服务的 {@link ChatModel}。
- * @param mcpClientFactory 表示大模型上下文客户端工厂的 {@link McpClientFactory}。
* @return 返回 WaterFlow 场景的 Agent 服务的 {@link AbstractAgent}{@code <}{@link Prompt}{@code ,
* }{@link Prompt}{@code >}。
*/
@Bean(AippConst.WATER_FLOW_AGENT_BEAN)
- public AbstractAgent getWaterFlowAgent(@Fit ToolExecuteService toolExecuteService, ChatModel chatModel, McpClientFactory mcpClientFactory) {
- return new WaterFlowAgent(toolExecuteService, chatModel, mcpClientFactory);
+ public AbstractAgent getWaterFlowAgent(@Fit ToolExecuteService toolExecuteService, ChatModel chatModel) {
+ return new WaterFlowAgent(toolExecuteService, chatModel);
}
}
\ No newline at end of file
diff --git a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/fel/WaterFlowAgent.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/fel/WaterFlowAgent.java
index b8fdb37fa1..bbbb30e72f 100644
--- a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/fel/WaterFlowAgent.java
+++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/fel/WaterFlowAgent.java
@@ -6,9 +6,6 @@
package modelengine.fit.jober.aipp.fel;
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONObject;
-
import modelengine.fel.core.chat.ChatMessage;
import modelengine.fel.core.chat.ChatModel;
import modelengine.fel.core.chat.Prompt;
@@ -22,20 +19,19 @@
import modelengine.fel.engine.operators.models.ChatChunk;
import modelengine.fel.engine.operators.models.ChatFlowModel;
import modelengine.fel.engine.operators.patterns.AbstractAgent;
-import modelengine.fel.tool.mcp.client.McpClient;
-import modelengine.fel.tool.mcp.client.McpClientFactory;
import modelengine.fel.tool.service.ToolExecuteService;
import modelengine.fit.jober.aipp.common.exception.AippErrCode;
import modelengine.fit.jober.aipp.common.exception.AippException;
import modelengine.fit.jober.aipp.constants.AippConst;
+import modelengine.fit.jober.aipp.util.LangChain4jMcpClient;
import modelengine.fit.jober.aipp.util.McpUtils;
import modelengine.fit.waterflow.domain.context.StateContext;
import modelengine.fitframework.annotation.Fit;
import modelengine.fitframework.inspection.Validation;
+import modelengine.fitframework.log.Logger;
import modelengine.fitframework.util.CollectionUtils;
import modelengine.fitframework.util.ObjectUtils;
-import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -54,23 +50,24 @@ public class WaterFlowAgent extends AbstractAgent {
private final String agentMsgKey;
private final ToolExecuteService toolExecuteService;
- private final McpClientFactory mcpClientFactory;
+ private java.util.function.Function mcpClientFactory = LangChain4jMcpClient::new;
/**
* {@link WaterFlowAgent} 的构造方法。
*
* @param toolExecuteService 表示工具调用服务的 {@link ToolExecuteService}。
* @param chatStreamModel 表示流式对话大模型的 {@link ChatModel}。
- * @param mcpClientFactory 表示大模型上下文客户端工厂的 {@link McpClientFactory}。
*/
- public WaterFlowAgent(@Fit ToolExecuteService toolExecuteService, ChatModel chatStreamModel,
- McpClientFactory mcpClientFactory) {
+ public WaterFlowAgent(@Fit ToolExecuteService toolExecuteService, ChatModel chatStreamModel) {
super(new ChatFlowModel(chatStreamModel, null));
this.toolExecuteService = Validation.notNull(toolExecuteService, "The tool execute service cannot be null.");
- this.mcpClientFactory = Validation.notNull(mcpClientFactory, "The mcp client factory cannot be null.");
this.agentMsgKey = AGENT_MSG_KEY;
}
+ void setMcpClientFactory(java.util.function.Function mcpClientFactory) {
+ this.mcpClientFactory = mcpClientFactory;
+ }
+
@Override
protected Prompt doToolCall(List toolCalls, StateContext ctx) {
Validation.notNull(ctx, "The state context cannot be null.");
@@ -136,12 +133,10 @@ private ChatMessage callTool(ToolCall toolCall, Map toolsMap,
if (mcpServerConfig != null) {
String url = Validation.notBlank(ObjectUtils.cast(mcpServerConfig.get(AippConst.MCP_SERVER_URL_KEY)),
"The mcp url should not be empty.");
- try (McpClient mcpClient = this.mcpClientFactory.create(McpUtils.getBaseUrl(url),
- McpUtils.getSseEndpoint(url))) {
- mcpClient.initialize();
- Object result = mcpClient.callTool(toolRealName, JSONObject.parseObject(toolCall.arguments()));
- return new ToolMessage(toolCall.id(), JSON.toJSONString(result));
- } catch (IOException exception) {
+ try (LangChain4jMcpClient mcpClient = this.mcpClientFactory.apply(url)) {
+ String result = mcpClient.callTool(toolRealName, toolCall.arguments());
+ return new ToolMessage(toolCall.id(), result);
+ } catch (Exception exception) {
throw new AippException(AippErrCode.CALL_MCP_SERVER_FAILED, exception.getMessage());
}
}
diff --git a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/fitable/LlmComponent.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/fitable/LlmComponent.java
index 476f76791e..18ab2a7383 100644
--- a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/fitable/LlmComponent.java
+++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/fitable/LlmComponent.java
@@ -20,13 +20,10 @@
import modelengine.fel.engine.flows.AiProcessFlow;
import modelengine.fel.engine.operators.patterns.AbstractAgent;
import modelengine.fel.engine.operators.prompts.Prompts;
-import modelengine.fel.tool.mcp.client.McpClient;
-import modelengine.fel.tool.mcp.client.McpClientFactory;
-import modelengine.fel.tool.mcp.entity.Tool;
import modelengine.fel.tool.model.transfer.ToolData;
import modelengine.fit.jober.aipp.domains.appversion.service.AppVersionService;
import modelengine.fit.jober.aipp.enums.MetaInstStatusEnum;
-import modelengine.fit.jober.aipp.util.McpUtils;
+import modelengine.fit.jober.aipp.util.LangChain4jMcpClient;
import modelengine.fitframework.inspection.Validation;
import modelengine.jade.store.service.ToolService;
import modelengine.fit.jade.aipp.formatter.OutputFormatterChain;
@@ -70,6 +67,9 @@
import modelengine.fitframework.util.StringUtils;
import modelengine.fitframework.util.UuidUtils;
+import dev.langchain4j.model.chat.request.json.JsonObjectSchema;
+import dev.langchain4j.agent.tool.ToolSpecification;
+
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
@@ -113,7 +113,6 @@ public class LlmComponent implements FlowableService {
private final AippModelCenter aippModelCenter;
private final PromptBuilderChain promptBuilderChain;
private final AppTaskInstanceService appTaskInstanceService;
- private final McpClientFactory mcpClientFactory;
private final OutputFormatterChain formatterChain;
private final AppVersionService appVersionService;
@@ -129,7 +128,6 @@ public class LlmComponent implements FlowableService {
* @param aippModelCenter 表示模型中心的 {@link AippModelCenter}。
* @param promptBuilderChain 表示提示器构造器职责链的 {@link PromptBuilderChain}。
* @param appTaskInstanceService 表示任务实例服务的 {@link AppTaskInstanceService}。
- * @param mcpClientFactory 表示大模型上下文客户端工厂的 {@link McpClientFactory}。
*/
public LlmComponent(FlowInstanceService flowInstanceService,
@Fit ToolService toolService,
@@ -141,7 +139,7 @@ public LlmComponent(FlowInstanceService flowInstanceService,
PromptBuilderChain promptBuilderChain,
AppTaskInstanceService appTaskInstanceService,
OutputFormatterChain formatterChain,
- McpClientFactory mcpClientFactory, AppVersionService appVersionService) {
+ AppVersionService appVersionService) {
this.flowInstanceService = flowInstanceService;
this.toolService = toolService;
this.aippLogService = aippLogService;
@@ -157,7 +155,6 @@ public LlmComponent(FlowInstanceService flowInstanceService,
.close();
this.promptBuilderChain = promptBuilderChain;
this.appTaskInstanceService = appTaskInstanceService;
- this.mcpClientFactory = notNull(mcpClientFactory, "The mcp client factory cannot be null.");
this.formatterChain = formatterChain;
this.appVersionService = appVersionService;
}
@@ -482,12 +479,12 @@ private List buildMcpToolInfos(Map mcpServersConfig) {
String url = Validation.notBlank(ObjectUtils.cast(serverConfig.get(AippConst.MCP_SERVER_URL_KEY)),
"The mcp url should not be empty.");
- try (McpClient mcpClient = this.mcpClientFactory.create(McpUtils.getBaseUrl(url),
- McpUtils.getSseEndpoint(url))) {
- mcpClient.initialize();
- List tools = mcpClient.getTools();
- result.addAll(tools.stream().map(tool -> buildMcpToolInfo(serverName, tool, serverConfig)).toList());
- } catch (IOException exception) {
+ try (LangChain4jMcpClient mcpClient = new LangChain4jMcpClient(url)) {
+ List tools = mcpClient.getTools();
+ result.addAll(tools.stream()
+ .map(tool -> buildMcpToolInfo(serverName, tool, serverConfig))
+ .toList());
+ } catch (Exception exception) {
throw new AippException(AippErrCode.CALL_MCP_SERVER_FAILED, exception.getMessage());
}
});
@@ -515,14 +512,23 @@ private ToolInfo buildToolInfo(ToolData toolData) {
.build();
}
- private static ToolInfo buildMcpToolInfo(String serverName, Tool tool, Map serverConfig) {
+ private static ToolInfo buildMcpToolInfo(String serverName,
+ ToolSpecification tool, Map serverConfig) {
+ JsonObjectSchema toolParams = tool.parameters();
+ Map parametersMap = new HashMap<>();
+ if (toolParams != null) {
+ parametersMap.put("type", "object");
+ parametersMap.put("properties", toolParams.properties());
+ parametersMap.put("required", toolParams.required());
+ }
+
return ToolInfo.custom()
- .name(buildUniqueToolName(AippConst.MCP_SERVER_TYPE, serverName, tool.getName()))
- .description(tool.getDescription())
- .parameters(tool.getInputSchema())
+ .name(buildUniqueToolName(AippConst.MCP_SERVER_TYPE, serverName, tool.name()))
+ .description(tool.description())
+ .parameters(parametersMap)
.extensions(MapBuilder.get()
.put(AippConst.MCP_SERVER_KEY, serverConfig)
- .put(AippConst.TOOL_REAL_NAME, tool.getName())
+ .put(AippConst.TOOL_REAL_NAME, tool.name())
.build())
.build();
}
diff --git a/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/util/LangChain4jMcpClient.java b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/util/LangChain4jMcpClient.java
new file mode 100644
index 0000000000..1ddc13b271
--- /dev/null
+++ b/app-builder/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/util/LangChain4jMcpClient.java
@@ -0,0 +1,92 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
+ * This file is a part of the ModelEngine Project.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+
+package modelengine.fit.jober.aipp.util;
+
+import dev.langchain4j.agent.tool.ToolExecutionRequest;
+import dev.langchain4j.agent.tool.ToolSpecification;
+import dev.langchain4j.mcp.client.DefaultMcpClient;
+import dev.langchain4j.mcp.client.McpClient;
+import dev.langchain4j.mcp.client.transport.http.HttpMcpTransport;
+
+import modelengine.fit.jober.aipp.common.exception.AippErrCode;
+import modelengine.fit.jober.aipp.common.exception.AippException;
+import modelengine.fitframework.util.StringUtils;
+
+import java.util.List;
+
+/**
+ * LangChain4jMcpClient is a client for calling ModelEngine's MCP server.
+ *
+ * @author songyongtan
+ * @since 2026-03-01
+ */
+public class LangChain4jMcpClient implements AutoCloseable {
+ private final McpClient mcpClient;
+ private final String url;
+
+ /**
+ * 构造函数,用于初始化LangChain4jMcpClient对象。
+ *
+ * @param url MCP服务器的URL,格式为http://host:port
+ */
+ public LangChain4jMcpClient(String url) {
+ this.url = url;
+
+ HttpMcpTransport transport = new HttpMcpTransport.Builder()
+ .sseUrl(url)
+ .build();
+
+ this.mcpClient = new DefaultMcpClient.Builder()
+ .transport(transport)
+ .build();
+ }
+
+ /**
+ * 获取MCP服务器上注册的所有工具。
+ *
+ * @return 包含所有工具规范的列表
+ */
+ public List getTools() {
+ try {
+ return this.mcpClient.listTools();
+ } catch (Exception e) {
+ throw new AippException(AippErrCode.CALL_MCP_SERVER_FAILED,
+ StringUtils.format("Failed to get tools from MCP server. [url={0}]", this.url), e);
+ }
+ }
+
+ /**
+ * 调用MCP服务器上的指定工具。
+ *
+ * @param toolName 要调用的工具名称
+ * @param arguments 工具调用的参数,格式为JSON字符串
+ * @return 工具调用的结果,格式为JSON字符串
+ */
+ public String callTool(String toolName, String arguments) {
+ try {
+ ToolExecutionRequest request = ToolExecutionRequest.builder()
+ .name(toolName)
+ .arguments(arguments)
+ .build();
+ return this.mcpClient.executeTool(request);
+ } catch (Exception e) {
+ throw new AippException(AippErrCode.CALL_MCP_SERVER_FAILED,
+ StringUtils.format("Failed to call tool. [toolName={0}, url={1}]", toolName, this.url), e);
+ }
+ }
+
+ @Override
+ public void close() {
+ try {
+ this.mcpClient.close();
+ } catch (Exception e) {
+ throw new AippException(AippErrCode.CALL_MCP_SERVER_FAILED,
+ StringUtils.format("Failed to close MCP client. [url={0}]", this.url), e);
+ }
+ }
+}
diff --git a/app-builder/plugins/aipp-plugin/src/test/java/modelengine/fit/jober/aipp/fel/WaterFlowAgentTest.java b/app-builder/plugins/aipp-plugin/src/test/java/modelengine/fit/jober/aipp/fel/WaterFlowAgentTest.java
index 11a965d68e..6ee1a57677 100644
--- a/app-builder/plugins/aipp-plugin/src/test/java/modelengine/fit/jober/aipp/fel/WaterFlowAgentTest.java
+++ b/app-builder/plugins/aipp-plugin/src/test/java/modelengine/fit/jober/aipp/fel/WaterFlowAgentTest.java
@@ -16,10 +16,9 @@
import modelengine.fel.core.tool.ToolCall;
import modelengine.fel.core.tool.ToolInfo;
import modelengine.fel.engine.flows.AiProcessFlow;
-import modelengine.fel.tool.mcp.client.McpClient;
-import modelengine.fel.tool.mcp.client.McpClientFactory;
import modelengine.fel.tool.service.ToolExecuteService;
import modelengine.fit.jober.aipp.constants.AippConst;
+import modelengine.fit.jober.aipp.util.LangChain4jMcpClient;
import modelengine.fitframework.flowable.Choir;
import modelengine.fitframework.util.MapBuilder;
@@ -27,7 +26,13 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
+import org.mockito.MockedStatic;
+import org.mockito.MockedConstruction;
import org.mockito.junit.jupiter.MockitoExtension;
+import org.mockito.junit.jupiter.MockitoSettings;
+import org.mockito.quality.Strictness;
+import org.mockito.InjectMocks;
+import modelengine.fit.jober.aipp.util.McpUtils;
import java.util.Collections;
import java.util.HashMap;
@@ -37,16 +42,21 @@
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.mockConstruction;
/**
* {@link WaterFlowAgent} 的测试。
*/
@ExtendWith(MockitoExtension.class)
+@MockitoSettings(strictness = Strictness.LENIENT)
class WaterFlowAgentTest {
private static final String TEXT_STEP = "textStep";
private static final String TOOL_CALL_STEP = "toolCallStep";
@@ -55,13 +65,11 @@ class WaterFlowAgentTest {
private ToolExecuteService toolExecuteService;
@Mock
private ChatModel chatModel;
- @Mock
- private McpClientFactory mcpClientFactory;
@Test
void shouldGetResultWhenRunFlowGivenNoToolCall() {
WaterFlowAgent waterFlowAgent =
- new WaterFlowAgent(this.toolExecuteService, this.chatModel, this.mcpClientFactory);
+ new WaterFlowAgent(this.toolExecuteService, this.chatModel);
String expectResult = "0123";
doAnswer(invocation -> Choir.create(emitter -> {
@@ -81,7 +89,7 @@ void shouldGetResultWhenRunFlowGivenNoToolCall() {
@Test
void shouldGetResultWhenRunFlowGivenStoreToolCall() {
- WaterFlowAgent waterFlowAgent = new WaterFlowAgent(this.toolExecuteService, this.chatModel, this.mcpClientFactory);
+ WaterFlowAgent waterFlowAgent = new WaterFlowAgent(this.toolExecuteService, this.chatModel);
String expectResult = "tool result:0123";
String realName = "realName";
@@ -105,19 +113,17 @@ void shouldGetResultWhenRunFlowGivenStoreToolCall() {
.bind(AippConst.TOOLS_KEY, Collections.singletonList(toolInfo))
.offer(ChatMessages.from(new HumanMessage("hi"))).await();
- verify(this.mcpClientFactory, times(0)).create(any(), any());
assertEquals(expectResult, result.text());
}
@Test
void shouldGetResultWhenRunFlowGivenMcpToolCall() {
- WaterFlowAgent waterFlowAgent = new WaterFlowAgent(this.toolExecuteService, this.chatModel, this.mcpClientFactory);
+ WaterFlowAgent waterFlowAgent = new WaterFlowAgent(this.toolExecuteService, this.chatModel);
- String expectResult = "\"tool result:\"0123";
+ String expectResult = "tool result:0123";
String realName = "realName";
- String baseUrl = "http://localhost";
- String sseEndpoint = "/sse";
- ToolInfo toolInfo = buildMcpToolInfo(realName, baseUrl, sseEndpoint);
+ String url = "http://localhost/sse";
+ ToolInfo toolInfo = buildMcpToolInfo(realName, url);
ToolCall toolCall = ToolCall.custom().id("id").name(toolInfo.name()).arguments("{}").build();
List toolCalls = Collections.singletonList(toolCall);
AtomicReference step = new AtomicReference<>(TOOL_CALL_STEP);
@@ -128,10 +134,13 @@ void shouldGetResultWhenRunFlowGivenMcpToolCall() {
return result;
}).when(chatModel).generate(any(), any());
Map toolContext = MapBuilder.get().put("key", "value").build();
- McpClient mcpClient = mock(McpClient.class);
- when(this.mcpClientFactory.create(baseUrl, sseEndpoint)).thenReturn(mcpClient);
- when(mcpClient.callTool(realName, new HashMap<>())).thenReturn("tool result:");
-
+
+ LangChain4jMcpClient mockMcpClient = mock(LangChain4jMcpClient.class);
+ when(mockMcpClient.callTool(realName, "{}")).thenReturn("tool result:");
+ doNothing().when(mockMcpClient).close();
+
+ waterFlowAgent.setMcpClientFactory(clientUrl -> mockMcpClient);
+
AiProcessFlow flow = waterFlowAgent.buildFlow();
ChatMessage result = flow.converse()
.bind(ChatOption.custom().build())
@@ -169,7 +178,7 @@ private static ToolInfo buildToolInfo(String realName) {
.build();
}
- private static ToolInfo buildMcpToolInfo(String realName, String baseUrl, String sseEndpoint) {
+ private static ToolInfo buildMcpToolInfo(String realName, String url) {
return ToolInfo.custom()
.name("tool1")
.description("desc")
@@ -177,7 +186,7 @@ private static ToolInfo buildMcpToolInfo(String realName, String baseUrl, Strin
.extensions(MapBuilder.get()
.put(AippConst.TOOL_REAL_NAME, realName)
.put(AippConst.MCP_SERVER_KEY,
- MapBuilder.get().put(AippConst.MCP_SERVER_URL_KEY, baseUrl + sseEndpoint).build())
+ MapBuilder.get().put(AippConst.MCP_SERVER_URL_KEY, url).build())
.build())
.build();
}
diff --git a/app-builder/plugins/aipp-plugin/src/test/java/modelengine/fit/jober/aipp/fitable/LlmComponentTest.java b/app-builder/plugins/aipp-plugin/src/test/java/modelengine/fit/jober/aipp/fitable/LlmComponentTest.java
index f1b011cd1b..139dc63025 100644
--- a/app-builder/plugins/aipp-plugin/src/test/java/modelengine/fit/jober/aipp/fitable/LlmComponentTest.java
+++ b/app-builder/plugins/aipp-plugin/src/test/java/modelengine/fit/jober/aipp/fitable/LlmComponentTest.java
@@ -9,18 +9,18 @@
import static modelengine.fit.jober.aipp.TestUtils.mockFailAsyncJob;
import static modelengine.fit.jober.aipp.TestUtils.mockResumeFlow;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.mockConstruction;
+import dev.langchain4j.model.chat.request.json.JsonObjectSchema;
import modelengine.fel.core.chat.ChatOption;
import modelengine.fel.core.tool.ToolInfo;
import modelengine.fel.engine.operators.models.ChatFlowModel;
import modelengine.fel.tool.ToolSchema;
-import modelengine.fel.tool.mcp.client.McpClient;
-import modelengine.fel.tool.mcp.client.McpClientFactory;
-import modelengine.fel.tool.mcp.entity.Tool;
import modelengine.fel.tool.model.transfer.ToolData;
import modelengine.fel.tool.service.ToolExecuteService;
import modelengine.fit.jade.aipp.formatter.OutputFormatterChain;
@@ -40,6 +40,7 @@
import modelengine.fit.jober.aipp.service.AippLogService;
import modelengine.fit.jober.aipp.service.AippLogStreamService;
import modelengine.fit.jober.aipp.util.JsonUtils;
+import modelengine.fit.jober.aipp.util.LangChain4jMcpClient;
import modelengine.fit.waterflow.domain.context.StateContext;
import modelengine.fel.core.chat.ChatMessage;
@@ -61,11 +62,14 @@
import modelengine.fitframework.util.ObjectUtils;
import modelengine.jade.store.service.ToolService;
+import dev.langchain4j.agent.tool.ToolSpecification;
+
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
+import org.mockito.MockedConstruction;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
@@ -104,8 +108,6 @@ public class LlmComponentTest {
@Mock
private AippModelCenter aippModelCenter;
@Mock
- private McpClientFactory mcpClientFactory;
- @Mock
private OutputFormatterChain formatterChain;
static class PromptBuilderStub implements PromptBuilder {
@@ -168,7 +170,7 @@ protected AiProcessFlow buildFlow() {
}
private AbstractAgent getWaterFlowAgent(ChatModel model) {
- return new WaterFlowAgent(this.toolExecuteService, model, this.mcpClientFactory);
+ return new WaterFlowAgent(this.toolExecuteService, model);
}
private ChatModel buildChatStreamModel(String exceptionMsg) {
@@ -242,8 +244,7 @@ void shouldFailedWhenNoTool() throws InterruptedException {
this.aippModelCenter,
this.promptBuilderChain,
this.appTaskInstanceService,
- this.formatterChain,
- this.mcpClientFactory, null);
+ this.formatterChain, null);
// mock
CountDownLatch countDownLatch = mockFailAsyncJob(flowInstanceService);
@@ -372,30 +373,35 @@ void shouldGetMcpToolsWhenHandleTaskGivenMcpServersConfig() throws InterruptedEx
Map