feat(RunnerClient): support MCP type-based dynamic client/server registration

This allows implementations of RunnerClient to dynamically register different types of MCP service, and also provides a shutdown hook to close client/server properly.
This commit is contained in:
2025-12-18 22:25:32 +08:00
parent cb28a5b068
commit e851e33b2e
2 changed files with 203 additions and 0 deletions

View File

@@ -1,5 +1,6 @@
package work.slhaf.partner.core.action.runner;
import com.alibaba.fastjson2.JSONObject;
import io.modelcontextprotocol.client.McpClient;
import io.modelcontextprotocol.client.McpSyncClient;
import io.modelcontextprotocol.server.McpServer;
@@ -7,11 +8,45 @@ import io.modelcontextprotocol.server.McpStatelessServerFeatures;
import io.modelcontextprotocol.server.McpStatelessSyncServer;
import io.modelcontextprotocol.spec.McpSchema;
import org.junit.jupiter.api.Test;
import work.slhaf.partner.core.action.entity.McpData;
import work.slhaf.partner.core.action.entity.MetaAction;
import work.slhaf.partner.core.action.entity.MetaActionInfo;
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
public class RunnerClientTest {
@Test
void httpMcpClientTest() {
TestRunnerClient testClient = new TestRunnerClient();
RunnerClient.HttpMcpServerParams params = new RunnerClient.HttpMcpServerParams(20, "https://dashscope.aliyuncs.com", "/api/v1/mcps/WebSearch/sse", Map.of("Authorization", "Bearer sk-xxx"));
testClient.registerMcpClient("test", params);
McpSyncClient client = testClient.mcpClients.values().stream().toList().getFirst();
List<McpSchema.Tool> tools = client.listTools().tools();
System.out.println(tools);
McpSchema.CallToolResult query = client.callTool(McpSchema.CallToolRequest.builder().name(tools.getFirst().name()).arguments(Map.of("query", "123")).build());
for (McpSchema.Content content : query.content()) {
System.out.println("\r\n---\r\n");
System.out.println(content);
}
}
@Test
void stdioMcpClientTest() {
TestRunnerClient testClient = new TestRunnerClient();
RunnerClient.StdioMcpServerParams params = new RunnerClient.StdioMcpServerParams(20, "uvx", Map.of("http_proxy", "http://127.0.0.1:7897", "https_proxy", "http://127.0.0.1:7897"), List.of("mcp-server-fetch"));
testClient.registerMcpClient("test", params);
McpSyncClient client = testClient.mcpClients.values().stream().toList().getFirst();
List<McpSchema.Tool> tools = client.listTools().tools();
System.out.println(tools);
McpSchema.CallToolResult query = client.callTool(McpSchema.CallToolRequest.builder().name(tools.getFirst().name()).arguments(Map.of("url", "https://gitea.slhaf.work")).build());
System.out.println(query.toString());
}
@Test
void inProcessMcpTransportTest() {
RunnerClient.InProcessMcpTransport.Pair pair = RunnerClient.InProcessMcpTransport.pair();
@@ -39,4 +74,35 @@ public class RunnerClientTest {
server.close();
}
private static class TestRunnerClient extends RunnerClient {
public TestRunnerClient() {
super(Map.of(), Executors.newVirtualThreadPerTaskExecutor());
}
@Override
protected RunnerResponse doRun(MetaAction metaAction) {
return null;
}
@Override
public Path buildTmpPath(MetaAction tempAction, String codeType) {
return null;
}
@Override
public void tmpSerialize(MetaAction tempAction, String code, String codeType) throws IOException {
}
@Override
public void persistSerialize(MetaActionInfo metaActionInfo, McpData mcpData) {
}
@Override
public JSONObject listSysDependencies() {
return null;
}
}
}