You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shardingsphere.apache.org by zh...@apache.org on 2026/07/19 12:52:48 UTC
(shardingsphere) branch master updated: Fix MCP E2E metadata search response pagination (#39185)
This is an automated email from the ASF dual-hosted git repository.
terrymanu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git
The following commit(s) were added to refs/heads/master by this push:
new 8b15b93e49c Fix MCP E2E metadata search response pagination (#39185)
8b15b93e49c is described below
commit 8b15b93e49cbf675c2274ef01bef3b0b62259f08
Author: Liang Zhang <zh...@apache.org>
AuthorDate: Sun Jul 19 20:52:42 2026 +0800
Fix MCP E2E metadata search response pagination (#39185)
Preserve complete metadata search pages in model-facing responses while
retaining compact non-search responses and canonical pagination actions.
---
.../LLMMCPModelFacingToolResponseFormatter.java | 6 ++-
...LLMMCPModelFacingToolResponseFormatterTest.java | 55 ++++++++++++++++++++++
2 files changed, 60 insertions(+), 1 deletion(-)
diff --git a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/conversation/LLMMCPModelFacingToolResponseFormatter.java b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/conversation/LLMMCPModelFacingToolResponseFormatter.java
index a63c0019013..b1cc13d66f3 100644
--- a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/conversation/LLMMCPModelFacingToolResponseFormatter.java
+++ b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/conversation/LLMMCPModelFacingToolResponseFormatter.java
@@ -22,6 +22,7 @@ import lombok.NoArgsConstructor;
import org.apache.shardingsphere.infra.util.json.JsonUtils;
import org.apache.shardingsphere.mcp.support.protocol.MCPModelFacingPayloadContract;
import org.apache.shardingsphere.mcp.support.protocol.MCPPayloadFieldNames;
+import org.apache.shardingsphere.mcp.support.protocol.MCPResponseMode;
import java.util.Collection;
import java.util.LinkedHashMap;
@@ -33,6 +34,8 @@ import java.util.Objects;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
final class LLMMCPModelFacingToolResponseFormatter {
+ private static final int COMPACT_ITEM_LIMIT = 5;
+
private static final List<String> GENERAL_FIELD_NAMES = List.of(
"response_mode", "error_code", "error_id", "summary", "message", "recovery_category", "result_kind", "status", "statement_type", "normalized_sql", "rows", "row_objects",
"returned_row_count", "plan_id", "workflow_resource");
@@ -112,7 +115,8 @@ final class LLMMCPModelFacingToolResponseFormatter {
return;
}
List<Map<String, Object>> compactItems = new LinkedList<>();
- for (Map<String, Object> each : items.subList(0, Math.min(items.size(), 5))) {
+ int visibleItemCount = MCPResponseMode.SEARCH.equals(source.get("response_mode")) ? items.size() : Math.min(items.size(), COMPACT_ITEM_LIMIT);
+ for (Map<String, Object> each : items.subList(0, visibleItemCount)) {
Map<String, Object> compactItem = new LinkedHashMap<>(8, 1F);
copyIfPresent(each, compactItem, "database");
copyIfPresent(each, compactItem, "schema");
diff --git a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/conversation/LLMMCPModelFacingToolResponseFormatterTest.java b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/conversation/LLMMCPModelFacingToolResponseFormatterTest.java
index 5b340754819..8370aaf0186 100644
--- a/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/conversation/LLMMCPModelFacingToolResponseFormatterTest.java
+++ b/test/e2e/mcp/src/test/java/org/apache/shardingsphere/test/e2e/mcp/llm/conversation/LLMMCPModelFacingToolResponseFormatterTest.java
@@ -19,10 +19,12 @@ package org.apache.shardingsphere.test.e2e.mcp.llm.conversation;
import com.fasterxml.jackson.core.type.TypeReference;
import org.apache.shardingsphere.infra.util.json.JsonUtils;
+import org.apache.shardingsphere.mcp.support.protocol.MCPResponseMode;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.Map;
+import java.util.stream.IntStream;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
@@ -63,6 +65,51 @@ class LLMMCPModelFacingToolResponseFormatterTest {
Map.of("name", "order_id")))));
}
+ @Test
+ void assertFormatWithCompactListItems() {
+ Map<String, Object> actual = format(Map.of("response_mode", MCPResponseMode.LIST, "items", createVerboseItems(6)));
+ assertThat(actual, is(Map.of("response_mode", MCPResponseMode.LIST, "items", createCompactItems(5))));
+ }
+
+ @Test
+ void assertFormatWithCompleteSearchItems() {
+ Map<String, Object> actual = format(Map.of(
+ "response_mode", MCPResponseMode.SEARCH,
+ "items", createVerboseItems(100),
+ "count", 100,
+ "truncated", false));
+ assertThat(actual, is(Map.of(
+ "response_mode", MCPResponseMode.SEARCH,
+ "items", createCompactItems(100),
+ "count", 100,
+ "truncated", false)));
+ }
+
+ @Test
+ void assertFormatWithPaginatedSearchItems() {
+ Map<String, Object> nextAction = Map.of(
+ "order", 1,
+ "type", "tool_call",
+ "title", "Call database_gateway_search_metadata",
+ "tool_name", "database_gateway_search_metadata",
+ "arguments", Map.of("database", "logic_db", "object_types", List.of("table"), "limit", 100, "offset", 100),
+ "reason", "Read the next deterministically ordered metadata search page.");
+ Map<String, Object> actual = format(Map.of(
+ "response_mode", MCPResponseMode.SEARCH,
+ "items", createVerboseItems(100),
+ "count", 100,
+ "total_match_count", 101,
+ "truncated", true,
+ "next_actions", List.of(nextAction)));
+ assertThat(actual, is(Map.of(
+ "response_mode", MCPResponseMode.SEARCH,
+ "items", createCompactItems(100),
+ "count", 100,
+ "total_match_count", 101,
+ "truncated", true,
+ "next_actions", List.of(nextAction))));
+ }
+
@Test
void assertFormatWithPrompts() {
Map<String, Object> actual = format(Map.of("prompts", List.of(Map.of("name", "inspect_metadata"), Map.of("description", "ignored"))));
@@ -161,4 +208,12 @@ class LLMMCPModelFacingToolResponseFormatterTest {
return JsonUtils.fromJsonString(LLMMCPModelFacingToolResponseFormatter.format(value), new TypeReference<>() {
});
}
+
+ private List<Map<String, Object>> createVerboseItems(final int count) {
+ return IntStream.range(0, count).mapToObj(each -> Map.<String, Object>of("name", "item_" + each, "ignored", "value")).toList();
+ }
+
+ private List<Map<String, Object>> createCompactItems(final int count) {
+ return IntStream.range(0, count).mapToObj(each -> Map.<String, Object>of("name", "item_" + each)).toList();
+ }
}