refactor(RunnerClient): redesign existedMetaActions update strategy

Context:
Resource-change events cannot reliably represent tool changes.
The previous approach attempted to externalize descriptive content into files, but the meta attribute of McpSchema.Tool can provide this information.
This commit is contained in:
2025-12-19 23:22:36 +08:00
parent ed042cfffa
commit 1f5509c17d
2 changed files with 41 additions and 13 deletions

View File

@@ -18,6 +18,8 @@ import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpStatelessServerTransport; import io.modelcontextprotocol.spec.McpStatelessServerTransport;
import lombok.Data; import lombok.Data;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.UnknownNullability;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import reactor.core.publisher.Sinks; import reactor.core.publisher.Sinks;
import work.slhaf.partner.core.action.entity.McpData; import work.slhaf.partner.core.action.entity.McpData;
@@ -88,25 +90,35 @@ public abstract class RunnerClient {
// ResourcesChange 事件传递的 Resource 可以由 Client 读取内容 // ResourcesChange 事件传递的 Resource 可以由 Client 读取内容
// 预计在 Server 侧,收到客户端发送的新的行动程序信息,该信息由客户端处补充后,将其放置在指定位置 // 预计在 Server 侧,收到客户端发送的新的行动程序信息,该信息由客户端处补充后,将其放置在指定位置
// 并写入描述文件、发起 ResourcesChange 事件 // 并写入描述文件、发起 ResourcesChange 事件
.resourcesChangeConsumer(resources -> updateExistedMetaActions(id, resources)) .toolsChangeConsumer(tools -> updateExistedMetaActions(id, tools))
.build(); .build();
mcpClients.put(id, client); mcpClients.put(id, client);
} }
private void updateExistedMetaActions(String id, List<McpSchema.Resource> resources) { private void updateExistedMetaActions(String id, @UnknownNullability List<McpSchema.Tool> tools) {
for (McpSchema.Tool tool : tools) {
MetaActionInfo info = buildMetaActionInfo(tool);
String actionKey = id + "::" + tool.name();
synchronized (existedMetaActions) { synchronized (existedMetaActions) {
McpSyncClient client = mcpClients.get(id); existedMetaActions.put(actionKey, info);
for (McpSchema.Resource resource : resources) {
McpSchema.ReadResourceResult resourceResult = client.readResource(resource);
for (McpSchema.ResourceContents resourceContent : resourceResult.contents()) {
// 忽略非文本类型,行动描述信息只会以文本形式存在
if (resourceContent instanceof McpSchema.TextResourceContents content) {
MetaActionInfo metaActionInfo = JSONObject.parseObject(content.text(), MetaActionInfo.class);
existedMetaActions.put(id + "::" + resource.name(), metaActionInfo);
}
} }
} }
} }
private static @NotNull MetaActionInfo buildMetaActionInfo(McpSchema.Tool tool) {
MetaActionInfo info = new MetaActionInfo();
info.setDescription(tool.description());
Map<String, Object> outputSchema = tool.outputSchema();
info.setResponseSchema(outputSchema == null ? JSONObject.of() : JSONObject.from(outputSchema));
info.setParams(tool.inputSchema().properties());
JSONObject meta = JSONObject.from(tool.meta());
info.setIo(meta.getBoolean("io"));
info.setPreActions(meta.getList("pre", String.class));
info.setPostActions(meta.getList("post", String.class));
info.setStrictDependencies(meta.getBoolean("strict"));
info.setTags(meta.getList("tag", String.class));
return info;
} }
private McpClientTransport createTransport(McpServerParams mcpServerParams) { private McpClientTransport createTransport(McpServerParams mcpServerParams) {

View File

@@ -46,6 +46,22 @@ public class RunnerClientTest {
System.out.println(query.toString()); System.out.println(query.toString());
} }
@Test
void schemaTest() {
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("\r\n ------ \r\n");
McpSchema.Tool first = tools.getFirst();
Map<String, Object> paramsSchema = first.inputSchema().properties();
System.out.println(paramsSchema.toString());
System.out.println("\r\n ------ \r\n");
Map<String, Object> outputSchema = first.outputSchema();
System.out.println(outputSchema);
}
@Test @Test
void inProcessMcpTransportTest() { void inProcessMcpTransportTest() {
RunnerClient.InProcessMcpTransport.Pair pair = RunnerClient.InProcessMcpTransport.pair(); RunnerClient.InProcessMcpTransport.Pair pair = RunnerClient.InProcessMcpTransport.pair();