From b9fd9bcaac8bee0845c6f32cdbe1e825e48b6e50 Mon Sep 17 00:00:00 2001 From: slhafzjw Date: Wed, 1 Apr 2026 22:57:17 +0800 Subject: [PATCH] refactor(mcp): switch desc.json loading to fastjson2 to avoid desc.json loading error --- .../runner/mcp/DynamicActionMcpManager.java | 4 +- .../action/runner/mcp/McpMetaRegistry.java | 4 +- .../action/runner/LocalRunnerClientTest.java | 52 ++++++++++++++----- 3 files changed, 44 insertions(+), 16 deletions(-) diff --git a/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/mcp/DynamicActionMcpManager.java b/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/mcp/DynamicActionMcpManager.java index a5658d8f..957ccc4e 100644 --- a/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/mcp/DynamicActionMcpManager.java +++ b/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/mcp/DynamicActionMcpManager.java @@ -1,6 +1,6 @@ package work.slhaf.partner.core.action.runner.mcp; -import cn.hutool.json.JSONUtil; +import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import io.modelcontextprotocol.common.McpTransportContext; import io.modelcontextprotocol.json.McpJsonMapper; @@ -241,7 +241,7 @@ public class DynamicActionMcpManager implements AutoCloseable { } MetaActionInfo info; try { - info = JSONUtil.readJSONObject(dir.resolve("desc.json").toFile(), StandardCharsets.UTF_8).toBean(MetaActionInfo.class); + info = JSON.parseObject(Files.readString(dir.resolve("desc.json"), StandardCharsets.UTF_8), MetaActionInfo.class); } catch (Exception e) { log.error("desc.json 加载失败: {}", dir); return false; diff --git a/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/mcp/McpMetaRegistry.java b/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/mcp/McpMetaRegistry.java index d7be9d32..d82d9f3d 100644 --- a/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/mcp/McpMetaRegistry.java +++ b/Partner-Core/src/main/java/work/slhaf/partner/core/action/runner/mcp/McpMetaRegistry.java @@ -1,6 +1,6 @@ package work.slhaf.partner.core.action.runner.mcp; -import cn.hutool.json.JSONUtil; +import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import io.modelcontextprotocol.common.McpTransportContext; import io.modelcontextprotocol.json.McpJsonMapper; @@ -70,7 +70,7 @@ public class McpMetaRegistry implements AutoCloseable { return false; } try { - MetaActionInfo info = JSONUtil.readJSONObject(file, StandardCharsets.UTF_8).toBean(MetaActionInfo.class); + MetaActionInfo info = JSON.parseObject(Files.readString(file.toPath(), StandardCharsets.UTF_8), MetaActionInfo.class); String uri = file.toPath().toUri().toString(); descCache.put(uri, JSONObject.toJSONString(info)); String actionKey = name.replace(".desc.json", ""); diff --git a/Partner-Core/src/test/java/work/slhaf/partner/core/action/runner/LocalRunnerClientTest.java b/Partner-Core/src/test/java/work/slhaf/partner/core/action/runner/LocalRunnerClientTest.java index 9850df46..4d3c7da1 100644 --- a/Partner-Core/src/test/java/work/slhaf/partner/core/action/runner/LocalRunnerClientTest.java +++ b/Partner-Core/src/test/java/work/slhaf/partner/core/action/runner/LocalRunnerClientTest.java @@ -183,11 +183,34 @@ public class LocalRunnerClientTest { + " }"; } + static String buildStdioServerEntry(String id, String packageName, Path npmCacheDir) { + String cachePath = npmCacheDir.toAbsolutePath().toString().replace("\\", "\\\\"); + return " \"" + id + "\": {\n" + + " \"command\": \"npx\",\n" + + " \"args\": [\n" + + " \"-y\",\n" + + " \"" + packageName + "\"\n" + + " ],\n" + + " \"env\": {\n" + + " \"NPM_CONFIG_CACHE\": \"" + cachePath + "\",\n" + + " \"npm_config_cache\": \"" + cachePath + "\"\n" + + " }\n" + + " }"; + } + static MetaAction buildMetaAction(MetaAction.Type type, String location, String name, Map params) { + return buildMetaAction(type, location, name, null, params); + } + + static MetaAction buildMetaAction(MetaAction.Type type, + String location, + String name, + String launcher, + Map params) { MetaAction metaAction = new MetaAction( name, false, - null, + launcher, type, location ); @@ -698,12 +721,13 @@ public class LocalRunnerClientTest { void testCommonMcpInitialLoad(@TempDir Path tempDir) throws IOException, InterruptedException { ConcurrentHashMap existedMetaActions = new ConcurrentHashMap<>(); ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor(); + Path npmCacheDir = tempDir.resolve("npm-cache"); Path mcpDir = tempDir.resolve("action").resolve("mcp"); Files.createDirectories(mcpDir); Path configFile = mcpDir.resolve("servers.json"); String config = buildCommonMcpConfig( - buildStdioServerEntry("mcp-deepwiki", "mcp-deepwiki@latest") + buildStdioServerEntry("mcp-deepwiki", "mcp-deepwiki@latest", npmCacheDir) ); writeCommonMcpConfig(configFile, config); @@ -722,6 +746,7 @@ public class LocalRunnerClientTest { ConcurrentHashMap existedMetaActions = new ConcurrentHashMap<>(); ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor(); new LocalRunnerClient(existedMetaActions, executor, tempDir.toString()); + Path npmCacheDir = tempDir.resolve("npm-cache"); try { Path mcpDir = tempDir.resolve("action").resolve("mcp"); @@ -729,15 +754,15 @@ public class LocalRunnerClientTest { Path configFile = mcpDir.resolve("servers.json"); String config = buildCommonMcpConfig( - buildStdioServerEntry("mcp-deepwiki", "mcp-deepwiki@latest") + buildStdioServerEntry("mcp-deepwiki", "mcp-deepwiki@latest", npmCacheDir) ); writeCommonMcpConfig(configFile, config); waitForCondition(() -> hasActionKey(existedMetaActions, key -> key.startsWith("mcp-deepwiki::")), 20000); Assertions.assertTrue(hasActionKey(existedMetaActions, key -> key.startsWith("mcp-deepwiki::"))); String updatedConfig = buildCommonMcpConfig( - buildStdioServerEntry("mcp-deepwiki", "mcp-deepwiki@latest"), - buildStdioServerEntry("playwright", "@playwright/mcp@latest") + buildStdioServerEntry("mcp-deepwiki", "mcp-deepwiki@latest", npmCacheDir), + buildStdioServerEntry("playwright", "@playwright/mcp@latest", npmCacheDir) ); writeCommonMcpConfig(configFile, updatedConfig); waitForCondition(() -> hasActionKey(existedMetaActions, key -> key.startsWith("playwright::")), 20000); @@ -757,6 +782,7 @@ public class LocalRunnerClientTest { ConcurrentHashMap existedMetaActions = new ConcurrentHashMap<>(); ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor(); new LocalRunnerClient(existedMetaActions, executor, tempDir.toString()); + Path npmCacheDir = tempDir.resolve("npm-cache"); try { Path mcpDir = tempDir.resolve("action").resolve("mcp"); @@ -764,8 +790,8 @@ public class LocalRunnerClientTest { Path configFile = mcpDir.resolve("servers.json"); String config = buildCommonMcpConfig( - buildStdioServerEntry("mcp-deepwiki", "mcp-deepwiki@latest"), - buildStdioServerEntry("playwright", "@playwright/mcp@latest") + buildStdioServerEntry("mcp-deepwiki", "mcp-deepwiki@latest", npmCacheDir), + buildStdioServerEntry("playwright", "@playwright/mcp@latest", npmCacheDir) ); writeCommonMcpConfig(configFile, config); waitForCondition(() -> hasActionKey(existedMetaActions, key -> key.startsWith("mcp-deepwiki::")), 20000); @@ -774,7 +800,7 @@ public class LocalRunnerClientTest { Assertions.assertTrue(hasActionKey(existedMetaActions, key -> key.startsWith("playwright::"))); String updatedConfig = buildCommonMcpConfig( - buildStdioServerEntry("mcp-deepwiki", "mcp-deepwiki@latest") + buildStdioServerEntry("mcp-deepwiki", "mcp-deepwiki@latest", npmCacheDir) ); writeCommonMcpConfig(configFile, updatedConfig); @@ -791,6 +817,7 @@ public class LocalRunnerClientTest { ConcurrentHashMap existedMetaActions = new ConcurrentHashMap<>(); ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor(); new LocalRunnerClient(existedMetaActions, executor, tempDir.toString()); + Path npmCacheDir = tempDir.resolve("npm-cache"); try { Path mcpDir = tempDir.resolve("action").resolve("mcp"); @@ -802,7 +829,7 @@ public class LocalRunnerClientTest { Assertions.assertFalse(hasActionKey(existedMetaActions, key -> key.startsWith("mcp-deepwiki::"))); String config = buildCommonMcpConfig( - buildStdioServerEntry("mcp-deepwiki", "mcp-deepwiki@latest") + buildStdioServerEntry("mcp-deepwiki", "mcp-deepwiki@latest", npmCacheDir) ); writeCommonMcpConfig(configFile, config); waitForCondition(() -> hasActionKey(existedMetaActions, key -> key.startsWith("mcp-deepwiki::")), 20000); @@ -830,7 +857,7 @@ public class LocalRunnerClientTest { RunnerClient.RunnerResponse response = client.doRun(metaAction); Assertions.assertNotNull(response); Assertions.assertFalse(response.isOk()); - Assertions.assertEquals("未知文件类型", response.getData()); + Assertions.assertTrue(response.getData().contains("parameter command")); } finally { executor.shutdownNow(); } @@ -845,7 +872,7 @@ public class LocalRunnerClientTest { try { Path script = tempDir.resolve("run.sh"); Files.writeString(script, "echo ok\n"); - MetaAction metaAction = buildMetaAction(MetaAction.Type.ORIGIN, script.toString(), "run", Map.of()); + MetaAction metaAction = buildMetaAction(MetaAction.Type.ORIGIN, script.toString(), "run", "sh", Map.of()); RunnerClient.RunnerResponse response = client.doRun(metaAction); Assertions.assertNotNull(response); Assertions.assertTrue(response.isOk()); @@ -927,12 +954,13 @@ public class LocalRunnerClientTest { void testDoRunWithMcpLoadedFromCommonConfig(@TempDir Path tempDir) throws IOException, InterruptedException { ConcurrentHashMap existedMetaActions = new ConcurrentHashMap<>(); ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor(); + Path npmCacheDir = tempDir.resolve("npm-cache"); Path mcpDir = tempDir.resolve("action").resolve("mcp"); Files.createDirectories(mcpDir); Path configFile = mcpDir.resolve("servers.json"); String config = buildCommonMcpConfig( - buildStdioServerEntry("playwright", "@playwright/mcp@latest") + buildStdioServerEntry("playwright", "@playwright/mcp@latest", npmCacheDir) ); writeCommonMcpConfig(configFile, config);